Release v0.3 - Add Redis support #82

Merged
lamacchinadesiderante merged 9 commits from develop into main 2024-05-18 11:35:07 +00:00
15 changed files with 412 additions and 245 deletions
Showing only changes of commit 0650c995a7 - Show all commits

View File

@ -2,4 +2,6 @@ node_modules
.git .git
.gitignore .gitignore
.next .next
package-lock.json package-lock.json
.env

8
.env.example Normal file
View File

@ -0,0 +1,8 @@
# enable content cache (less server api calls)
ENABLE_REDIS=true
# if cache enabled, sets redis url for Docker network (see docker-compose.yaml)
# REDIS_URL='redis://redis:6379'
# if cache enabled, set redis url for external redis
REDIS_URL='redis://127.0.0.1:6379'

3
.gitignore vendored
View File

@ -34,3 +34,6 @@ yarn-error.log*
# typescript # typescript
*.tsbuildinfo *.tsbuildinfo
next-env.d.ts next-env.d.ts
# local .env
.env

View File

@ -1,6 +1,6 @@
# PHASE 1: copy and build # PHASE 1: copy and build
FROM node:alpine AS build FROM node:22.0.0-alpine3.19 AS build
WORKDIR /app WORKDIR /app
@ -10,7 +10,7 @@ RUN rm -rf node_modules && npm install && npm run build
# PHASE 2: prepare for exec # PHASE 2: prepare for exec
FROM node:alpine AS exec FROM node:22.0.0-alpine3.19 AS exec
WORKDIR /app WORKDIR /app

View File

@ -18,27 +18,49 @@ Self-hosted demo can be found [here](https://proxyraye.copyriot.xyz).
You can run the project on local by cloning the repo. You can run the project on local by cloning the repo.
Project requires no configuration. ## Docker
You can run it via Docker with docker-compose by opening root folder via console and running: You can run it via Docker with docker-compose by opening root folder via console and running:
``` ```
docker-compose up -d docker-compose up -d
``` ```
And head browser to `localhost:8069`. And head browser to `localhost:8069`.
Or you can run it outside Docker via npm (tested with NodeJS `20.11`) by opening root folder via console and running: ### Caching
Starting from version `0.3.0` caching is enabled by default inside `docker-compose.yaml`.
A base Redis image will be added to the network.
However, Proxy Raye can still work without Redis by setting `ENABLE_REDIS=false` under `environment:`.
## Node.js
You can also run project outside Docker via npm (tested with NodeJS `20.11` and above).
You can run the project by opening root folder via console and running:
``` ```
npm install npm install
npm run build npm run build
npm run start npm run start
``` ```
And head browser to `localhost:3000`. And head browser to `localhost:3000`.
### WARNING:
Proxy Raye tries to avoid ip blacklisting by setting random human-request-like headers at every call. But in the long run (after several hours of continuous requests) XVideos might **temporarily blacklist** your IP address. When this happen, it will stop returning HD videos from pages. Only low quality (SD) videos will be shown.
Using a VPN can avoid such issue. ### (optional) Enable caching
If you want to enable caching, please rename `.env.example` to `.env` file inside root folder. Inside `.env` file you will find following variables:
```
ENABLE_REDIS=true
REDIS_URL='redis://127.0.0.1:6379'
```
These values assume a basic Redis instance running on local machine. If your local setup is different, or your Redis instance is somewhere else, please change `REDIS_URL` accordingly.
# Modify # Modify
If you want to edit the project you can start development mode by opening root folder via console and running: If you want to edit the project you can start development mode by opening root folder via console and running:

View File

@ -19,3 +19,12 @@ services:
ports: ports:
- "8069:3000" - "8069:3000"
environment:
- ENABLE_REDIS=true
- REDIS_URL=redis://redis:6379
redis:
image: redis:alpine
container_name: redis
restart: unless-stopped

439
package-lock.json generated
View File

@ -1,54 +1,47 @@
{ {
"name": "proxyraye-next", "name": "proxyraye-next",
"version": "0.2.0", "version": "0.3.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "proxyraye-next", "name": "proxyraye-next",
"version": "0.2.0", "version": "0.3.0",
"dependencies": { "dependencies": {
"@picocss/pico": "^2.0.6", "@picocss/pico": "2.0.6",
"@reduxjs/toolkit": "^2.2.3", "@reduxjs/toolkit": "2.2.3",
"axios": "^1.6.8", "axios": "1.6.8",
"cheerio": "^1.0.0-rc.12", "cheerio": "1.0.0-rc.12",
"classnames": "^2.5.1", "classnames": "2.5.1",
"next": "14.2.2", "next": "14.2.2",
"next-intl": "^3.11.3", "next-intl": "3.11.3",
"next-nprogress-bar": "^2.3.11", "next-nprogress-bar": "2.3.11",
"react": "^18", "react": "18.3.0",
"react-cookie": "^7.1.4", "react-cookie": "7.1.4",
"react-dom": "^18", "react-dom": "18.3.0",
"react-icons": "^5.1.0", "react-icons": "5.1.0",
"react-image": "^4.1.0", "react-image": "4.1.0",
"react-redux": "^9.1.1", "react-redux": "9.1.1",
"redux-persist": "^6.0.0", "redis": "4.6.14",
"video.js": "^8.10.0", "redux-persist": "6.0.0",
"videojs-hls-quality-selector": "^2.0.0" "video.js": "8.10.0",
"videojs-hls-quality-selector": "2.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20", "@types/node": "20.12.12",
"@types/react": "^18", "@types/react": "18.3.0",
"@types/react-dom": "^18", "@types/react-dom": "18.3.0",
"eslint": "^8", "@types/redis": "4.0.11",
"eslint": "8",
"eslint-config-next": "14.2.2", "eslint-config-next": "14.2.2",
"sass": "^1.75.0", "sass": "1.75.0",
"typescript": "^5" "typescript": "5.4.5"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
"integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
} }
}, },
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
"version": "7.24.4", "version": "7.24.5",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz",
"integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", "integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==",
"dependencies": { "dependencies": {
"regenerator-runtime": "^0.14.0" "regenerator-runtime": "^0.14.0"
}, },
@ -130,64 +123,30 @@
} }
}, },
"node_modules/@formatjs/fast-memoize": { "node_modules/@formatjs/fast-memoize": {
"version": "1.2.1", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-1.2.1.tgz", "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz",
"integrity": "sha512-Rg0e76nomkz3vF9IPlKeV+Qynok0r7YZjL6syLz4/urSg0IbjPZCB/iYUMNsYA643gh4mgrX3T7KEIFIxJBQeg==", "integrity": "sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==",
"dependencies": { "dependencies": {
"tslib": "^2.1.0" "tslib": "^2.4.0"
} }
}, },
"node_modules/@formatjs/icu-messageformat-parser": { "node_modules/@formatjs/icu-messageformat-parser": {
"version": "2.1.0", "version": "2.7.6",
"resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.0.tgz", "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.6.tgz",
"integrity": "sha512-Qxv/lmCN6hKpBSss2uQ8IROVnta2r9jd3ymUEIjm2UyIkUCHVcbUVRGL/KS/wv7876edvsPe+hjHVJ4z8YuVaw==", "integrity": "sha512-etVau26po9+eewJKYoiBKP6743I1br0/Ie00Pb/S/PtmYfmjTcOn2YCh2yNkSZI12h6Rg+BOgQYborXk46BvkA==",
"dependencies": { "dependencies": {
"@formatjs/ecma402-abstract": "1.11.4", "@formatjs/ecma402-abstract": "1.18.2",
"@formatjs/icu-skeleton-parser": "1.3.6", "@formatjs/icu-skeleton-parser": "1.8.0",
"tslib": "^2.1.0" "tslib": "^2.4.0"
}
},
"node_modules/@formatjs/icu-messageformat-parser/node_modules/@formatjs/ecma402-abstract": {
"version": "1.11.4",
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz",
"integrity": "sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==",
"dependencies": {
"@formatjs/intl-localematcher": "0.2.25",
"tslib": "^2.1.0"
}
},
"node_modules/@formatjs/icu-messageformat-parser/node_modules/@formatjs/intl-localematcher": {
"version": "0.2.25",
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz",
"integrity": "sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==",
"dependencies": {
"tslib": "^2.1.0"
} }
}, },
"node_modules/@formatjs/icu-skeleton-parser": { "node_modules/@formatjs/icu-skeleton-parser": {
"version": "1.3.6", "version": "1.8.0",
"resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.6.tgz", "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.0.tgz",
"integrity": "sha512-I96mOxvml/YLrwU2Txnd4klA7V8fRhb6JG/4hm3VMNmeJo1F03IpV2L3wWt7EweqNLES59SZ4d6hVOPCSf80Bg==", "integrity": "sha512-QWLAYvM0n8hv7Nq5BEs4LKIjevpVpbGLAJgOaYzg9wABEoX1j0JO1q2/jVkO6CVlq0dbsxZCngS5aXbysYueqA==",
"dependencies": { "dependencies": {
"@formatjs/ecma402-abstract": "1.11.4", "@formatjs/ecma402-abstract": "1.18.2",
"tslib": "^2.1.0" "tslib": "^2.4.0"
}
},
"node_modules/@formatjs/icu-skeleton-parser/node_modules/@formatjs/ecma402-abstract": {
"version": "1.11.4",
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz",
"integrity": "sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==",
"dependencies": {
"@formatjs/intl-localematcher": "0.2.25",
"tslib": "^2.1.0"
}
},
"node_modules/@formatjs/icu-skeleton-parser/node_modules/@formatjs/intl-localematcher": {
"version": "0.2.25",
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz",
"integrity": "sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==",
"dependencies": {
"tslib": "^2.1.0"
} }
}, },
"node_modules/@formatjs/intl-localematcher": { "node_modules/@formatjs/intl-localematcher": {
@ -477,6 +436,59 @@
"node": ">=14" "node": ">=14"
} }
}, },
"node_modules/@redis/bloom": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz",
"integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
},
"node_modules/@redis/client": {
"version": "1.5.16",
"resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.16.tgz",
"integrity": "sha512-X1a3xQ5kEMvTib5fBrHKh6Y+pXbeKXqziYuxOUo1ojQNECg4M5Etd1qqyhMap+lFUOAh8S7UYevgJHOm4A+NOg==",
"dependencies": {
"cluster-key-slot": "1.1.2",
"generic-pool": "3.9.0",
"yallist": "4.0.0"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@redis/graph": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz",
"integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
},
"node_modules/@redis/json": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.6.tgz",
"integrity": "sha512-rcZO3bfQbm2zPRpqo82XbW8zg4G/w4W3tI7X8Mqleq9goQjAGLL7q/1n1ZX4dXEAmORVZ4s1+uKLaUOg7LrUhw==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
},
"node_modules/@redis/search": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.6.tgz",
"integrity": "sha512-mZXCxbTYKBQ3M2lZnEddwEAks0Kc7nauire8q20oA0oA/LoA+E/b5Y5KZn232ztPb1FkIGqo12vh3Lf+Vw5iTw==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
},
"node_modules/@redis/time-series": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.5.tgz",
"integrity": "sha512-IFjIgTusQym2B5IZJG3XKr5llka7ey84fw/NOYqESP5WUfQs9zz1ww/9+qoz4ka/S6KcGBodzlCeZ5UImKbscg==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
},
"node_modules/@reduxjs/toolkit": { "node_modules/@reduxjs/toolkit": {
"version": "2.2.3", "version": "2.2.3",
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.3.tgz", "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.3.tgz",
@ -501,9 +513,9 @@
} }
}, },
"node_modules/@rushstack/eslint-patch": { "node_modules/@rushstack/eslint-patch": {
"version": "1.10.2", "version": "1.10.3",
"resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.2.tgz", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.3.tgz",
"integrity": "sha512-hw437iINopmQuxWPSUEvqE56NCPsiU8N4AYtfHmJFckclktzK9YQJieD3XkDCDH4OjL+C7zgPUh73R/nrcHrqw==", "integrity": "sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg==",
"dev": true "dev": true
}, },
"node_modules/@swc/counter": { "node_modules/@swc/counter": {
@ -541,9 +553,9 @@
"dev": true "dev": true
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "20.12.7", "version": "20.12.12",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz",
"integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"undici-types": "~5.26.4" "undici-types": "~5.26.4"
@ -555,23 +567,33 @@
"integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q=="
}, },
"node_modules/@types/react": { "node_modules/@types/react": {
"version": "18.2.79", "version": "18.3.0",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.79.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.0.tgz",
"integrity": "sha512-RwGAGXPl9kSXwdNTafkOEuFrTBD5SA2B3iEB96xi8+xu5ddUa/cpvyVCSNn+asgLCTHkb5ZxN8gbuibYJi4s1w==", "integrity": "sha512-DiUcKjzE6soLyln8NNZmyhcQjVv+WsUIFSqetMN0p8927OztKT4VTfFTqsbAi5oAGIcgOmOajlfBqyptDDjZRw==",
"dependencies": { "dependencies": {
"@types/prop-types": "*", "@types/prop-types": "*",
"csstype": "^3.0.2" "csstype": "^3.0.2"
} }
}, },
"node_modules/@types/react-dom": { "node_modules/@types/react-dom": {
"version": "18.2.25", "version": "18.3.0",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.25.tgz", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz",
"integrity": "sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==", "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/react": "*" "@types/react": "*"
} }
}, },
"node_modules/@types/redis": {
"version": "4.0.11",
"resolved": "https://registry.npmjs.org/@types/redis/-/redis-4.0.11.tgz",
"integrity": "sha512-bI+gth8La8Wg/QCR1+V1fhrL9+LZUSWfcqpOj2Kc80ZQ4ffbdL173vQd5wovmoV9i071FU9oP2g6etLuEwb6Rg==",
"deprecated": "This is a stub types definition. redis provides its own type definitions, so you do not need this installed.",
"dev": true,
"dependencies": {
"redis": "*"
}
},
"node_modules/@types/use-sync-external-store": { "node_modules/@types/use-sync-external-store": {
"version": "0.0.3", "version": "0.0.3",
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
@ -1201,9 +1223,9 @@
} }
}, },
"node_modules/caniuse-lite": { "node_modules/caniuse-lite": {
"version": "1.0.30001612", "version": "1.0.30001620",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001620.tgz",
"integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==", "integrity": "sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew==",
"funding": [ "funding": [
{ {
"type": "opencollective", "type": "opencollective",
@ -1317,6 +1339,14 @@
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
}, },
"node_modules/cluster-key-slot": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/color-convert": { "node_modules/color-convert": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@ -1629,9 +1659,9 @@
"dev": true "dev": true
}, },
"node_modules/enhanced-resolve": { "node_modules/enhanced-resolve": {
"version": "5.16.0", "version": "5.16.1",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.1.tgz",
"integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", "integrity": "sha512-4U5pNsuDl0EhuZpq46M5xPslstkviJuhrdobaRDBk2Jy2KO37FDAJl4lb2KlNabxT0m4MTK2UHNrsAcphE8nyw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"graceful-fs": "^4.2.4", "graceful-fs": "^4.2.4",
@ -1734,14 +1764,14 @@
} }
}, },
"node_modules/es-iterator-helpers": { "node_modules/es-iterator-helpers": {
"version": "1.0.18", "version": "1.0.19",
"resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz", "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz",
"integrity": "sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==", "integrity": "sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"call-bind": "^1.0.7", "call-bind": "^1.0.7",
"define-properties": "^1.2.1", "define-properties": "^1.2.1",
"es-abstract": "^1.23.0", "es-abstract": "^1.23.3",
"es-errors": "^1.3.0", "es-errors": "^1.3.0",
"es-set-tostringtag": "^2.0.3", "es-set-tostringtag": "^2.0.3",
"function-bind": "^1.1.2", "function-bind": "^1.1.2",
@ -2098,9 +2128,9 @@
} }
}, },
"node_modules/eslint-plugin-react-hooks": { "node_modules/eslint-plugin-react-hooks": {
"version": "4.6.0", "version": "4.6.2",
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz",
"integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=10" "node": ">=10"
@ -2462,6 +2492,14 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/generic-pool": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz",
"integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==",
"engines": {
"node": ">= 4"
}
},
"node_modules/get-intrinsic": { "node_modules/get-intrinsic": {
"version": "1.2.4", "version": "1.2.4",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
@ -2499,9 +2537,9 @@
} }
}, },
"node_modules/get-tsconfig": { "node_modules/get-tsconfig": {
"version": "4.7.3", "version": "4.7.5",
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz",
"integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==", "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"resolve-pkg-maps": "^1.0.0" "resolve-pkg-maps": "^1.0.0"
@ -2593,12 +2631,13 @@
} }
}, },
"node_modules/globalthis": { "node_modules/globalthis": {
"version": "1.0.3", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
"integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"define-properties": "^1.1.3" "define-properties": "^1.2.1",
"gopd": "^1.0.1"
}, },
"engines": { "engines": {
"node": ">= 0.4" "node": ">= 0.4"
@ -2767,18 +2806,18 @@
} }
}, },
"node_modules/immer": { "node_modules/immer": {
"version": "10.0.4", "version": "10.1.1",
"resolved": "https://registry.npmjs.org/immer/-/immer-10.0.4.tgz", "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz",
"integrity": "sha512-cuBuGK40P/sk5IzWa9QPUaAdvPHjkk1c+xYsd9oZw+YQQEV+10G0P5uMpGctZZKnyQ+ibRO08bD25nWLmYi2pw==", "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==",
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/immer" "url": "https://opencollective.com/immer"
} }
}, },
"node_modules/immutable": { "node_modules/immutable": {
"version": "4.3.5", "version": "4.3.6",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz",
"integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", "integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==",
"devOptional": true "devOptional": true
}, },
"node_modules/import-fresh": { "node_modules/import-fresh": {
@ -2842,31 +2881,14 @@
} }
}, },
"node_modules/intl-messageformat": { "node_modules/intl-messageformat": {
"version": "9.13.0", "version": "10.5.12",
"resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-9.13.0.tgz", "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.5.12.tgz",
"integrity": "sha512-7sGC7QnSQGa5LZP7bXLDhVDtQOeKGeBFGHF2Y8LVBwYZoQZCgWeKoPGTa5GMG8g/TzDgeXuYJQis7Ggiw2xTOw==", "integrity": "sha512-izl0uxhy/melhw8gP2r8pGiVieviZmM4v5Oqx3c1/R7g9cwER2smmGfSjcIsp8Y3Q53bfciL/gkxacJRx/dUvg==",
"dependencies": { "dependencies": {
"@formatjs/ecma402-abstract": "1.11.4", "@formatjs/ecma402-abstract": "1.18.2",
"@formatjs/fast-memoize": "1.2.1", "@formatjs/fast-memoize": "2.2.0",
"@formatjs/icu-messageformat-parser": "2.1.0", "@formatjs/icu-messageformat-parser": "2.7.6",
"tslib": "^2.1.0" "tslib": "^2.4.0"
}
},
"node_modules/intl-messageformat/node_modules/@formatjs/ecma402-abstract": {
"version": "1.11.4",
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz",
"integrity": "sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==",
"dependencies": {
"@formatjs/intl-localematcher": "0.2.25",
"tslib": "^2.1.0"
}
},
"node_modules/intl-messageformat/node_modules/@formatjs/intl-localematcher": {
"version": "0.2.25",
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz",
"integrity": "sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==",
"dependencies": {
"tslib": "^2.1.0"
} }
}, },
"node_modules/is-array-buffer": { "node_modules/is-array-buffer": {
@ -3424,9 +3446,9 @@
} }
}, },
"node_modules/lru-cache": { "node_modules/lru-cache": {
"version": "10.2.0", "version": "10.2.2",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz",
"integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": "14 || >=16.14" "node": "14 || >=16.14"
@ -3527,9 +3549,9 @@
} }
}, },
"node_modules/minipass": { "node_modules/minipass": {
"version": "7.0.4", "version": "7.1.1",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz",
"integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=16 || 14 >=14.17" "node": ">=16 || 14 >=14.17"
@ -3839,17 +3861,17 @@
} }
}, },
"node_modules/optionator": { "node_modules/optionator": {
"version": "0.9.3", "version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
"integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@aashutoshrathi/word-wrap": "^1.2.3",
"deep-is": "^0.1.3", "deep-is": "^0.1.3",
"fast-levenshtein": "^2.0.6", "fast-levenshtein": "^2.0.6",
"levn": "^0.4.1", "levn": "^0.4.1",
"prelude-ls": "^1.2.1", "prelude-ls": "^1.2.1",
"type-check": "^0.4.0" "type-check": "^0.4.0",
"word-wrap": "^1.2.5"
}, },
"engines": { "engines": {
"node": ">= 0.8.0" "node": ">= 0.8.0"
@ -3954,16 +3976,16 @@
"dev": true "dev": true
}, },
"node_modules/path-scurry": { "node_modules/path-scurry": {
"version": "1.10.2", "version": "1.11.1",
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
"integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"lru-cache": "^10.2.0", "lru-cache": "^10.2.0",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
}, },
"engines": { "engines": {
"node": ">=16 || 14 >=14.17" "node": ">=16 || 14 >=14.18"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
@ -3979,9 +4001,9 @@
} }
}, },
"node_modules/picocolors": { "node_modules/picocolors": {
"version": "1.0.0", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew=="
}, },
"node_modules/picomatch": { "node_modules/picomatch": {
"version": "2.3.1", "version": "2.3.1",
@ -4105,9 +4127,9 @@
] ]
}, },
"node_modules/react": { "node_modules/react": {
"version": "18.2.0", "version": "18.3.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", "resolved": "https://registry.npmjs.org/react/-/react-18.3.0.tgz",
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", "integrity": "sha512-RPutkJftSAldDibyrjuku7q11d3oy6wKOyPe5K1HA/HwwrXcEqBdHsLypkC2FFYjP7bPUa6gbzSBhw4sY2JcDg==",
"dependencies": { "dependencies": {
"loose-envify": "^1.1.0" "loose-envify": "^1.1.0"
}, },
@ -4129,15 +4151,15 @@
} }
}, },
"node_modules/react-dom": { "node_modules/react-dom": {
"version": "18.2.0", "version": "18.3.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.0.tgz",
"integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", "integrity": "sha512-zaKdLBftQJnvb7FtDIpZtsAIb2MZU087RM8bRDZU8LVCCFYjPTsDZJNFUWPcVz3HFSN1n/caxi0ca4B/aaVQGQ==",
"dependencies": { "dependencies": {
"loose-envify": "^1.1.0", "loose-envify": "^1.1.0",
"scheduler": "^0.23.0" "scheduler": "^0.23.1"
}, },
"peerDependencies": { "peerDependencies": {
"react": "^18.2.0" "react": "^18.3.0"
} }
}, },
"node_modules/react-icons": { "node_modules/react-icons": {
@ -4201,6 +4223,22 @@
"node": ">=8.10.0" "node": ">=8.10.0"
} }
}, },
"node_modules/redis": {
"version": "4.6.14",
"resolved": "https://registry.npmjs.org/redis/-/redis-4.6.14.tgz",
"integrity": "sha512-GrNg/e33HtsQwNXL7kJT+iNFPSwE1IPmd7wzV3j4f2z0EYxZfZE7FVTmUysgAtqQQtg5NXF5SNLR9OdO/UHOfw==",
"workspaces": [
"./packages/*"
],
"dependencies": {
"@redis/bloom": "1.2.0",
"@redis/client": "1.5.16",
"@redis/graph": "1.1.1",
"@redis/json": "1.0.6",
"@redis/search": "1.1.6",
"@redis/time-series": "1.0.5"
}
},
"node_modules/redux": { "node_modules/redux": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
@ -4443,21 +4481,18 @@
} }
}, },
"node_modules/scheduler": { "node_modules/scheduler": {
"version": "0.23.0", "version": "0.23.2",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
"integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
"dependencies": { "dependencies": {
"loose-envify": "^1.1.0" "loose-envify": "^1.1.0"
} }
}, },
"node_modules/semver": { "node_modules/semver": {
"version": "7.6.0", "version": "7.6.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
"dev": true, "dev": true,
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": { "bin": {
"semver": "bin/semver.js" "semver": "bin/semver.js"
}, },
@ -4465,18 +4500,6 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/semver/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/set-function-length": { "node_modules/set-function-length": {
"version": "1.2.2", "version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@ -5028,21 +5051,21 @@
"integrity": "sha512-mtN6xk+Nac+oyJ/PrI7tzfmomRVNFIWKUbG8jdYFt52hxbiReFAXIjYskvu64/dvuW71IcB7lV8l0HvZMac6Jg==" "integrity": "sha512-mtN6xk+Nac+oyJ/PrI7tzfmomRVNFIWKUbG8jdYFt52hxbiReFAXIjYskvu64/dvuW71IcB7lV8l0HvZMac6Jg=="
}, },
"node_modules/use-intl": { "node_modules/use-intl": {
"version": "3.11.3", "version": "3.14.0",
"resolved": "https://registry.npmjs.org/use-intl/-/use-intl-3.11.3.tgz", "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-3.14.0.tgz",
"integrity": "sha512-qxW2CiDWQY6ilR7AxrQPp5qiU6hWWh7Ek8uBEKGjcO7KoRuJ/4/ybIi/Z7rTXnEHHvQyCT1dotyDT9WIBGwCWg==", "integrity": "sha512-Dy3B4C7ICGDM5ZDrnNpf8bDfFbnYYjK5vNzij0kPfJNM2G0nfLWGQvhBXEyPPKZpNvnkKkFasXR8AAxSwXTAoA==",
"dependencies": { "dependencies": {
"@formatjs/ecma402-abstract": "^1.11.4", "@formatjs/ecma402-abstract": "^1.11.4",
"intl-messageformat": "^9.3.18" "intl-messageformat": "^10.5.11"
}, },
"peerDependencies": { "peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0" "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
} }
}, },
"node_modules/use-sync-external-store": { "node_modules/use-sync-external-store": {
"version": "1.2.1", "version": "1.2.2",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.1.tgz", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz",
"integrity": "sha512-6MCBDr76UJmRpbF8pzP27uIoTocf3tITaMJ52mccgAhMJycuh5A/RL6mDZCTwTisj0Qfeq69FtjMCUX27U78oA==", "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==",
"peerDependencies": { "peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0" "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
} }
@ -5068,7 +5091,7 @@
"videojs-vtt.js": "0.15.5" "videojs-vtt.js": "0.15.5"
} }
}, },
"node_modules/video.js/node_modules/videojs-contrib-quality-levels": { "node_modules/videojs-contrib-quality-levels": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/videojs-contrib-quality-levels/-/videojs-contrib-quality-levels-4.0.0.tgz", "resolved": "https://registry.npmjs.org/videojs-contrib-quality-levels/-/videojs-contrib-quality-levels-4.0.0.tgz",
"integrity": "sha512-u5rmd8BjLwANp7XwuQ0Q/me34bMe6zg9PQdHfTS7aXgiVRbNTb4djcmfG7aeSrkpZjg+XCLezFNenlJaCjBHKw==", "integrity": "sha512-u5rmd8BjLwANp7XwuQ0Q/me34bMe6zg9PQdHfTS7aXgiVRbNTb4djcmfG7aeSrkpZjg+XCLezFNenlJaCjBHKw==",
@ -5203,6 +5226,15 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/word-wrap": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/wrap-ansi": { "node_modules/wrap-ansi": {
"version": "8.1.0", "version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
@ -5306,8 +5338,7 @@
"node_modules/yallist": { "node_modules/yallist": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
"dev": true
}, },
"node_modules/yocto-queue": { "node_modules/yocto-queue": {
"version": "0.1.0", "version": "0.1.0",

View File

@ -1,6 +1,6 @@
{ {
"name": "proxyraye-next", "name": "proxyraye-next",
"version": "0.2.0", "version": "0.3.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
@ -9,31 +9,33 @@
"lint": "next lint" "lint": "next lint"
}, },
"dependencies": { "dependencies": {
"@picocss/pico": "^2.0.6", "@picocss/pico": "2.0.6",
"@reduxjs/toolkit": "^2.2.3", "@reduxjs/toolkit": "2.2.3",
"axios": "^1.6.8", "axios": "1.6.8",
"cheerio": "^1.0.0-rc.12", "cheerio": "1.0.0-rc.12",
"classnames": "^2.5.1", "classnames": "2.5.1",
"next": "14.2.2", "next": "14.2.2",
"next-intl": "^3.11.3", "next-intl": "3.11.3",
"next-nprogress-bar": "^2.3.11", "next-nprogress-bar": "2.3.11",
"react": "^18", "react": "18.3.0",
"react-cookie": "^7.1.4", "react-cookie": "7.1.4",
"react-dom": "^18", "react-dom": "18.3.0",
"react-icons": "^5.1.0", "react-icons": "5.1.0",
"react-image": "^4.1.0", "react-image": "4.1.0",
"react-redux": "^9.1.1", "react-redux": "9.1.1",
"redux-persist": "^6.0.0", "redis": "4.6.14",
"video.js": "^8.10.0", "redux-persist": "6.0.0",
"videojs-hls-quality-selector": "^2.0.0" "video.js": "8.10.0",
"videojs-hls-quality-selector": "2.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20", "@types/node": "20.12.12",
"@types/react": "^18", "@types/react": "18.3.0",
"@types/react-dom": "^18", "@types/react-dom": "18.3.0",
"eslint": "^8", "@types/redis": "4.0.11",
"eslint": "8",
"eslint-config-next": "14.2.2", "eslint-config-next": "14.2.2",
"sass": "^1.75.0", "sass": "1.75.0",
"typescript": "^5" "typescript": "5.4.5"
} }
} }

4
src/constants/redis.ts Normal file
View File

@ -0,0 +1,4 @@
export const DEFAULT_XVIDEOS_CONTENT_EXPIRY = { EX: 60 * 60 * 24 };
export const DEFAULT_XNXX_CONTENT_EXPIRY = { EX: 60 * 60 * 24 };
export const DEFAULT_RELATED_VIDEO_KEY_PATH = '/related/'

38
src/redis/client.ts Normal file
View File

@ -0,0 +1,38 @@
import { createClient } from 'redis';
export const getDataFromRedis = async (key: string): Promise<Object | null> => {
if (Boolean(process.env.ENABLE_REDIS)) {
const redis = await createClient({ url: process.env.REDIS_URL })
.on('error', err => console.log('Redis Client Error', err))
.connect()
const cached = await redis.get(key);
if (cached) {
await redis.disconnect();
return JSON.parse(cached)
} else {
return null
}
} else {
return null
}
}
export const storeDataIntoRedis = async (key: string, data: Object, expiry?: Object) => {
if (Boolean(process.env.ENABLE_REDIS)) {
const redis = await createClient({ url: process.env.REDIS_URL })
.on('error', err => console.log('Redis Client Error', err))
.connect()
await redis.set(key, JSON.stringify(data), expiry);
await redis.disconnect();
}
}

View File

@ -1,5 +1,5 @@
import { FetchParams, GalleryData, VideoAgent, VideoData } from "@/meta/data"; import { FetchParams, GalleryData, VideoAgent, VideoData } from "@/meta/data";
import { fetchXNXXGalleryData, } from "./gallery"; import { fetchXNXXGalleryData } from "./gallery";
import { fetchXNXXVideoData } from "./video"; import { fetchXNXXVideoData } from "./video";
export class XNXXAgent implements VideoAgent { export class XNXXAgent implements VideoAgent {

View File

@ -8,6 +8,8 @@ import { getXNXXQueryUrl } from './url';
import { Platforms } from '@/meta/settings'; import { Platforms } from '@/meta/settings';
import { XNXX_BASE_URL } from '@/constants/urls'; import { XNXX_BASE_URL } from '@/constants/urls';
import { getDataFromRedis, storeDataIntoRedis } from '@/redis/client';
import { DEFAULT_XNXX_CONTENT_EXPIRY } from '@/constants/redis';
export const fetchXNXXGalleryData = async (params?: FetchParams): Promise<GalleryData[]> => { export const fetchXNXXGalleryData = async (params?: FetchParams): Promise<GalleryData[]> => {
@ -17,9 +19,15 @@ export const fetchXNXXGalleryData = async (params?: FetchParams): Promise<Galler
const queryUrl = await getXNXXQueryUrl(params?.query) const queryUrl = await getXNXXQueryUrl(params?.query)
const cachedData = await getDataFromRedis(queryUrl)
if (cachedData) {
return cachedData as GalleryData[]
}
await axios.get(queryUrl, reqHeaders) await axios.get(queryUrl, reqHeaders)
.then(response => { .then(async response => {
const html = response.data; const html = response.data;
@ -41,6 +49,8 @@ export const fetchXNXXGalleryData = async (params?: FetchParams): Promise<Galler
}) })
}) })
await storeDataIntoRedis(queryUrl, data, DEFAULT_XNXX_CONTENT_EXPIRY);
}).catch((error: AxiosError) => { }).catch((error: AxiosError) => {
// handle errors // handle errors
}); });

View File

@ -8,6 +8,8 @@ import * as cheerio from "cheerio";
import { Platforms } from '@/meta/settings'; import { Platforms } from '@/meta/settings';
import { findRelatedVideos, findVideoUrlInsideTagStringByFunctionNameAndExtension } from '@/utils/scrape/common/wgcz'; import { findRelatedVideos, findVideoUrlInsideTagStringByFunctionNameAndExtension } from '@/utils/scrape/common/wgcz';
import { getHeaders } from '@/utils/scrape/common/headers'; import { getHeaders } from '@/utils/scrape/common/headers';
import { DEFAULT_RELATED_VIDEO_KEY_PATH, DEFAULT_XNXX_CONTENT_EXPIRY } from '@/constants/redis';
import { getDataFromRedis, storeDataIntoRedis } from '@/redis/client';
export const fetchXNXXVideoData = async (videoId: string, params?: FetchParams): Promise<[VideoData, GalleryData[]]> => { export const fetchXNXXVideoData = async (videoId: string, params?: FetchParams): Promise<[VideoData, GalleryData[]]> => {
@ -23,9 +25,16 @@ export const fetchXNXXVideoData = async (videoId: string, params?: FetchParams):
const queryUrl = `${host}${videoId}` const queryUrl = `${host}${videoId}`
const cachedVideoData = await getDataFromRedis(queryUrl)
const cachedRelatedData = await getDataFromRedis(queryUrl + DEFAULT_RELATED_VIDEO_KEY_PATH)
if (cachedVideoData) {
return [cachedVideoData as VideoData, cachedRelatedData as GalleryData[] ?? []]
}
await axios.get(queryUrl, reqHeaders) await axios.get(queryUrl, reqHeaders)
.then(response => { .then(async response => {
const html = response.data; const html = response.data;
@ -54,6 +63,8 @@ export const fetchXNXXVideoData = async (videoId: string, params?: FetchParams):
}) })
await storeDataIntoRedis(queryUrl, data, DEFAULT_XNXX_CONTENT_EXPIRY);
// populate related gallery // populate related gallery
scriptTags.map((idx, elem) => { scriptTags.map((idx, elem) => {
const relatedVideos = findRelatedVideos($(elem).toString(), Platforms.xnxx) const relatedVideos = findRelatedVideos($(elem).toString(), Platforms.xnxx)
@ -63,6 +74,8 @@ export const fetchXNXXVideoData = async (videoId: string, params?: FetchParams):
} }
}) })
await storeDataIntoRedis(queryUrl + DEFAULT_RELATED_VIDEO_KEY_PATH, related, DEFAULT_XNXX_CONTENT_EXPIRY);
}).catch((error: AxiosError) => { }).catch((error: AxiosError) => {
// handle errors // handle errors
}); });

View File

@ -6,6 +6,9 @@ import { getHeaders } from '@/utils/scrape/common/headers';
import { getXVideosQueryUrl } from './url'; import { getXVideosQueryUrl } from './url';
import { Platforms } from '@/meta/settings'; import { Platforms } from '@/meta/settings';
import { getDataFromRedis, storeDataIntoRedis } from '@/redis/client';
import { DEFAULT_XVIDEOS_CONTENT_EXPIRY } from '@/constants/redis';
export const fetchXVideosGalleryData = async (params?: FetchParams): Promise<GalleryData[]> => { export const fetchXVideosGalleryData = async (params?: FetchParams): Promise<GalleryData[]> => {
let data: GalleryData[] = []; let data: GalleryData[] = [];
@ -14,22 +17,28 @@ export const fetchXVideosGalleryData = async (params?: FetchParams): Promise<Gal
const queryUrl = await getXVideosQueryUrl(params?.query) const queryUrl = await getXVideosQueryUrl(params?.query)
const cachedData = await getDataFromRedis(queryUrl)
if (cachedData) {
return cachedData as GalleryData[]
}
await axios.get(queryUrl, reqHeaders) await axios.get(queryUrl, reqHeaders)
.then(response => { .then(async response => {
const html = response.data; const html = response.data;
const $ = cheerio.load(html); const $ = cheerio.load(html);
const thumbs = $(".thumb-block"); const thumbs = $(".thumb-block");
thumbs.map((key, thumb) => { thumbs.map((key, thumb) => {
const videoUrl = $(thumb).find(".thumb a").attr("href") const videoUrl = $(thumb).find(".thumb a").attr("href")
const imgUrl = $(thumb).find(".thumb img").attr("data-src") const imgUrl = $(thumb).find(".thumb img").attr("data-src")
const text = $(thumb).find(".thumb-under a").attr("title") const text = $(thumb).find(".thumb-under a").attr("title")
videoUrl && imgUrl && text && data.push({ videoUrl && imgUrl && text && data.push({
videoUrl, videoUrl,
imgUrl, imgUrl,
@ -38,7 +47,10 @@ export const fetchXVideosGalleryData = async (params?: FetchParams): Promise<Gal
}) })
}) })
}).catch((error: AxiosError) => { await storeDataIntoRedis(queryUrl, data, DEFAULT_XVIDEOS_CONTENT_EXPIRY);
})
.catch((error: AxiosError) => {
// handle errors // handle errors
}); });

View File

@ -8,6 +8,8 @@ import { getHeaders } from '@/utils/scrape/common/headers';
import { Platforms } from '@/meta/settings'; import { Platforms } from '@/meta/settings';
import { findRelatedVideos, findVideoUrlInsideTagStringByFunctionNameAndExtension } from '@/utils/scrape/common/wgcz'; import { findRelatedVideos, findVideoUrlInsideTagStringByFunctionNameAndExtension } from '@/utils/scrape/common/wgcz';
import { getDataFromRedis, storeDataIntoRedis } from '@/redis/client';
import { DEFAULT_RELATED_VIDEO_KEY_PATH, DEFAULT_XVIDEOS_CONTENT_EXPIRY } from '@/constants/redis';
export const fetchXvideosVideoData = async (videoId: string, params?: FetchParams): Promise<[VideoData, GalleryData[]]> => { export const fetchXvideosVideoData = async (videoId: string, params?: FetchParams): Promise<[VideoData, GalleryData[]]> => {
@ -23,9 +25,16 @@ export const fetchXvideosVideoData = async (videoId: string, params?: FetchParam
const queryUrl = `${host}${videoId}` const queryUrl = `${host}${videoId}`
const cachedVideoData = await getDataFromRedis(queryUrl)
const cachedRelatedData = await getDataFromRedis(queryUrl + DEFAULT_RELATED_VIDEO_KEY_PATH)
if (cachedVideoData) {
return [cachedVideoData as VideoData, cachedRelatedData as GalleryData[] ?? []]
}
await axios.get(queryUrl, reqHeaders) await axios.get(queryUrl, reqHeaders)
.then(response => { .then(async response => {
const html = response.data; const html = response.data;
@ -54,6 +63,8 @@ export const fetchXvideosVideoData = async (videoId: string, params?: FetchParam
}) })
await storeDataIntoRedis(queryUrl, data, DEFAULT_XVIDEOS_CONTENT_EXPIRY);
// populate related gallery // populate related gallery
scriptTags.map((idx, elem) => { scriptTags.map((idx, elem) => {
const relatedVideos = findRelatedVideos($(elem).toString(), Platforms.xvideos) const relatedVideos = findRelatedVideos($(elem).toString(), Platforms.xvideos)
@ -63,6 +74,8 @@ export const fetchXvideosVideoData = async (videoId: string, params?: FetchParam
} }
}) })
await storeDataIntoRedis(queryUrl + DEFAULT_RELATED_VIDEO_KEY_PATH, related, DEFAULT_XVIDEOS_CONTENT_EXPIRY);
}).catch((error: AxiosError) => { }).catch((error: AxiosError) => {
// handle errors // handle errors
}); });