From 423cb0b951861e64cce43d31256cc1c70447fd5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=97=88=EC=A7=80=EC=98=88?= <78946499+HeoJiye@users.noreply.github.com> Date: Fri, 8 Dec 2023 10:24:31 +0900 Subject: [PATCH 01/67] =?UTF-8?q?docs:=20=EC=8B=9C=EC=8A=A4=ED=85=9C=20?= =?UTF-8?q?=EC=95=84=ED=82=A4=ED=85=8D=EC=B2=98=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 2dea7e8c..96213db8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # ๐Ÿš AI ํƒ€๋กœ ์ƒ๋‹ด ํ”Œ๋žซํผ, ๋งˆ๋ฒ•์˜ ์†Œ๋ผ๊ณ ๋‘ฅ
- +

@@ -28,7 +28,7 @@
  • - Project ๊ด€๋ฆฌ (GitHub Projects) + ๋ฐฑ๋กœ๊ทธ (GitHub Projects)
  • @@ -36,34 +36,9 @@
    -## ๋ธŒ๋žœ์น˜ ์ „๋žต +## ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜ -- main(๊ธฐ๋ณธ) - dev(๊ฐœ๋ฐœ) - feature branch -- ์ด์Šˆ๋ณ„๋กœ ๋ธŒ๋žœ์น˜ ์ƒ์„ฑ -- ๋ธŒ๋žœ์น˜ ๋„ค์ด๋ฐ ๊ทœ์น™ - - `{FE/BE}/feature/{issue-number}-{feature-name}` - - `{FE/BE}/bugfix/{issue-number}-{bugfix-name}` - - `{FE/BE}/refactor/{issue-number}-{refactor-name}` -- husky๋กœ commit message ์ด์Šˆ ์—ฐ๊ฒฐ ์ž๋™ํ™” -- PR merge ์‹œ, rebase merge - -
    - -## ์—…๋ฌด ๋ฐฉ์‹ - -- `์›”-๋ชฉ` `10์‹œ-19์‹œ` ์ฝ”์–ดํƒ€์ž„์— ์ •ํ•ด์ง„ ์žฅ์†Œ์—์„œ `๋Œ€๋ฉด`์œผ๋กœ ์ž‘์—…ํ•œ๋‹ค. -- ์ตœ๋Œ€ํ•œ ์ฝ”์–ดํƒ€์ž„ ๋‚ด์—๋งŒ ํ™œ๋™ํ•˜๊ธฐ๋ฅผ ์ง€ํ–ฅํ•œ๋‹ค. -- ์ด์Šˆ ํ•ด๊ฒฐ ์‹œ์— ๋ฐ”๋กœ PR์„ ๋‚ ๋ฆฌ๊ณ  `์ฝ”๋“œ ๋ฆฌ๋ทฐ`๋ฅผ ์š”์ฒญํ•œ๋‹ค. -- ์ฝ”๋“œ ๋ฆฌ๋ทฐ๋Š” `์ผ๊ด€์„ฑ`, `๊ฐ€๋…์„ฑ`, `์ปจ๋ฒค์…˜ ํ™•์ธ`, `์ฝ”๋“œ์˜ ์ดํ•ด`๋ฅผ ๋ชฉํ‘œ๋กœ ํ•œ๋‹ค. -- ๋‹น์ผ PR์€ ๋‹น์ผ ๋ฆฌ๋ทฐ๋ฅผ ๋ชฉํ‘œ๋กœ ํ•œ๋‹ค. -- ์ฝ”๋“œ ๋ฆฌ๋ทฐ ๋‹จ๊ณ„์  ์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ ์šฉํ•œ๋‹ค. - - โš ๏ธย : ๊ผญ ๋ฐ˜์˜ํ•ด์ค˜ (๋ฒ„๊ทธ/์„ฑ๋Šฅ์ด์Šˆ ํฌํ•จ!!) - - โ“: ์งˆ๋ฌธ! - - ๐Ÿ‘ : ๊ฐ์ข… ์นญ์ฐฌ,,, - - โœจ : ์ฝ”๋“œ ์Šคํƒ€์ผ ํ†ต์ผํ•˜์ž?? - - ๐Ÿ’ฌย : ๊ทธ๋ƒฅ comment -- `18์‹œ`๊นŒ์ง€ PR์„ ๋‚ ๋ฆฌ์ง€ ๋ชปํ•˜๋ฉด, ๊ทธ ์ด์œ ์— ๋Œ€ํ•ด์„œ ํ•จ๊ป˜ `ํšŒ๊ณ `ํ•œ๋‹ค. -- `18์‹œ-19์‹œ`์—๋Š” ๊ทธ ๋‚ ์˜ ์ด์Šˆ๋ฅผ ๊ณต์œ ํ•˜๊ณ , `๋ฌธ์„œํ™”`๋ฅผ ํ•˜๋Š” ์‹œ๊ฐ„์„ ๊ฐ–๋Š”๋‹ค. +![image](https://github.com/boostcampwm2023/web09-MagicConch/assets/78946499/dee03d42-2b4d-4bcd-bdfa-dc10f06e973a)
    From f16b1af51013dab8dfd30857a1e7eb64ccc84aae Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Fri, 8 Dec 2023 10:59:38 +0900 Subject: [PATCH 02/67] =?UTF-8?q?docs:=20=EC=9C=84=ED=82=A4=20=EC=A3=BC?= =?UTF-8?q?=EC=86=8C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 96213db8..b184733f 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,13 @@ ๋ฐฑ๋กœ๊ทธ (GitHub Projects) +
  • + + ์œ„ํ‚ค + +
  • -
    ## ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜ From 1e93533a3560a7c04974134303e86764a623deec Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sat, 9 Dec 2023 15:29:21 +0900 Subject: [PATCH 03/67] =?UTF-8?q?chore:=20=EC=BB=A4=EC=8A=A4=ED=85=80?= =?UTF-8?q?=ED=95=9C=20socket.io=20=ED=98=95=EC=8B=9D=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20install?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/signal/package-lock.json | 8 ++++---- backend/signal/package.json | 2 +- backend/was/package-lock.json | 14 +++++++------- backend/was/package.json | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/backend/signal/package-lock.json b/backend/signal/package-lock.json index 8bb89ba6..fea3edf8 100644 --- a/backend/signal/package-lock.json +++ b/backend/signal/package-lock.json @@ -16,7 +16,7 @@ "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.2.10", "@nestjs/websockets": "^10.2.10", - "@tarotmilktea/human-socketio-event": "^2.0.1", + "@tarotmilktea/human-socketio-event": "^2.0.2", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", "socket.io": "^4.7.2", @@ -1935,9 +1935,9 @@ "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" }, "node_modules/@tarotmilktea/human-socketio-event": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@tarotmilktea/human-socketio-event/-/human-socketio-event-2.0.1.tgz", - "integrity": "sha512-V8cIxWr8dL0Yo/5DrLNoiqN0e6EQV+D02Dc148/UAK2PglSybI8P3yKx+rWyry3uPMMecybB9nUIkXe5aWMM1w==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@tarotmilktea/human-socketio-event/-/human-socketio-event-2.0.2.tgz", + "integrity": "sha512-GNuloLBcHMO6icB7hH4CvjFSTwbHMZJqYry2o/W27VvDLOH89c3zF/RVBIlOlcouvHf8U5YJkl3J2HW/hEzoOw==" }, "node_modules/@trivago/prettier-plugin-sort-imports": { "version": "4.3.0", diff --git a/backend/signal/package.json b/backend/signal/package.json index 9e09aaab..a7d9eca6 100644 --- a/backend/signal/package.json +++ b/backend/signal/package.json @@ -27,7 +27,7 @@ "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.2.10", "@nestjs/websockets": "^10.2.10", - "@tarotmilktea/human-socketio-event": "^2.0.1", + "@tarotmilktea/human-socketio-event": "^2.0.2", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", "socket.io": "^4.7.2", diff --git a/backend/was/package-lock.json b/backend/was/package-lock.json index e1016321..9dffe53d 100644 --- a/backend/was/package-lock.json +++ b/backend/was/package-lock.json @@ -18,7 +18,7 @@ "@nestjs/swagger": "^7.1.15", "@nestjs/typeorm": "^10.0.0", "@nestjs/websockets": "^10.2.8", - "@tarotmilktea/ai-socketio-event": "^2.0.2", + "@tarotmilktea/ai-socketio-event": "^2.0.3", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "cookie-parser": "^1.4.6", @@ -2270,9 +2270,9 @@ "integrity": "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==" }, "node_modules/@tarotmilktea/ai-socketio-event": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@tarotmilktea/ai-socketio-event/-/ai-socketio-event-2.0.2.tgz", - "integrity": "sha512-bXWzxAHQo5a6fMee9WJ8uqW4AMiKU0fnk8PmYn+xH3SX/6J1bIdrq6JdNlzqKcSVSvtDg5yrkYIe44RuPnrGtg==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@tarotmilktea/ai-socketio-event/-/ai-socketio-event-2.0.3.tgz", + "integrity": "sha512-K8IRKzKJaCf4lU8KcbobVHi6Xmxil/5a/uWAwTUkuLPKAtUj8BkuNTG/6XiCQUXjTpfBdSWvIKsQVZuQSoaD7Q==" }, "node_modules/@trivago/prettier-plugin-sort-imports": { "version": "4.3.0", @@ -12938,9 +12938,9 @@ "integrity": "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==" }, "@tarotmilktea/ai-socketio-event": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@tarotmilktea/ai-socketio-event/-/ai-socketio-event-2.0.2.tgz", - "integrity": "sha512-bXWzxAHQo5a6fMee9WJ8uqW4AMiKU0fnk8PmYn+xH3SX/6J1bIdrq6JdNlzqKcSVSvtDg5yrkYIe44RuPnrGtg==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@tarotmilktea/ai-socketio-event/-/ai-socketio-event-2.0.3.tgz", + "integrity": "sha512-K8IRKzKJaCf4lU8KcbobVHi6Xmxil/5a/uWAwTUkuLPKAtUj8BkuNTG/6XiCQUXjTpfBdSWvIKsQVZuQSoaD7Q==" }, "@trivago/prettier-plugin-sort-imports": { "version": "4.3.0", diff --git a/backend/was/package.json b/backend/was/package.json index de0dd4aa..cdfd3505 100644 --- a/backend/was/package.json +++ b/backend/was/package.json @@ -29,7 +29,7 @@ "@nestjs/swagger": "^7.1.15", "@nestjs/typeorm": "^10.0.0", "@nestjs/websockets": "^10.2.8", - "@tarotmilktea/ai-socketio-event": "^2.0.2", + "@tarotmilktea/ai-socketio-event": "^2.0.3", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "cookie-parser": "^1.4.6", From acc4f9d0219c75fcc52c41639cd31c20dbb51e0a Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Sat, 9 Dec 2023 15:57:44 +0900 Subject: [PATCH 04/67] =?UTF-8?q?refactor:=20useMedia=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EB=AA=A8=EB=93=A0=20=EB=B3=80=EC=88=98=EB=A5=BC=20=EB=82=B4?= =?UTF-8?q?=EB=B3=B4=EB=82=B4=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit useRTCPeerConnection ํ›…์—์„œ ๋˜ ์ƒ์„ฑํ•˜๋ฉด ์–ด๋””์žˆ๋Š”์ง€ ์ฐพ๊ธฐ ์–ด๋ ค์› ์Œ. --- .../src/business/hooks/useWebRTC/useMedia.ts | 4 ++++ .../hooks/useWebRTC/useRTCPeerConnection.ts | 19 ++++++------------- .../src/business/hooks/useWebRTC/useWebRTC.ts | 3 ++- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/frontend/src/business/hooks/useWebRTC/useMedia.ts b/frontend/src/business/hooks/useWebRTC/useMedia.ts index 93b1391c..aeef9716 100644 --- a/frontend/src/business/hooks/useWebRTC/useMedia.ts +++ b/frontend/src/business/hooks/useWebRTC/useMedia.ts @@ -14,6 +14,7 @@ export function useMedia() { const [audioOptions, setAudioOptions] = useState([]); const localStreamRef = useRef(); + const remoteStreamRef = useRef(); const localVideoRef = useRef(null); const remoteVideoRef = useRef(null); @@ -30,6 +31,7 @@ export function useMedia() { setAudioOptions(audios); }; + // TODO: ์•„๋ž˜ ํ•จ์ˆ˜๋„ ์ฝ๊ธฐ ์‰ฝ๊ฒŒ ๋ฆฌํŒฉํ† ๋ง ํ•ด์•ผํ•จ, ํ˜„์žฌ๋Š” ๋ฌด์Šจ ๋œป์ธ์ง€ ๋‚˜๋„ ๋ชจ๋ฅด๊ฒ ์Œ const getMedia = async ({ audioID, cameraID }: { cameraID?: string; audioID?: string }) => { const _audioID = audioID || selectedAudioID; const _cameraID = cameraID || selectedCameraID; @@ -77,6 +79,8 @@ export function useMedia() { localVideoRef, remoteVideoRef, localStreamRef, + remoteStreamRef, + getMedia, getAudiosOptions, getCamerasOptions, diff --git a/frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts b/frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts index af16a243..f5ae597e 100644 --- a/frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts +++ b/frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts @@ -5,22 +5,15 @@ import { HumanSocketManager } from '@business/services/SocketManager'; import { iceServers } from '@constants/urls'; interface useRTCPeerConnectionParams { - remoteVideoRef: React.RefObject; + remoteVideoRef: React.RefObject; + remoteStreamRef: React.MutableRefObject; } -export function useRTCPeerConnection({ remoteVideoRef }: useRTCPeerConnectionParams) { +export function useRTCPeerConnection({ remoteVideoRef, remoteStreamRef }: useRTCPeerConnectionParams) { const peerConnectionRef = useRef(); - const peerStreamRef = useRef(null); const socketManager = new HumanSocketManager(); - // const prodIceServerConfig = [ - // { - // urls: `${import.meta.env.VITE_WAS_URL}/turn`, - // credential: import.meta.env.VITE_ICE_SERVER_CREDENTIAL, - // username: import.meta.env.VITE_ICER_SERVER_USERNAME, - // }, - // ]; const devIceServerConfig = [{ urls: iceServers }]; const makeRTCPeerConnection = async ({ roomName }: { roomName: string }) => { @@ -29,7 +22,7 @@ export function useRTCPeerConnection({ remoteVideoRef }: useRTCPeerConnectionPar }); peerConnectionRef.current.addEventListener('track', e => { - peerStreamRef.current = e.streams[0]; + remoteStreamRef.current = e.streams[0]; if (!remoteVideoRef.current) { return; } @@ -55,11 +48,11 @@ export function useRTCPeerConnection({ remoteVideoRef }: useRTCPeerConnectionPar }; useEffect(() => { - if (!remoteVideoRef.current) { + if (!remoteVideoRef.current || !remoteStreamRef.current) { return; } - remoteVideoRef.current.srcObject = peerStreamRef.current; + remoteVideoRef.current.srcObject = remoteStreamRef.current; }, [remoteVideoRef.current]); return { makeRTCPeerConnection, closeRTCPeerConnection, peerConnectionRef, isConnectedPeerConnection }; diff --git a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts index c27352eb..4b4ec281 100644 --- a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts +++ b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts @@ -11,6 +11,7 @@ export default function useWebRTC() { localVideoRef, remoteVideoRef, localStreamRef, + remoteStreamRef, cameraOptions, audioOptions, getMedia, @@ -19,7 +20,7 @@ export default function useWebRTC() { } = useMedia(); const { peerConnectionRef, makeRTCPeerConnection, closeRTCPeerConnection, isConnectedPeerConnection } = - useRTCPeerConnection({ remoteVideoRef }); + useRTCPeerConnection({ remoteVideoRef, remoteStreamRef }); const { mediaInfoChannel, chatChannel, initDataChannels, closeDataChannels, profileChannel, nicknameChannel } = useDataChannel({ From 6a4c8c85c9dd1fabf07ac866f80675209b874504 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sat, 9 Dec 2023 15:59:01 +0900 Subject: [PATCH 05/67] =?UTF-8?q?fix:=20--no-cache=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --no-cache ํ”Œ๋ž˜๊ทธ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ชจ๋“  ๋ ˆ์ด์–ด ์ƒˆ๋กญ๊ฒŒ ๋นŒ๋“œ -> ์„œ๋กœ ๋‹ค๋ฅธ ์ด๋ฏธ์ง€ ์•„์ด๋”” ๊ฐ–๋„๋ก ์ˆ˜์ • --- .github/workflows/blue-green-cd.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/blue-green-cd.yml b/.github/workflows/blue-green-cd.yml index 4b811dae..77e25c4d 100644 --- a/.github/workflows/blue-green-cd.yml +++ b/.github/workflows/blue-green-cd.yml @@ -2,7 +2,7 @@ name: Blue/Green CD on: push: - branches: ["dev"] + branches: ["BE/bugfix/#401-๋„์ปค-์บ์‹œ-์ด์Šˆ"] env: DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} @@ -54,8 +54,8 @@ jobs: - name: Build & Push Docker Images (Blue & Green) run: | cd backend - docker-compose -f docker-compose.blue.yml build - docker-compose -f docker-compose.green.yml build + docker-compose -f docker-compose.blue.yml build --no-cache + docker-compose -f docker-compose.green.yml build --no-cache docker-compose -f docker-compose.blue.yml push docker-compose -f docker-compose.green.yml push From 103368cc11ecdcba045c558c13594b92c3dc7586 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sat, 9 Dec 2023 16:35:56 +0900 Subject: [PATCH 06/67] =?UTF-8?q?fix:=20entity=20=EA=B2=BD=EB=A1=9C=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/was/src/common/config/database/database.module.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/was/src/common/config/database/database.module.ts b/backend/was/src/common/config/database/database.module.ts index ef3e2cdb..8e050f98 100644 --- a/backend/was/src/common/config/database/database.module.ts +++ b/backend/was/src/common/config/database/database.module.ts @@ -15,7 +15,7 @@ import { SnakeNamingStrategy } from 'typeorm-naming-strategies'; username: configService.get('DB_USERNAME'), password: configService.get('DB_PASSWORD'), database: configService.get('DB_DATABASE'), - entities: ['src/**/*.entity{.ts,.js}'], + entities: ['src/**/entites/*.entity{.ts,.js}'], autoLoadEntities: true, namingStrategy: new SnakeNamingStrategy(), extra: { From f0e0a0bc2acd4455c8a2295128fc7879d2182fcd Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sat, 9 Dec 2023 16:49:28 +0900 Subject: [PATCH 07/67] =?UTF-8?q?fix:=20entity=20=EA=B2=BD=EB=A1=9C=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/was/src/common/config/database/database.module.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/was/src/common/config/database/database.module.ts b/backend/was/src/common/config/database/database.module.ts index 8e050f98..32bb3c25 100644 --- a/backend/was/src/common/config/database/database.module.ts +++ b/backend/was/src/common/config/database/database.module.ts @@ -15,7 +15,7 @@ import { SnakeNamingStrategy } from 'typeorm-naming-strategies'; username: configService.get('DB_USERNAME'), password: configService.get('DB_PASSWORD'), database: configService.get('DB_DATABASE'), - entities: ['src/**/entites/*.entity{.ts,.js}'], + // entities: ['src/**/entites/*.entity{.ts,.js}'], autoLoadEntities: true, namingStrategy: new SnakeNamingStrategy(), extra: { From aa5313c2fa749ff1f4dafbf70063530fd5229d28 Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Sat, 9 Dec 2023 16:50:47 +0900 Subject: [PATCH 08/67] =?UTF-8?q?refactor:=20=EC=B9=B4=EB=A9=94=EB=9D=BC,?= =?UTF-8?q?=20=EC=98=A4=EB=94=94=EC=98=A4=20=EA=B0=80=EC=A0=B8=EC=98=A4?= =?UTF-8?q?=EB=8A=94=20=EB=B6=80=EB=B6=84=20=EB=8B=A4=EB=A5=B8=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ์ด ๋ถ€๋ถ„์€ ๊ตณ์ด useMedia ์•ˆ์— ์žˆ์„ ํ•„์š”๊ฐ€ ์—†์Œ. - ๋‹ค๋ฅธ๊ณณ์—์„œ๋„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜๋ผ ์ƒ๊ฐํ•ด์„œ ๋ถ„๋ฆฌ์‹œํ‚ด --- .../src/business/hooks/useWebRTC/useMedia.ts | 63 ++++++------------- .../src/business/hooks/useWebRTC/useWebRTC.ts | 20 ++---- frontend/src/business/services/Media.ts | 28 +++++++++ .../src/pages/HumanChatPage/SettingPage.tsx | 13 ++-- .../useSettingPageMediaOptions.tsx | 28 +++++++++ 5 files changed, 86 insertions(+), 66 deletions(-) create mode 100644 frontend/src/business/services/Media.ts create mode 100644 frontend/src/pages/HumanChatPage/useSettingPageMediaOptions.tsx diff --git a/frontend/src/business/hooks/useWebRTC/useMedia.ts b/frontend/src/business/hooks/useWebRTC/useMedia.ts index aeef9716..d4ba9b8c 100644 --- a/frontend/src/business/hooks/useWebRTC/useMedia.ts +++ b/frontend/src/business/hooks/useWebRTC/useMedia.ts @@ -1,4 +1,6 @@ -import { useRef, useState } from 'react'; +import { useRef } from 'react'; + +import { getUserMediaStream } from '@business/services/Media'; import { useMediaInfo } from '@stores/zustandStores/useMediaInfo'; @@ -10,48 +12,36 @@ export function useMedia() { myVideoOn: state.myVideoOn, })); - const [cameraOptions, setCameraOptions] = useState([]); - const [audioOptions, setAudioOptions] = useState([]); - const localStreamRef = useRef(); const remoteStreamRef = useRef(); const localVideoRef = useRef(null); const remoteVideoRef = useRef(null); - const getCamerasOptions = async () => { - const devices = await navigator.mediaDevices.enumerateDevices(); - const cameras = devices.filter(device => device.kind === 'videoinput'); - setCameraOptions(cameras); - }; - - const getAudiosOptions = async () => { - const devices = await navigator.mediaDevices.enumerateDevices(); - const audios = devices.filter(device => device.kind === 'audioinput'); - setAudioOptions(audios); + const setLocalVideo = (stream: MediaStream) => { + if (localVideoRef.current) { + localVideoRef.current.srcObject = stream; + localStreamRef.current = stream; + } }; - // TODO: ์•„๋ž˜ ํ•จ์ˆ˜๋„ ์ฝ๊ธฐ ์‰ฝ๊ฒŒ ๋ฆฌํŒฉํ† ๋ง ํ•ด์•ผํ•จ, ํ˜„์žฌ๋Š” ๋ฌด์Šจ ๋œป์ธ์ง€ ๋‚˜๋„ ๋ชจ๋ฅด๊ฒ ์Œ - const getMedia = async ({ audioID, cameraID }: { cameraID?: string; audioID?: string }) => { - const _audioID = audioID || selectedAudioID; - const _cameraID = cameraID || selectedCameraID; + const getMedia = async ({ audioID, cameraID }: { cameraID?: string; audioID?: string } = {}) => { + const nowSelectedAudioID = audioID || selectedAudioID; + const nowSelectedCameraID = cameraID || selectedCameraID; const audioOptions = { - withAudioId: { deviceId: _audioID }, - default: true, + withAudioID: { deviceId: nowSelectedAudioID }, + withoutAudioID: true, }; const videoOptions = { - withCameraId: { deviceId: _cameraID, width: 320, height: 320 }, - default: { facingMode: 'user', width: 320, height: 320 }, + withCameraID: { deviceId: nowSelectedCameraID, width: 320, height: 320 }, + withoutCameraID: { facingMode: 'user', width: 320, height: 320 }, }; - const audioOption = _audioID ? audioOptions.withAudioId : audioOptions.default; - const videoOption = _cameraID ? videoOptions.withCameraId : videoOptions.default; + const audio = nowSelectedAudioID ? audioOptions.withAudioID : audioOptions.withoutAudioID; + const video = nowSelectedCameraID ? videoOptions.withCameraID : videoOptions.withoutCameraID; - const stream = await navigator.mediaDevices.getUserMedia({ - audio: audioOption, - video: videoOption, - }); + const stream = await getUserMediaStream({ audio, video }); if (!myVideoOn) { stream.getVideoTracks().forEach(track => (track.enabled = false)); @@ -60,29 +50,14 @@ export function useMedia() { stream.getAudioTracks().forEach(track => (track.enabled = false)); } - if (localVideoRef.current) { - localVideoRef.current.srcObject = stream; - localStreamRef.current = stream; - } - - if (!selectedAudioID) { - await getCamerasOptions(); - } - if (!selectedCameraID) { - await getAudiosOptions(); - } + setLocalVideo(stream); }; return { - cameraOptions, - audioOptions, localVideoRef, remoteVideoRef, localStreamRef, remoteStreamRef, - getMedia, - getAudiosOptions, - getCamerasOptions, }; } diff --git a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts index 4b4ec281..ce0251fa 100644 --- a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts +++ b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts @@ -7,17 +7,7 @@ import { useRTCPeerConnection } from './useRTCPeerConnection'; import { useSignalingSocket } from './useSignalingSocket'; export default function useWebRTC() { - const { - localVideoRef, - remoteVideoRef, - localStreamRef, - remoteStreamRef, - cameraOptions, - audioOptions, - getMedia, - getAudiosOptions, - getCamerasOptions, - } = useMedia(); + const { localVideoRef, remoteVideoRef, localStreamRef, remoteStreamRef, getMedia } = useMedia(); const { peerConnectionRef, makeRTCPeerConnection, closeRTCPeerConnection, isConnectedPeerConnection } = useRTCPeerConnection({ remoteVideoRef, remoteStreamRef }); @@ -73,8 +63,8 @@ export default function useWebRTC() { }, []); return { - cameraOptions, - audioOptions, + // cameraOptions, + // audioOptions, localVideoRef, remoteVideoRef, mediaInfoChannel, @@ -86,8 +76,8 @@ export default function useWebRTC() { addTracks, changeMyAudioTrack, changeMyVideoTrack, - getAudiosOptions, - getCamerasOptions, + // getAudiosOptions, + // getCamerasOptions, getMedia, startWebRTC, endWebRTC, diff --git a/frontend/src/business/services/Media.ts b/frontend/src/business/services/Media.ts new file mode 100644 index 00000000..c80c1099 --- /dev/null +++ b/frontend/src/business/services/Media.ts @@ -0,0 +1,28 @@ +export async function getCameraInputOptions() { + const devices = await navigator.mediaDevices.enumerateDevices(); + const cameraOptions = devices.filter(device => device.kind === 'videoinput'); + return cameraOptions; +} + +export async function getAudioInputOptions() { + const devices = await navigator.mediaDevices.enumerateDevices(); + const audiosOptions = devices.filter(device => device.kind === 'audioinput'); + return audiosOptions; +} + +export async function getMediaDeviceOptions() { + const devices = await navigator.mediaDevices.enumerateDevices(); + const cameraOptions = devices.filter(device => device.kind === 'videoinput'); + const audiosOptions = devices.filter(device => device.kind === 'audioinput'); + return { cameraOptions, audiosOptions }; +} + +export async function getUserMediaStream({ + audio, + video, +}: { + audio: boolean | MediaTrackConstraints | undefined; + video: boolean | MediaTrackConstraints | undefined; +}) { + return await navigator.mediaDevices.getUserMedia({ audio, video }); +} diff --git a/frontend/src/pages/HumanChatPage/SettingPage.tsx b/frontend/src/pages/HumanChatPage/SettingPage.tsx index 6142133a..8908d524 100644 --- a/frontend/src/pages/HumanChatPage/SettingPage.tsx +++ b/frontend/src/pages/HumanChatPage/SettingPage.tsx @@ -6,6 +6,7 @@ import ProfileSetting from '@components/ProfileSetting'; import { HumanSocketManager } from '@business/services/SocketManager'; import type { OutletContext } from './HumanChatPage'; +import { useSettingPageMediaOptinos } from './useSettingPageMediaOptions'; import { useSettingPageProfileNicknameSetting } from './useSettingPageProfileNicknameSetting'; export default function ChattingPage() { @@ -15,8 +16,6 @@ export default function ChattingPage() { const { localVideoRef, - cameraOptions, - audioOptions, toggleVideo, toggleAudio, changeMyVideoTrack, @@ -30,23 +29,23 @@ export default function ChattingPage() { if (!socketManager.connected) { navigate('..'); } + changeMyVideoTrack(); }, []); - const camList = cameraOptions.map(({ deviceId, label }) => ({ label, value: deviceId })); - const micList = audioOptions.map(({ deviceId, label }) => ({ label, value: deviceId })); - const { setLocalNickname, setLocalProfileImage, sendProfileInfoWithNavigateBefore } = useSettingPageProfileNicknameSetting(); + const { mediaOptions } = useSettingPageMediaOptinos(); + return ( { sendProfileInfoWithNavigateBefore(); diff --git a/frontend/src/pages/HumanChatPage/useSettingPageMediaOptions.tsx b/frontend/src/pages/HumanChatPage/useSettingPageMediaOptions.tsx new file mode 100644 index 00000000..d1314d09 --- /dev/null +++ b/frontend/src/pages/HumanChatPage/useSettingPageMediaOptions.tsx @@ -0,0 +1,28 @@ +import { useEffect, useState } from 'react'; + +import { getMediaDeviceOptions } from '@business/services/Media'; + +export function useSettingPageMediaOptinos() { + const [mediaOptions, setMediaOptions] = useState<{ + audio: { label: string; value: string }[]; + video: { label: string; value: string }[]; + }>({ + audio: [], + video: [], + }); + + const changeMediaOptions = async () => { + const { audiosOptions, cameraOptions } = await getMediaDeviceOptions(); + + setMediaOptions({ + audio: audiosOptions.map(({ deviceId, label }) => ({ label, value: deviceId })), + video: cameraOptions.map(({ deviceId, label }) => ({ label, value: deviceId })), + }); + }; + + useEffect(() => { + changeMediaOptions(); + }, []); + + return { mediaOptions }; +} From 609ffea0af46120d4786eb1e6df85eaf43fc3eec Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Sat, 9 Dec 2023 17:02:02 +0900 Subject: [PATCH 09/67] =?UTF-8?q?refactor:=20WebRTC=20=EB=AA=A8=EB=93=88?= =?UTF-8?q?=EC=9D=98=20stream=EC=9D=84=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/business/hooks/useWebRTC/WebRTC.ts | 21 +++++++++++++++++++ .../hooks/useWebRTC/useControllMedia.ts | 16 +++++++------- .../src/business/hooks/useWebRTC/useMedia.ts | 13 ++++++------ .../hooks/useWebRTC/useRTCPeerConnection.ts | 13 +++++++----- .../src/business/hooks/useWebRTC/useWebRTC.ts | 5 ++--- 5 files changed, 46 insertions(+), 22 deletions(-) create mode 100644 frontend/src/business/hooks/useWebRTC/WebRTC.ts diff --git a/frontend/src/business/hooks/useWebRTC/WebRTC.ts b/frontend/src/business/hooks/useWebRTC/WebRTC.ts new file mode 100644 index 00000000..57c64cd3 --- /dev/null +++ b/frontend/src/business/hooks/useWebRTC/WebRTC.ts @@ -0,0 +1,21 @@ +export default class WebRTC { + public localStream: MediaStream | undefined; + public remoteStream: MediaStream | undefined; + + private static instance: WebRTC | undefined; + constructor() {} + + static getInstace() { + if (!this.instance) { + this.instance = new WebRTC(); + } + return this.instance; + } + + public setLocalStream(stream: MediaStream) { + this.localStream = stream; + } + public setRemoteStream(stream: MediaStream) { + this.remoteStream = stream; + } +} diff --git a/frontend/src/business/hooks/useWebRTC/useControllMedia.ts b/frontend/src/business/hooks/useWebRTC/useControllMedia.ts index b5986421..693a95d4 100644 --- a/frontend/src/business/hooks/useWebRTC/useControllMedia.ts +++ b/frontend/src/business/hooks/useWebRTC/useControllMedia.ts @@ -2,8 +2,9 @@ import { useEffect } from 'react'; import { useMediaInfo } from '@stores/zustandStores/useMediaInfo'; +import WebRTC from './WebRTC'; + interface useContorollMediaParams { - localStreamRef: React.MutableRefObject; peerConnectionRef: React.MutableRefObject; localVideoRef: React.RefObject; mediaInfoChannel: React.MutableRefObject; @@ -12,7 +13,6 @@ interface useContorollMediaParams { export function useControllMedia({ localVideoRef, - localStreamRef, peerConnectionRef, mediaInfoChannel, getMedia, @@ -27,23 +27,25 @@ export function useControllMedia({ selectedCameraID: state.selectedCameraID, })); + const webRTC = WebRTC.getInstace(); + const addTracks = () => { - if (localStreamRef.current === undefined) { + if (webRTC.localStream === undefined) { return; } - localStreamRef.current.getTracks().forEach(track => { - peerConnectionRef.current?.addTrack(track, localStreamRef.current!); + webRTC.localStream.getTracks().forEach(track => { + peerConnectionRef.current?.addTrack(track, webRTC.localStream!); }); }; const changeVideoTrack = () => { - const nowTrack = localStreamRef.current?.getVideoTracks()[0]; + const nowTrack = webRTC.localStream?.getVideoTracks()[0]; const sender = peerConnectionRef.current?.getSenders().find(sender => sender.track?.kind === 'video'); sender?.replaceTrack(nowTrack!); }; const changeAudioTrack = () => { - const nowTrack = localStreamRef.current?.getAudioTracks()[0]; + const nowTrack = webRTC.localStream?.getAudioTracks()[0]; const sender = peerConnectionRef.current?.getSenders().find(sender => sender.track?.kind === 'audio'); sender?.replaceTrack(nowTrack!); }; diff --git a/frontend/src/business/hooks/useWebRTC/useMedia.ts b/frontend/src/business/hooks/useWebRTC/useMedia.ts index d4ba9b8c..4ee8440e 100644 --- a/frontend/src/business/hooks/useWebRTC/useMedia.ts +++ b/frontend/src/business/hooks/useWebRTC/useMedia.ts @@ -4,6 +4,8 @@ import { getUserMediaStream } from '@business/services/Media'; import { useMediaInfo } from '@stores/zustandStores/useMediaInfo'; +import WebRTC from './WebRTC'; + export function useMedia() { const { myMicOn, myVideoOn, selectedAudioID, selectedCameraID } = useMediaInfo(state => ({ selectedAudioID: state.selectedAudioID, @@ -12,16 +14,15 @@ export function useMedia() { myVideoOn: state.myVideoOn, })); - const localStreamRef = useRef(); - const remoteStreamRef = useRef(); + const webRTC = WebRTC.getInstace(); const localVideoRef = useRef(null); const remoteVideoRef = useRef(null); - const setLocalVideo = (stream: MediaStream) => { + const setLocalVideoWithLocalStream = (stream: MediaStream) => { if (localVideoRef.current) { localVideoRef.current.srcObject = stream; - localStreamRef.current = stream; + webRTC.setLocalStream(stream); } }; @@ -50,14 +51,12 @@ export function useMedia() { stream.getAudioTracks().forEach(track => (track.enabled = false)); } - setLocalVideo(stream); + setLocalVideoWithLocalStream(stream); }; return { localVideoRef, remoteVideoRef, - localStreamRef, - remoteStreamRef, getMedia, }; } diff --git a/frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts b/frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts index f5ae597e..08cbd234 100644 --- a/frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts +++ b/frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts @@ -4,25 +4,28 @@ import { HumanSocketManager } from '@business/services/SocketManager'; import { iceServers } from '@constants/urls'; +import WebRTC from './WebRTC'; + interface useRTCPeerConnectionParams { remoteVideoRef: React.RefObject; - remoteStreamRef: React.MutableRefObject; } -export function useRTCPeerConnection({ remoteVideoRef, remoteStreamRef }: useRTCPeerConnectionParams) { +export function useRTCPeerConnection({ remoteVideoRef }: useRTCPeerConnectionParams) { const peerConnectionRef = useRef(); const socketManager = new HumanSocketManager(); const devIceServerConfig = [{ urls: iceServers }]; + const webRTC = WebRTC.getInstace(); + const makeRTCPeerConnection = async ({ roomName }: { roomName: string }) => { peerConnectionRef.current = new RTCPeerConnection({ iceServers: import.meta.env.MODE === 'development' ? devIceServerConfig : devIceServerConfig, }); peerConnectionRef.current.addEventListener('track', e => { - remoteStreamRef.current = e.streams[0]; + webRTC.setRemoteStream(e.streams[0]); if (!remoteVideoRef.current) { return; } @@ -48,11 +51,11 @@ export function useRTCPeerConnection({ remoteVideoRef, remoteStreamRef }: useRTC }; useEffect(() => { - if (!remoteVideoRef.current || !remoteStreamRef.current) { + if (!remoteVideoRef.current || !webRTC.remoteStream) { return; } - remoteVideoRef.current.srcObject = remoteStreamRef.current; + remoteVideoRef.current.srcObject = webRTC.remoteStream; }, [remoteVideoRef.current]); return { makeRTCPeerConnection, closeRTCPeerConnection, peerConnectionRef, isConnectedPeerConnection }; diff --git a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts index ce0251fa..11840887 100644 --- a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts +++ b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts @@ -7,10 +7,10 @@ import { useRTCPeerConnection } from './useRTCPeerConnection'; import { useSignalingSocket } from './useSignalingSocket'; export default function useWebRTC() { - const { localVideoRef, remoteVideoRef, localStreamRef, remoteStreamRef, getMedia } = useMedia(); + const { localVideoRef, remoteVideoRef, getMedia } = useMedia(); const { peerConnectionRef, makeRTCPeerConnection, closeRTCPeerConnection, isConnectedPeerConnection } = - useRTCPeerConnection({ remoteVideoRef, remoteStreamRef }); + useRTCPeerConnection({ remoteVideoRef }); const { mediaInfoChannel, chatChannel, initDataChannels, closeDataChannels, profileChannel, nicknameChannel } = useDataChannel({ @@ -18,7 +18,6 @@ export default function useWebRTC() { }); const { addTracks, changeMyAudioTrack, changeMyVideoTrack, toggleAudio, toggleVideo } = useControllMedia({ - localStreamRef, peerConnectionRef, localVideoRef, mediaInfoChannel, From 8ede6b6c7e03ca3baaf3a4c25eb73dc1e217b3b9 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sat, 9 Dec 2023 17:27:13 +0900 Subject: [PATCH 10/67] =?UTF-8?q?fix:=20winston=20transport=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/logger/winston/winston.transports.ts | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/backend/was/src/logger/winston/winston.transports.ts b/backend/was/src/logger/winston/winston.transports.ts index fea8f30b..eb7e1a4a 100644 --- a/backend/was/src/logger/winston/winston.transports.ts +++ b/backend/was/src/logger/winston/winston.transports.ts @@ -20,19 +20,10 @@ function createDailyRotateFile(level: string): DailyRotateFile { }); } -export const debugTransports: transports.ConsoleTransportInstance = - new transports.Console({ - level: 'debug', - }); - -export const infoTransports: transports.FileTransportInstance = - new transports.File(createDailyRotateFile('info')); - -export const warnTransports: transports.FileTransportInstance = - new transports.File(createDailyRotateFile('warn')); - -export const errorTransports: transports.FileTransportInstance = - new transports.File(createDailyRotateFile('error')); - -export const fatalTransports: transports.FileTransportInstance = - new transports.File(createDailyRotateFile('fatal')); +export const debugTransports = new transports.Console({ + level: 'debug', +}); +export const infoTransports: DailyRotateFile = createDailyRotateFile('info'); +export const warnTransports: DailyRotateFile = createDailyRotateFile('warn'); +export const errorTransports: DailyRotateFile = createDailyRotateFile('error'); +export const fatalTransports: DailyRotateFile = createDailyRotateFile('fatal'); From 9fddd73feca4f4961dedb98765e18af25baa4339 Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Sat, 9 Dec 2023 17:48:16 +0900 Subject: [PATCH 11/67] =?UTF-8?q?refactor:=20RTCPeerConnection=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EB=A1=9C=EC=A7=81=20WebRTC=EB=A1=9C=20=EB=84=A3?= =?UTF-8?q?=EC=9D=8C.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hooks/useWebRTC/useRTCPeerConnection.ts | 26 ++++-------------- .../src/business/hooks/useWebRTC/useWebRTC.ts | 27 +++++++------------ 2 files changed, 14 insertions(+), 39 deletions(-) diff --git a/frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts b/frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts index 08cbd234..a6e4ea61 100644 --- a/frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts +++ b/frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts @@ -1,9 +1,7 @@ -import { useEffect, useRef } from 'react'; +import { useEffect } from 'react'; import { HumanSocketManager } from '@business/services/SocketManager'; -import { iceServers } from '@constants/urls'; - import WebRTC from './WebRTC'; interface useRTCPeerConnectionParams { @@ -11,20 +9,14 @@ interface useRTCPeerConnectionParams { } export function useRTCPeerConnection({ remoteVideoRef }: useRTCPeerConnectionParams) { - const peerConnectionRef = useRef(); - const socketManager = new HumanSocketManager(); - const devIceServerConfig = [{ urls: iceServers }]; - const webRTC = WebRTC.getInstace(); const makeRTCPeerConnection = async ({ roomName }: { roomName: string }) => { - peerConnectionRef.current = new RTCPeerConnection({ - iceServers: import.meta.env.MODE === 'development' ? devIceServerConfig : devIceServerConfig, - }); + webRTC.connectRTCPeerConnection(); - peerConnectionRef.current.addEventListener('track', e => { + webRTC.addRTCPeerConnectionEventListener('track', e => { webRTC.setRemoteStream(e.streams[0]); if (!remoteVideoRef.current) { return; @@ -33,7 +25,7 @@ export function useRTCPeerConnection({ remoteVideoRef }: useRTCPeerConnectionPar remoteVideoRef.current.srcObject = e.streams[0]; }); - peerConnectionRef.current.addEventListener('icecandidate', e => { + webRTC.addRTCPeerConnectionEventListener('icecandidate', e => { if (!e.candidate) { return; } @@ -42,14 +34,6 @@ export function useRTCPeerConnection({ remoteVideoRef }: useRTCPeerConnectionPar }); }; - const closeRTCPeerConnection = () => { - peerConnectionRef.current?.close(); - }; - - const isConnectedPeerConnection = () => { - return peerConnectionRef.current?.iceConnectionState === 'connected'; - }; - useEffect(() => { if (!remoteVideoRef.current || !webRTC.remoteStream) { return; @@ -58,5 +42,5 @@ export function useRTCPeerConnection({ remoteVideoRef }: useRTCPeerConnectionPar remoteVideoRef.current.srcObject = webRTC.remoteStream; }, [remoteVideoRef.current]); - return { makeRTCPeerConnection, closeRTCPeerConnection, peerConnectionRef, isConnectedPeerConnection }; + return { makeRTCPeerConnection }; } diff --git a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts index 11840887..1c44d10f 100644 --- a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts +++ b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts @@ -1,5 +1,6 @@ import { useEffect } from 'react'; +import WebRTC from './WebRTC'; import { useControllMedia } from './useControllMedia'; import { useDataChannel } from './useDataChannel'; import { useMedia } from './useMedia'; @@ -7,25 +8,21 @@ import { useRTCPeerConnection } from './useRTCPeerConnection'; import { useSignalingSocket } from './useSignalingSocket'; export default function useWebRTC() { + const webRTC = WebRTC.getInstace(); + const { localVideoRef, remoteVideoRef, getMedia } = useMedia(); - const { peerConnectionRef, makeRTCPeerConnection, closeRTCPeerConnection, isConnectedPeerConnection } = - useRTCPeerConnection({ remoteVideoRef }); + const { makeRTCPeerConnection } = useRTCPeerConnection({ remoteVideoRef }); - const { mediaInfoChannel, chatChannel, initDataChannels, closeDataChannels, profileChannel, nicknameChannel } = - useDataChannel({ - peerConnectionRef, - }); + const { initDataChannels } = useDataChannel({}); const { addTracks, changeMyAudioTrack, changeMyVideoTrack, toggleAudio, toggleVideo } = useControllMedia({ - peerConnectionRef, localVideoRef, - mediaInfoChannel, getMedia, }); const negotiationDataChannels = ({ roomName }: { roomName: string }) => { - closeRTCPeerConnection(); + webRTC.closeRTCPeerConnection(); closeDataChannels(); makeRTCPeerConnection({ roomName }); initDataChannels(); @@ -33,12 +30,11 @@ export default function useWebRTC() { }; const { initSignalingSocket, createRoom, joinRoom, checkRoomExist } = useSignalingSocket({ - peerConnectionRef, negotiationDataChannels, }); const startWebRTC = async ({ roomName }: { roomName: string }) => { - if (isConnectedPeerConnection()) { + if (webRTC.isConnectedPeerConnection()) { return; } await getMedia({}); @@ -49,8 +45,8 @@ export default function useWebRTC() { }; const endWebRTC = () => { - if (isConnectedPeerConnection()) { - closeRTCPeerConnection(); + if (webRTC.isConnectedPeerConnection()) { + webRTC.closeRTCPeerConnection(); closeDataChannels(); } }; @@ -62,8 +58,6 @@ export default function useWebRTC() { }, []); return { - // cameraOptions, - // audioOptions, localVideoRef, remoteVideoRef, mediaInfoChannel, @@ -75,14 +69,11 @@ export default function useWebRTC() { addTracks, changeMyAudioTrack, changeMyVideoTrack, - // getAudiosOptions, - // getCamerasOptions, getMedia, startWebRTC, endWebRTC, createRoom, joinRoom, checkRoomExist, - isConnectedPeerConnection, }; } From d697d50cf9aaad2527af57f946ae8e5771eddb2f Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Sat, 9 Dec 2023 18:01:15 +0900 Subject: [PATCH 12/67] =?UTF-8?q?feat:=20useMedia=20=ED=9B=85=20useWebRTC?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/business/hooks/useWebRTC/useMedia.ts | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/frontend/src/business/hooks/useWebRTC/useMedia.ts b/frontend/src/business/hooks/useWebRTC/useMedia.ts index 4ee8440e..f9306d7c 100644 --- a/frontend/src/business/hooks/useWebRTC/useMedia.ts +++ b/frontend/src/business/hooks/useWebRTC/useMedia.ts @@ -1,4 +1,4 @@ -import { useRef } from 'react'; +import { RefObject } from 'react'; import { getUserMediaStream } from '@business/services/Media'; @@ -16,14 +16,18 @@ export function useMedia() { const webRTC = WebRTC.getInstace(); - const localVideoRef = useRef(null); - const remoteVideoRef = useRef(null); - - const setLocalVideoWithLocalStream = (stream: MediaStream) => { - if (localVideoRef.current) { - localVideoRef.current.srcObject = stream; - webRTC.setLocalStream(stream); + const setLocalVideoWithLocalStream = ({ + stream, + localVideoRef, + }: { + stream: MediaStream; + localVideoRef: RefObject; + }) => { + if (!localVideoRef.current) { + return; } + localVideoRef.current.srcObject = stream; + webRTC.setLocalStream(stream); }; const getMedia = async ({ audioID, cameraID }: { cameraID?: string; audioID?: string } = {}) => { @@ -50,13 +54,10 @@ export function useMedia() { if (!myMicOn) { stream.getAudioTracks().forEach(track => (track.enabled = false)); } - - setLocalVideoWithLocalStream(stream); }; return { - localVideoRef, - remoteVideoRef, getMedia, + setLocalVideoWithLocalStream, }; } From e3b5e4facdd1e32e6cae73dbb14c1f5b12ad74ed Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sat, 9 Dec 2023 18:14:01 +0900 Subject: [PATCH 13/67] =?UTF-8?q?remove:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=9A=A9=20=EB=B8=8C=EB=9E=9C=EC=B9=98=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/blue-green-cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/blue-green-cd.yml b/.github/workflows/blue-green-cd.yml index 77e25c4d..72d29e02 100644 --- a/.github/workflows/blue-green-cd.yml +++ b/.github/workflows/blue-green-cd.yml @@ -2,7 +2,7 @@ name: Blue/Green CD on: push: - branches: ["BE/bugfix/#401-๋„์ปค-์บ์‹œ-์ด์Šˆ"] + branches: ["dev"] env: DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} From cab2f1650602ea4b1c56c9b11701150c77a636f3 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Thu, 7 Dec 2023 14:06:14 +0900 Subject: [PATCH 14/67] =?UTF-8?q?chore:=20sentry=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=ED=8C=A8=ED=82=A4=EC=A7=80=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/was/package-lock.json | 1993 ++++++++++++++++++++++++++++++++- backend/was/package.json | 2 + 2 files changed, 1957 insertions(+), 38 deletions(-) diff --git a/backend/was/package-lock.json b/backend/was/package-lock.json index 9dffe53d..a658fd60 100644 --- a/backend/was/package-lock.json +++ b/backend/was/package-lock.json @@ -19,6 +19,8 @@ "@nestjs/typeorm": "^10.0.0", "@nestjs/websockets": "^10.2.8", "@tarotmilktea/ai-socketio-event": "^2.0.3", + "@sentry/node": "^7.85.0", + "@sentry/profiling-node": "^1.2.6", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "cookie-parser": "^1.4.6", @@ -1211,6 +1213,11 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==" + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.13", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", @@ -2188,6 +2195,75 @@ "node": ">= 8" } }, + "node_modules/@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/move-file": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/move-file/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/move-file/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/move-file/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@nuxtjs/opencollective": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@nuxtjs/opencollective/-/opencollective-0.3.2.tgz", @@ -2235,6 +2311,100 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@sentry-internal/tracing": { + "version": "7.85.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.85.0.tgz", + "integrity": "sha512-p3YMUwkPCy2su9cm/3+7QYR4RiMI0+07DU1BZtht9NLTzY2O87/yvUbn1v2yHR3vJQTy/+7N0ud9/mPBFznRQQ==", + "dependencies": { + "@sentry/core": "7.85.0", + "@sentry/types": "7.85.0", + "@sentry/utils": "7.85.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/core": { + "version": "7.85.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.85.0.tgz", + "integrity": "sha512-DFDAc4tWmHN5IWhr7XbHCiyF1Xgb95jz8Uj/JTX9atlgodId1UIbER77qpEmH3eQGid/QBdqrlR98zCixgSbwg==", + "dependencies": { + "@sentry/types": "7.85.0", + "@sentry/utils": "7.85.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/hub": { + "version": "7.85.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-7.85.0.tgz", + "integrity": "sha512-08Vq+N7P538D68HpIq4GpvGkqc2zj3yk0Xh5z0xYBf4QoTDTzeELt9Ryi5lCW9mgXVzHbKbgzcxIO1EE4FugoA==", + "dependencies": { + "@sentry/core": "7.85.0", + "@sentry/types": "7.85.0", + "@sentry/utils": "7.85.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/node": { + "version": "7.85.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.85.0.tgz", + "integrity": "sha512-uiBtRW9G017NHoCXBlK3ttkTwHXLFyI8ndHpaObtyajKTv3ptGIThVEn7DuK7Pwor//RjwjSEEOa7WDK+FdMVQ==", + "dependencies": { + "@sentry-internal/tracing": "7.85.0", + "@sentry/core": "7.85.0", + "@sentry/types": "7.85.0", + "@sentry/utils": "7.85.0", + "https-proxy-agent": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/profiling-node": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@sentry/profiling-node/-/profiling-node-1.2.6.tgz", + "integrity": "sha512-WsXO7VmLze5wPWHpvoRZFTtN+wHw9lYWKZs4T2FwPmvfNVaScGJey/+Wp51aM47Yy12Gj9n/BpqFYDsUXRLMvw==", + "hasInstallScript": true, + "dependencies": { + "@sentry/core": "^7.76.0", + "@sentry/hub": "^7.76.0", + "@sentry/node": "^7.76.0", + "@sentry/types": "^7.76.0", + "@sentry/utils": "^7.76.0", + "detect-libc": "^2.0.2", + "node-abi": "^3.47.0", + "node-gyp": "^9.4.0" + }, + "bin": { + "sentry-prune-profiler-binaries": "scripts/prune-profiler-binaries.mjs" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@sentry/types": { + "version": "7.85.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.85.0.tgz", + "integrity": "sha512-R5jR4XkK5tBU2jDiPdSVqzkmjYRr666bcGaFGUHB/xDQCjPsjk+pEmCCL+vpuWoaZmQJUE1hVU7rgnVX81w8zg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@sentry/utils": { + "version": "7.85.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.85.0.tgz", + "integrity": "sha512-JZ7seNOLvhjAQ8GeB3GYknPQJkuhF88xAYOaESZP3xPOWBMFUN+IO4RqjMqMLFDniOwsVQS7GB/MfP+hxufieg==", + "dependencies": { + "@sentry/types": "7.85.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -2274,6 +2444,14 @@ "resolved": "https://registry.npmjs.org/@tarotmilktea/ai-socketio-event/-/ai-socketio-event-2.0.3.tgz", "integrity": "sha512-K8IRKzKJaCf4lU8KcbobVHi6Xmxil/5a/uWAwTUkuLPKAtUj8BkuNTG/6XiCQUXjTpfBdSWvIKsQVZuQSoaD7Q==" }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "engines": { + "node": ">= 10" + } + }, "node_modules/@trivago/prettier-plugin-sort-imports": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.3.0.tgz", @@ -3021,6 +3199,11 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -3072,6 +3255,40 @@ "node": ">=0.4.0" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/ajv": { "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", @@ -3182,6 +3399,36 @@ "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -3597,7 +3844,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3731,6 +3977,159 @@ "node": ">= 0.8" } }, + "node_modules/cacache": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/cacache/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacache/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacache/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/cacache/node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/cacache/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/call-bind": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", @@ -3839,6 +4238,14 @@ "fsevents": "~2.3.2" } }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, "node_modules/chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", @@ -3884,6 +4291,14 @@ "validator": "^13.7.0" } }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "engines": { + "node": ">=6" + } + }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -4091,6 +4506,14 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "bin": { + "color-support": "bin.js" + } + }, "node_modules/color/node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -4162,8 +4585,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/concat-stream": { "version": "1.6.2", @@ -4190,6 +4612,11 @@ "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -4603,6 +5030,11 @@ "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, "node_modules/denque": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", @@ -4628,6 +5060,14 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -4755,6 +5195,27 @@ "node": ">= 0.8" } }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -4805,6 +5266,19 @@ "node": ">=10.13.0" } }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -5461,6 +5935,11 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==" + }, "node_modules/express": { "version": "4.18.2", "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", @@ -5921,6 +6400,33 @@ "node": ">=12" } }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/fs-monkey": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", @@ -5981,6 +6487,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/gauge/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, "node_modules/generate-function": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", @@ -6179,8 +6708,7 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/graphemer": { "version": "1.4.0", @@ -6262,6 +6790,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, "node_modules/hasown": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", @@ -6296,6 +6829,11 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -6311,6 +6849,31 @@ "node": ">= 0.8" } }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -6320,6 +6883,14 @@ "node": ">=10.17.0" } }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dependencies": { + "ms": "^2.0.0" + } + }, "node_modules/husky": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", @@ -6413,11 +6984,23 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, "engines": { "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -6481,6 +7064,11 @@ "node": ">= 0.10" } }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -6668,6 +7256,11 @@ "node": ">=8" } }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==" + }, "node_modules/is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", @@ -6861,8 +7454,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", @@ -7864,6 +8456,56 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "devOptional": true }, + "node_modules/make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/make-fetch-happen/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/make-fetch-happen/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -7977,7 +8619,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -8002,6 +8643,174 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-collect/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-fetch/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-fetch/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -8135,6 +8944,17 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "node_modules/node-abi": { + "version": "3.52.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.52.0.tgz", + "integrity": "sha512-JJ98b02z16ILv7859irtXn4oUaFWADtvkzy2c0IAatNVX2Mc9Yoh8z6hZInn3QwvMEYhHuQloYi+TTQy67SIdQ==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/node-abort-controller": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", @@ -8169,6 +8989,63 @@ } } }, + "node_modules/node-gyp": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", + "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.13 || ^14.13 || >=16" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -8181,6 +9058,20 @@ "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", "dev": true }, + "node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -8202,6 +9093,20 @@ "node": ">=8" } }, + "node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -8471,6 +9376,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -8549,7 +9468,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -8775,6 +9693,23 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==" + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -9077,6 +10012,14 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "engines": { + "node": ">= 4" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -9334,7 +10277,6 @@ "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -9349,7 +10291,6 @@ "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" }, @@ -9360,8 +10301,7 @@ "node_modules/semver/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/send": { "version": "0.18.0", @@ -9432,6 +10372,11 @@ "node": ">= 0.8.0" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, "node_modules/set-function-length": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", @@ -9588,6 +10533,15 @@ "node": ">=8" } }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, "node_modules/socket.io": { "version": "4.7.2", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.2.tgz", @@ -9625,6 +10579,32 @@ "node": ">=10.0.0" } }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/source-map": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", @@ -9667,6 +10647,33 @@ "node": ">= 0.6" } }, + "node_modules/ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ssri/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ssri/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -9973,6 +10980,46 @@ "node": ">=6" } }, + "node_modules/tar": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/terser": { "version": "5.24.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.24.0.tgz", @@ -10717,6 +11764,28 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, + "node_modules/unique-filename": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "dependencies": { + "unique-slug": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/unique-slug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", @@ -10975,7 +12044,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -11021,6 +12089,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, "node_modules/windows-release": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-4.0.0.tgz", @@ -12218,6 +13294,11 @@ "integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==", "dev": true }, + "@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==" + }, "@humanwhocodes/config-array": { "version": "0.11.13", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", @@ -12872,6 +13953,52 @@ "fastq": "^1.6.0" } }, + "@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "requires": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + } + }, + "@npmcli/move-file": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, "@nuxtjs/opencollective": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@nuxtjs/opencollective/-/opencollective-0.3.2.tgz", @@ -12903,6 +14030,75 @@ "tslib": "^2.6.0" } }, + "@sentry-internal/tracing": { + "version": "7.85.0", + "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.85.0.tgz", + "integrity": "sha512-p3YMUwkPCy2su9cm/3+7QYR4RiMI0+07DU1BZtht9NLTzY2O87/yvUbn1v2yHR3vJQTy/+7N0ud9/mPBFznRQQ==", + "requires": { + "@sentry/core": "7.85.0", + "@sentry/types": "7.85.0", + "@sentry/utils": "7.85.0" + } + }, + "@sentry/core": { + "version": "7.85.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.85.0.tgz", + "integrity": "sha512-DFDAc4tWmHN5IWhr7XbHCiyF1Xgb95jz8Uj/JTX9atlgodId1UIbER77qpEmH3eQGid/QBdqrlR98zCixgSbwg==", + "requires": { + "@sentry/types": "7.85.0", + "@sentry/utils": "7.85.0" + } + }, + "@sentry/hub": { + "version": "7.85.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-7.85.0.tgz", + "integrity": "sha512-08Vq+N7P538D68HpIq4GpvGkqc2zj3yk0Xh5z0xYBf4QoTDTzeELt9Ryi5lCW9mgXVzHbKbgzcxIO1EE4FugoA==", + "requires": { + "@sentry/core": "7.85.0", + "@sentry/types": "7.85.0", + "@sentry/utils": "7.85.0" + } + }, + "@sentry/node": { + "version": "7.85.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.85.0.tgz", + "integrity": "sha512-uiBtRW9G017NHoCXBlK3ttkTwHXLFyI8ndHpaObtyajKTv3ptGIThVEn7DuK7Pwor//RjwjSEEOa7WDK+FdMVQ==", + "requires": { + "@sentry-internal/tracing": "7.85.0", + "@sentry/core": "7.85.0", + "@sentry/types": "7.85.0", + "@sentry/utils": "7.85.0", + "https-proxy-agent": "^5.0.0" + } + }, + "@sentry/profiling-node": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@sentry/profiling-node/-/profiling-node-1.2.6.tgz", + "integrity": "sha512-WsXO7VmLze5wPWHpvoRZFTtN+wHw9lYWKZs4T2FwPmvfNVaScGJey/+Wp51aM47Yy12Gj9n/BpqFYDsUXRLMvw==", + "requires": { + "@sentry/core": "^7.76.0", + "@sentry/hub": "^7.76.0", + "@sentry/node": "^7.76.0", + "@sentry/types": "^7.76.0", + "@sentry/utils": "^7.76.0", + "detect-libc": "^2.0.2", + "node-abi": "^3.47.0", + "node-gyp": "^9.4.0" + } + }, + "@sentry/types": { + "version": "7.85.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.85.0.tgz", + "integrity": "sha512-R5jR4XkK5tBU2jDiPdSVqzkmjYRr666bcGaFGUHB/xDQCjPsjk+pEmCCL+vpuWoaZmQJUE1hVU7rgnVX81w8zg==" + }, + "@sentry/utils": { + "version": "7.85.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.85.0.tgz", + "integrity": "sha512-JZ7seNOLvhjAQ8GeB3GYknPQJkuhF88xAYOaESZP3xPOWBMFUN+IO4RqjMqMLFDniOwsVQS7GB/MfP+hxufieg==", + "requires": { + "@sentry/types": "7.85.0" + } + }, "@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -12942,6 +14138,11 @@ "resolved": "https://registry.npmjs.org/@tarotmilktea/ai-socketio-event/-/ai-socketio-event-2.0.3.tgz", "integrity": "sha512-K8IRKzKJaCf4lU8KcbobVHi6Xmxil/5a/uWAwTUkuLPKAtUj8BkuNTG/6XiCQUXjTpfBdSWvIKsQVZuQSoaD7Q==" }, + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==" + }, "@trivago/prettier-plugin-sort-imports": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.3.0.tgz", @@ -13588,6 +14789,11 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, "accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -13623,6 +14829,31 @@ "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", "devOptional": true }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, + "agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "requires": { + "humanize-ms": "^1.2.1" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, "ajv": { "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", @@ -13697,6 +14928,32 @@ "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", @@ -14016,7 +15273,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -14098,6 +15354,124 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" }, + "cacache": { + "version": "16.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", + "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "requires": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^2.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, "call-bind": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", @@ -14163,6 +15537,11 @@ "readdirp": "~3.6.0" } }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + }, "chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", @@ -14196,6 +15575,11 @@ "validator": "^13.7.0" } }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" + }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -14367,6 +15751,11 @@ "simple-swizzle": "^0.2.2" } }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" + }, "colorspace": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", @@ -14413,8 +15802,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "concat-stream": { "version": "1.6.2", @@ -14438,6 +15826,11 @@ "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, "content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -14712,6 +16105,11 @@ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, "denque": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", @@ -14727,6 +16125,11 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, + "detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==" + }, "detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -14821,6 +16224,26 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -14862,6 +16285,16 @@ "tapable": "^2.2.0" } }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==" + }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -15357,6 +16790,11 @@ "jest-util": "^29.7.0" } }, + "exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==" + }, "express": { "version": "4.18.2", "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", @@ -15738,6 +17176,29 @@ "universalify": "^2.0.0" } }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, "fs-monkey": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", @@ -15773,12 +17234,34 @@ "functions-have-names": "^1.2.3" } }, - "functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true - }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "dependencies": { + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + } + } + }, "generate-function": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", @@ -15919,8 +17402,7 @@ "graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "graphemer": { "version": "1.4.0", @@ -15972,6 +17454,11 @@ "has-symbols": "^1.0.2" } }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, "hasown": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", @@ -15997,6 +17484,11 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, "http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -16009,12 +17501,39 @@ "toidentifier": "1.0.1" } }, + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "requires": { + "agent-base": "6", + "debug": "4" + } + }, "human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "requires": { + "ms": "^2.0.0" + } + }, "husky": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", @@ -16063,8 +17582,17 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" }, "inflight": { "version": "1.0.6", @@ -16120,6 +17648,11 @@ "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", "dev": true }, + "ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -16241,6 +17774,11 @@ "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "dev": true }, + "is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==" + }, "is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", @@ -16364,8 +17902,7 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "istanbul-lib-coverage": { "version": "3.2.2", @@ -17142,6 +18679,49 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "devOptional": true }, + "make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" + }, + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, "makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -17225,7 +18805,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -17241,6 +18820,148 @@ "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", "dev": true }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "requires": { + "encoding": "^0.1.13", + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, "mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -17351,6 +19072,14 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "node-abi": { + "version": "3.52.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.52.0.tgz", + "integrity": "sha512-JJ98b02z16ILv7859irtXn4oUaFWADtvkzy2c0IAatNVX2Mc9Yoh8z6hZInn3QwvMEYhHuQloYi+TTQy67SIdQ==", + "requires": { + "semver": "^7.3.5" + } + }, "node-abort-controller": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", @@ -17374,6 +19103,47 @@ "whatwg-url": "^5.0.0" } }, + "node-gyp": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", + "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", + "requires": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^10.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -17386,6 +19156,14 @@ "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", "dev": true }, + "nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "requires": { + "abbrev": "^1.0.0" + } + }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -17401,6 +19179,17 @@ "path-key": "^3.0.0" } }, + "npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "requires": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + } + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -17592,6 +19381,14 @@ "p-limit": "^3.0.2" } }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "requires": { + "aggregate-error": "^3.0.0" + } + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -17653,8 +19450,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, "path-key": { "version": "3.1.1", @@ -17814,6 +19610,20 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==" + }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, "prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -18035,6 +19845,11 @@ } } }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==" + }, "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -18208,7 +20023,6 @@ "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, "requires": { "lru-cache": "^6.0.0" }, @@ -18217,7 +20031,6 @@ "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, "requires": { "yallist": "^4.0.0" } @@ -18225,8 +20038,7 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } }, @@ -18297,6 +20109,11 @@ "send": "0.18.0" } }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, "set-function-length": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", @@ -18418,6 +20235,11 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" + }, "socket.io": { "version": "4.7.2", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.2.tgz", @@ -18449,6 +20271,25 @@ "debug": "~4.3.1" } }, + "socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + } + }, "source-map": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", @@ -18484,6 +20325,29 @@ "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==" }, + "ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "requires": { + "minipass": "^3.1.1" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, "stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -18707,6 +20571,36 @@ "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true }, + "tar": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==" + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, "terser": { "version": "5.24.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.24.0.tgz", @@ -19156,6 +21050,22 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, + "unique-filename": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", + "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "requires": { + "unique-slug": "^3.0.0" + } + }, + "unique-slug": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", + "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "requires": { + "imurmurhash": "^0.1.4" + } + }, "universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", @@ -19342,7 +21252,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "requires": { "isexe": "^2.0.0" } @@ -19373,6 +21282,14 @@ "has-tostringtag": "^1.0.0" } }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, "windows-release": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-4.0.0.tgz", diff --git a/backend/was/package.json b/backend/was/package.json index cdfd3505..876fa9e3 100644 --- a/backend/was/package.json +++ b/backend/was/package.json @@ -30,6 +30,8 @@ "@nestjs/typeorm": "^10.0.0", "@nestjs/websockets": "^10.2.8", "@tarotmilktea/ai-socketio-event": "^2.0.3", + "@sentry/node": "^7.85.0", + "@sentry/profiling-node": "^1.2.6", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "cookie-parser": "^1.4.6", From 6268f18aa0520d29c53d6bfde8df0d0648f06fd8 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Thu, 7 Dec 2023 14:14:08 +0900 Subject: [PATCH 15/67] =?UTF-8?q?feat:=20sentry=20SDK=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ๋ฒ„๊ทธ ๋ฐ ์—๋Ÿฌ๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋ง/๋””๋ฒ„๊น… ํ•˜๊ธฐ ์œ„ํ•ด Sentry ์‚ฌ์šฉ - dsn : Sentry ํ”„๋กœ์ ํŠธ์— ๋Œ€ํ•œ ๊ณ ์œ  ์‹๋ณ„์ž - ProfilingIntegration : ํ”„๋กœํŒŒ์ผ๋ง ์ •๋ณด ์ˆ˜์ง‘ ํ™œ์„ฑํ™” - tracesSampleRate : ํŠธ๋žœ์žญ์…˜ ์ถ”์  ์ƒ˜ํ”Œ๋ง ๋น„์œจ - profilesSampleRate : ํ”„๋กœํŒŒ์ผ ๋ฐ์ดํ„ฐ ์ƒ˜ํ”Œ๋ง ๋น„์œจ --- backend/was/src/common/config/sentry.setting.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 backend/was/src/common/config/sentry.setting.ts diff --git a/backend/was/src/common/config/sentry.setting.ts b/backend/was/src/common/config/sentry.setting.ts new file mode 100644 index 00000000..8dd477b3 --- /dev/null +++ b/backend/was/src/common/config/sentry.setting.ts @@ -0,0 +1,11 @@ +import * as Sentry from '@sentry/node'; +import { ProfilingIntegration } from '@sentry/profiling-node'; + +export function setupSentry(dsn: string): void { + Sentry.init({ + dsn: dsn, + integrations: [new ProfilingIntegration()], + tracesSampleRate: 1.0, + profilesSampleRate: 1.0, + }); +} From 5d1db2d66cdc7bd3ef9ac7a2d08c876cd2a88662 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Thu, 7 Dec 2023 14:21:45 +0900 Subject: [PATCH 16/67] =?UTF-8?q?feat:=20=EC=96=B4=ED=94=8C=EB=A6=AC?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=85=98=20=EC=A0=95=EB=B3=B4=20Sentry?= =?UTF-8?q?=EB=A1=9C=20=EC=A0=84=EB=8B=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - errorHandler() : ์˜ˆ์™ธ ์ถ”์  - tracingHandler() : ์ฝ”๋“œ ์„ฑ๋Šฅ ์ถ”์  - requestHandler() : HTTP ์š”์ฒญ ์ถ”์  --- backend/was/src/common/config/sentry.setting.ts | 7 ++++++- backend/was/src/main.ts | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/backend/was/src/common/config/sentry.setting.ts b/backend/was/src/common/config/sentry.setting.ts index 8dd477b3..596d4f9e 100644 --- a/backend/was/src/common/config/sentry.setting.ts +++ b/backend/was/src/common/config/sentry.setting.ts @@ -1,11 +1,16 @@ +import { INestApplication } from '@nestjs/common/interfaces/nest-application.interface'; import * as Sentry from '@sentry/node'; import { ProfilingIntegration } from '@sentry/profiling-node'; -export function setupSentry(dsn: string): void { +export function setupSentry(app: INestApplication, dsn: string): void { Sentry.init({ dsn: dsn, integrations: [new ProfilingIntegration()], tracesSampleRate: 1.0, profilesSampleRate: 1.0, }); + + app.use(Sentry.Handlers.errorHandler()); + app.use(Sentry.Handlers.tracingHandler()); + app.use(Sentry.Handlers.requestHandler()); } diff --git a/backend/was/src/main.ts b/backend/was/src/main.ts index 5547a736..5ccbcfd7 100644 --- a/backend/was/src/main.ts +++ b/backend/was/src/main.ts @@ -2,6 +2,7 @@ import { ValidationPipe } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; import * as cookieParser from 'cookie-parser'; import { AppModule } from './app.module'; +import { setupSentry } from './common/config/sentry.setting'; import { setupSwagger } from './common/config/swagger.setting'; import { LoggerService } from './logger/logger.service'; @@ -20,6 +21,9 @@ async function bootstrap() { const logger: LoggerService = app.get(LoggerService); app.useLogger(logger); + const dsn: string = process.env.SENTRY_DSN || ''; + setupSentry(app, dsn); + setupSwagger(app); const port: number = parseInt(process.env.PORT || '3000'); From ca0a2e3451c480982d99a29e12e9c5b8f83dd22f Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Thu, 7 Dec 2023 14:37:18 +0900 Subject: [PATCH 17/67] =?UTF-8?q?feat:=20SENTRY=5FDSN=20=ED=99=98=EA=B2=BD?= =?UTF-8?q?=EB=B3=80=EC=88=98=20=EC=A3=BC=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/blue-green-cd.yml | 3 ++- backend/docker-compose.blue.yml | 1 + backend/docker-compose.green.yml | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/blue-green-cd.yml b/.github/workflows/blue-green-cd.yml index 72d29e02..9939931a 100644 --- a/.github/workflows/blue-green-cd.yml +++ b/.github/workflows/blue-green-cd.yml @@ -2,7 +2,7 @@ name: Blue/Green CD on: push: - branches: ["dev"] + branches: ["dev", "BE/refactor/#419-sentry"] env: DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} @@ -28,6 +28,7 @@ jobs: echo "TURN_SERVER_NAME=${{ secrets.TURN_SERVER_NAME }}" >> .env echo "TURN_SERVER_USER=${{ secrets.TURN_SERVER_USER }}" >> .env echo "TURN_SERVER_PASSWORD=${{ secrets.TURN_SERVER_PASSWORD }}" >> .env + echo "SENTRY_DSN=${{ secrets.SENTRY_DSN }}" >> .env mkdir -p config/nginx/ssl/ echo "${{ secrets.SSL_OPTIONS }}" > config/nginx/ssl/options-ssl-nginx.conf echo "${{ secrets.SSL_FULLCHAIN }}" > config/nginx/ssl/fullchain.pem diff --git a/backend/docker-compose.blue.yml b/backend/docker-compose.blue.yml index 5b19dae6..ed84586c 100644 --- a/backend/docker-compose.blue.yml +++ b/backend/docker-compose.blue.yml @@ -18,6 +18,7 @@ services: - X_NCP_CLOVASTUDIO_API_KEY=${X_NCP_CLOVASTUDIO_API_KEY} - X_NCP_APIGW_API_KEY=${X_NCP_APIGW_API_KEY} - PORT=3000 + - SENTRY_DSN=${SENTRY_DSN} expose: - "3000" volumes: diff --git a/backend/docker-compose.green.yml b/backend/docker-compose.green.yml index 2e091730..0c2f9889 100644 --- a/backend/docker-compose.green.yml +++ b/backend/docker-compose.green.yml @@ -18,6 +18,7 @@ services: - X_NCP_CLOVASTUDIO_API_KEY=${X_NCP_CLOVASTUDIO_API_KEY} - X_NCP_APIGW_API_KEY=${X_NCP_APIGW_API_KEY} - PORT=3002 + - SENTRY_DSN=${SENTRY_DSN} expose: - "3002" volumes: From c7d24f1e9cac7d6c3297d2d9228a5f34c0d01531 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sat, 9 Dec 2023 19:30:21 +0900 Subject: [PATCH 18/67] =?UTF-8?q?remove:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=9A=A9=20=EB=B8=8C=EB=9E=9C=EC=B9=98=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/blue-green-cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/blue-green-cd.yml b/.github/workflows/blue-green-cd.yml index 9939931a..f5562e44 100644 --- a/.github/workflows/blue-green-cd.yml +++ b/.github/workflows/blue-green-cd.yml @@ -2,7 +2,7 @@ name: Blue/Green CD on: push: - branches: ["dev", "BE/refactor/#419-sentry"] + branches: ["dev"] env: DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} From 215b0f4b561d01cfb84600580d1936808ce197aa Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sat, 9 Dec 2023 19:31:00 +0900 Subject: [PATCH 19/67] =?UTF-8?q?refactor:=20=EB=B0=B0=ED=8F=AC=20?= =?UTF-8?q?=EB=94=94=EB=B2=84=EA=B9=85=20=EB=A1=9C=EA=B7=B8=20=ED=98=95?= =?UTF-8?q?=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/deploy.sh b/backend/deploy.sh index 9e58c2b3..15b125d6 100644 --- a/backend/deploy.sh +++ b/backend/deploy.sh @@ -9,7 +9,7 @@ run_docker() { DOCKER_COMPOSE_FILE="docker-compose.$RUN_TARGET.yml" - echo "<<< Run docker compose : $DOCKER_COMPOSE_FILE" >> $DEBUG_LOG + echo "<<< Run docker compose : $DOCKER_COMPOSE_FILE" > $DEBUG_LOG docker-compose -f "$DOCKER_COMPOSE_FILE" pull docker-compose -f "$DOCKER_COMPOSE_FILE" up -d From 826c35666f793934afc1fae0f4118cb249d51573 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sat, 9 Dec 2023 19:32:11 +0900 Subject: [PATCH 20/67] =?UTF-8?q?feat:=20QueryFailedError=20=EB=B0=9C?= =?UTF-8?q?=EC=83=9D=20=EC=8B=9C=20=EC=95=8C=EB=A6=BC=20=EC=B2=98=EB=A6=AC?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Sentry.captureException() : Sentry์— ์˜ˆ์™ธ ๊ธฐ๋ก - slackWebhook.send() : ์Šฌ๋ž™ ์•Œ๋ฆผ ์ „์†ก --- .../common/interceptors/errors.interceptor.ts | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/backend/was/src/common/interceptors/errors.interceptor.ts b/backend/was/src/common/interceptors/errors.interceptor.ts index f519fe04..d27daba6 100644 --- a/backend/was/src/common/interceptors/errors.interceptor.ts +++ b/backend/was/src/common/interceptors/errors.interceptor.ts @@ -4,6 +4,9 @@ import { Injectable, NestInterceptor, } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import * as Sentry from '@sentry/node'; +import { IncomingWebhook } from '@slack/client'; import { Observable, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; import { LoggerService } from 'src/logger/logger.service'; @@ -12,7 +15,16 @@ import { ERR_MSG } from '../constants/errors'; @Injectable() export class ErrorsInterceptor implements NestInterceptor { - constructor(private readonly logger: LoggerService) {} + private readonly slackWebhook: IncomingWebhook; + + constructor( + private readonly logger: LoggerService, + private readonly configService: ConfigService, + ) { + this.slackWebhook = new IncomingWebhook( + this.configService.get('SLACK_WEBHOOK_FOR_BE') || '', + ); + } intercept(context: ExecutionContext, next: CallHandler): Observable { const controllerName: string = context.getClass().name; @@ -46,6 +58,8 @@ export class ErrorsInterceptor implements NestInterceptor { err: QueryFailedError, logMessage: string, ): Error { + this.sendSlackNotification(err); + const isFatal: boolean = err.message.includes('ETIMEOUT'); this.logQueryFailedError(logMessage, isFatal, err.stack); @@ -78,4 +92,24 @@ export class ErrorsInterceptor implements NestInterceptor { private makeErrorLogMessage(logMessage: string, err: any): string { return `${logMessage} : ${err.message || ERR_MSG.UNKNOWN}`; } + + private sendSlackNotification(err: QueryFailedError) { + Sentry.captureException(err); + this.slackWebhook.send({ + attachments: [ + { + color: 'danger', + text: '๐Ÿ“ข QueryFailedError ๋ฒ„๊ทธ ๋ฐœ์ƒ', + fields: [ + { + title: `Error Message: ${err.message}`, + value: err.stack || '', + short: false, + }, + ], + ts: Math.floor(new Date().getTime() / 1000).toString(), + }, + ], + }); + } } From bc7700563ad772b565196b8f8088e017152d3b1b Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sat, 9 Dec 2023 19:32:35 +0900 Subject: [PATCH 21/67] =?UTF-8?q?chore:=20slack=20webhook=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/was/package-lock.json | 486 +++++++++++++++++++++++++++++++++- backend/was/package.json | 3 +- 2 files changed, 478 insertions(+), 11 deletions(-) diff --git a/backend/was/package-lock.json b/backend/was/package-lock.json index a658fd60..501409d2 100644 --- a/backend/was/package-lock.json +++ b/backend/was/package-lock.json @@ -18,9 +18,10 @@ "@nestjs/swagger": "^7.1.15", "@nestjs/typeorm": "^10.0.0", "@nestjs/websockets": "^10.2.8", - "@tarotmilktea/ai-socketio-event": "^2.0.3", "@sentry/node": "^7.85.0", "@sentry/profiling-node": "^1.2.6", + "@slack/client": "^5.0.2", + "@tarotmilktea/ai-socketio-event": "^2.0.3", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "cookie-parser": "^1.4.6", @@ -2429,6 +2430,149 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@slack/client": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@slack/client/-/client-5.0.2.tgz", + "integrity": "sha512-HurKTUBZlwj/1cnZ6QOHpYR7k+G62WlL+13DgYD7onVRnQWggkIyCg+ymX1kQn6txzNdUyDEaixyCvBvmhH8tQ==", + "deprecated": "Slack Client is deprecated - Use @slack/web-api, @slack/rtm-api, or @slack/webhook instead.", + "dependencies": { + "@slack/logger": "^1.0.0", + "@slack/rtm-api": "^5.0.2", + "@slack/types": "^1.1.0", + "@slack/web-api": "^5.1.0", + "@slack/webhook": "^5.0.1" + }, + "engines": { + "node": ">= 8.9.0", + "npm": ">= 5.5.1" + } + }, + "node_modules/@slack/logger": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@slack/logger/-/logger-1.1.1.tgz", + "integrity": "sha512-PAC5CMnNAv/FPtJ0le+YD2wUV+tZ7n3Bnjj9dBI+deIcHsExCnQkQmZE79cLvfuYXbz3PWyv5coti30MJQhEjA==", + "dependencies": { + "@types/node": ">=8.9.0" + }, + "engines": { + "node": ">= 8.9.0", + "npm": ">= 5.5.1" + } + }, + "node_modules/@slack/rtm-api": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@slack/rtm-api/-/rtm-api-5.0.5.tgz", + "integrity": "sha512-x2B4hyoxjg62cxf4M5QRomx+xYp2XoajPKdd24SM2Sl4m+IrzwKzmcrysQuYmF6BMsm3IoTKymW5BBGckHGTIw==", + "dependencies": { + "@slack/logger": ">=1.0.0 <3.0.0", + "@slack/web-api": "^5.3.0", + "@types/node": ">=8.9.0", + "@types/p-queue": "^2.3.2", + "@types/ws": "^7.2.5", + "eventemitter3": "^3.1.0", + "finity": "^0.5.4", + "p-cancelable": "^1.1.0", + "p-queue": "^2.4.2", + "ws": "^5.2.0" + }, + "engines": { + "node": ">= 8.9.0", + "npm": ">= 5.5.1" + } + }, + "node_modules/@slack/rtm-api/node_modules/ws": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.3.tgz", + "integrity": "sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA==", + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/@slack/types": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@slack/types/-/types-1.10.0.tgz", + "integrity": "sha512-tA7GG7Tj479vojfV3AoxbckalA48aK6giGjNtgH6ihpLwTyHE3fIgRrvt8TWfLwW8X8dyu7vgmAsGLRG7hWWOg==", + "engines": { + "node": ">= 8.9.0", + "npm": ">= 5.5.1" + } + }, + "node_modules/@slack/web-api": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@slack/web-api/-/web-api-5.15.0.tgz", + "integrity": "sha512-tjQ8Zqv/Fmj9SOL9yIEd7IpTiKfKHi9DKAkfRVeotoX0clMr3SqQtBqO+KZMX27gm7dmgJsQaDKlILyzdCO+IA==", + "dependencies": { + "@slack/logger": ">=1.0.0 <3.0.0", + "@slack/types": "^1.7.0", + "@types/is-stream": "^1.1.0", + "@types/node": ">=8.9.0", + "axios": "^0.21.1", + "eventemitter3": "^3.1.0", + "form-data": "^2.5.0", + "is-stream": "^1.1.0", + "p-queue": "^6.6.1", + "p-retry": "^4.0.0" + }, + "engines": { + "node": ">= 8.9.0", + "npm": ">= 5.5.1" + } + }, + "node_modules/@slack/web-api/node_modules/form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/@slack/web-api/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@slack/web-api/node_modules/p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "dependencies": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@slack/web-api/node_modules/p-queue/node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/@slack/webhook": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@slack/webhook/-/webhook-5.0.4.tgz", + "integrity": "sha512-IC1dpVSc2F/pmwCxOb0QzH2xnGKmyT7MofPGhNkeaoiMrLMU+Oc7xV/AxGnz40mURtCtaDchZSM3tDo9c9x6BA==", + "dependencies": { + "@slack/types": "^1.2.1", + "@types/node": ">=8.9.0", + "axios": "^0.21.1" + }, + "engines": { + "node": ">= 8.9.0", + "npm": ">= 5.5.1" + } + }, "node_modules/@socket.io/component-emitter": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", @@ -2680,6 +2824,14 @@ "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", "dev": true }, + "node_modules/@types/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-jkZatu4QVbR60mpIzjINmtS1ZF4a/FqdTUTBeQDVOQ2PYyidtwFKr0B5G6ERukKwliq+7mIXvxyppwzG5EgRYg==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -2741,6 +2893,11 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/p-queue": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@types/p-queue/-/p-queue-2.3.2.tgz", + "integrity": "sha512-eKAv5Ql6k78dh3ULCsSBxX6bFNuGjTmof5Q/T6PiECDq0Yf8IIn46jCyp3RJvCi8owaEmm3DZH1PEImjBMd/vQ==" + }, "node_modules/@types/qs": { "version": "6.9.10", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", @@ -2753,6 +2910,11 @@ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", "dev": true }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, "node_modules/@types/semver": { "version": "7.5.6", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", @@ -2831,6 +2993,14 @@ "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.7.tgz", "integrity": "sha512-q0JomTsJ2I5Mv7dhHhQLGjMvX0JJm5dyZ1DXQySIUzU1UlwzB8bt+R6+LODUbz0UDIOvEzGc28tk27gBJw2N8Q==" }, + "node_modules/@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/yargs": { "version": "17.0.32", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", @@ -3583,11 +3753,15 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/available-typed-arrays": { "version": "1.0.5", @@ -3601,6 +3775,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -4540,7 +4722,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -5025,7 +5206,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -5872,6 +6052,11 @@ "node": ">= 0.6" } }, + "node_modules/eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" + }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -6228,6 +6413,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/finity": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/finity/-/finity-0.5.4.tgz", + "integrity": "sha512-3l+5/1tuw616Lgb0QBimxfdd2TqaDGpfCBpfX6EqtFmqUV3FtQnVEX4Aa62DagYEqnsTIjZcTfbq9msDbXYgyA==" + }, "node_modules/flat-cache": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", @@ -6288,6 +6478,25 @@ "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -9346,6 +9555,22 @@ "node": ">=0.10.0" } }, + "node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "engines": { + "node": ">=4" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -9390,6 +9615,45 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-queue": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-2.4.2.tgz", + "integrity": "sha512-n8/y+yDJwBjoLQe1GSJbbaYQLTI7QHNZI2+rpmCDbe++WLf9HC3gf6iqj5yfPAV71W4UF3ql5W1+UBPXoXTxng==", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "dependencies": { + "p-finally": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -14123,6 +14387,118 @@ "@sinonjs/commons": "^3.0.0" } }, + "@slack/client": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@slack/client/-/client-5.0.2.tgz", + "integrity": "sha512-HurKTUBZlwj/1cnZ6QOHpYR7k+G62WlL+13DgYD7onVRnQWggkIyCg+ymX1kQn6txzNdUyDEaixyCvBvmhH8tQ==", + "requires": { + "@slack/logger": "^1.0.0", + "@slack/rtm-api": "^5.0.2", + "@slack/types": "^1.1.0", + "@slack/web-api": "^5.1.0", + "@slack/webhook": "^5.0.1" + } + }, + "@slack/logger": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@slack/logger/-/logger-1.1.1.tgz", + "integrity": "sha512-PAC5CMnNAv/FPtJ0le+YD2wUV+tZ7n3Bnjj9dBI+deIcHsExCnQkQmZE79cLvfuYXbz3PWyv5coti30MJQhEjA==", + "requires": { + "@types/node": ">=8.9.0" + } + }, + "@slack/rtm-api": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@slack/rtm-api/-/rtm-api-5.0.5.tgz", + "integrity": "sha512-x2B4hyoxjg62cxf4M5QRomx+xYp2XoajPKdd24SM2Sl4m+IrzwKzmcrysQuYmF6BMsm3IoTKymW5BBGckHGTIw==", + "requires": { + "@slack/logger": ">=1.0.0 <3.0.0", + "@slack/web-api": "^5.3.0", + "@types/node": ">=8.9.0", + "@types/p-queue": "^2.3.2", + "@types/ws": "^7.2.5", + "eventemitter3": "^3.1.0", + "finity": "^0.5.4", + "p-cancelable": "^1.1.0", + "p-queue": "^2.4.2", + "ws": "^5.2.0" + }, + "dependencies": { + "ws": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.3.tgz", + "integrity": "sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA==", + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "@slack/types": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@slack/types/-/types-1.10.0.tgz", + "integrity": "sha512-tA7GG7Tj479vojfV3AoxbckalA48aK6giGjNtgH6ihpLwTyHE3fIgRrvt8TWfLwW8X8dyu7vgmAsGLRG7hWWOg==" + }, + "@slack/web-api": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@slack/web-api/-/web-api-5.15.0.tgz", + "integrity": "sha512-tjQ8Zqv/Fmj9SOL9yIEd7IpTiKfKHi9DKAkfRVeotoX0clMr3SqQtBqO+KZMX27gm7dmgJsQaDKlILyzdCO+IA==", + "requires": { + "@slack/logger": ">=1.0.0 <3.0.0", + "@slack/types": "^1.7.0", + "@types/is-stream": "^1.1.0", + "@types/node": ">=8.9.0", + "axios": "^0.21.1", + "eventemitter3": "^3.1.0", + "form-data": "^2.5.0", + "is-stream": "^1.1.0", + "p-queue": "^6.6.1", + "p-retry": "^4.0.0" + }, + "dependencies": { + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==" + }, + "p-queue": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz", + "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==", + "requires": { + "eventemitter3": "^4.0.4", + "p-timeout": "^3.2.0" + }, + "dependencies": { + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + } + } + } + } + }, + "@slack/webhook": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@slack/webhook/-/webhook-5.0.4.tgz", + "integrity": "sha512-IC1dpVSc2F/pmwCxOb0QzH2xnGKmyT7MofPGhNkeaoiMrLMU+Oc7xV/AxGnz40mURtCtaDchZSM3tDo9c9x6BA==", + "requires": { + "@slack/types": "^1.2.1", + "@types/node": ">=8.9.0", + "axios": "^0.21.1" + } + }, "@socket.io/component-emitter": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", @@ -14360,6 +14736,14 @@ "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", "dev": true }, + "@types/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-jkZatu4QVbR60mpIzjINmtS1ZF4a/FqdTUTBeQDVOQ2PYyidtwFKr0B5G6ERukKwliq+7mIXvxyppwzG5EgRYg==", + "requires": { + "@types/node": "*" + } + }, "@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -14421,6 +14805,11 @@ "undici-types": "~5.26.4" } }, + "@types/p-queue": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@types/p-queue/-/p-queue-2.3.2.tgz", + "integrity": "sha512-eKAv5Ql6k78dh3ULCsSBxX6bFNuGjTmof5Q/T6PiECDq0Yf8IIn46jCyp3RJvCi8owaEmm3DZH1PEImjBMd/vQ==" + }, "@types/qs": { "version": "6.9.10", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.10.tgz", @@ -14433,6 +14822,11 @@ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", "dev": true }, + "@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, "@types/semver": { "version": "7.5.6", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", @@ -14510,6 +14904,14 @@ "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.7.tgz", "integrity": "sha512-q0JomTsJ2I5Mv7dhHhQLGjMvX0JJm5dyZ1DXQySIUzU1UlwzB8bt+R6+LODUbz0UDIOvEzGc28tk27gBJw2N8Q==" }, + "@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "requires": { + "@types/node": "*" + } + }, "@types/yargs": { "version": "17.0.32", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", @@ -15072,11 +15474,15 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "available-typed-arrays": { "version": "1.0.5", @@ -15084,6 +15490,14 @@ "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", "dev": true }, + "axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "requires": { + "follow-redirects": "^1.14.0" + } + }, "babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -15769,7 +16183,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -16102,8 +16515,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, "delegates": { "version": "1.0.0", @@ -16740,6 +17152,11 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, + "eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" + }, "events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -17046,6 +17463,11 @@ "path-exists": "^4.0.0" } }, + "finity": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/finity/-/finity-0.5.4.tgz", + "integrity": "sha512-3l+5/1tuw616Lgb0QBimxfdd2TqaDGpfCBpfX6EqtFmqUV3FtQnVEX4Aa62DagYEqnsTIjZcTfbq9msDbXYgyA==" + }, "flat-cache": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", @@ -17093,6 +17515,11 @@ "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, + "follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==" + }, "for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -19363,6 +19790,16 @@ "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==" + }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -19389,6 +19826,35 @@ "aggregate-error": "^3.0.0" } }, + "p-queue": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-2.4.2.tgz", + "integrity": "sha512-n8/y+yDJwBjoLQe1GSJbbaYQLTI7QHNZI2+rpmCDbe++WLf9HC3gf6iqj5yfPAV71W4UF3ql5W1+UBPXoXTxng==" + }, + "p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "requires": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "dependencies": { + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" + } + } + }, + "p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "requires": { + "p-finally": "^1.0.0" + } + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", diff --git a/backend/was/package.json b/backend/was/package.json index 876fa9e3..b07a1ff5 100644 --- a/backend/was/package.json +++ b/backend/was/package.json @@ -29,9 +29,10 @@ "@nestjs/swagger": "^7.1.15", "@nestjs/typeorm": "^10.0.0", "@nestjs/websockets": "^10.2.8", - "@tarotmilktea/ai-socketio-event": "^2.0.3", "@sentry/node": "^7.85.0", "@sentry/profiling-node": "^1.2.6", + "@slack/client": "^5.0.2", + "@tarotmilktea/ai-socketio-event": "^2.0.3", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "cookie-parser": "^1.4.6", From 4ab6c4253effe47f17b4172e8ca5bf1bb8eb8f02 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sat, 9 Dec 2023 23:38:48 +0900 Subject: [PATCH 22/67] =?UTF-8?q?fix:=20nginx=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - nginx๋Š” TCP, HTTP ๊ธฐ๋ฐ˜ ์„œ๋ฒ„์ด๋ฏ€๋กœ UDP ๊ธฐ๋ฐ˜์˜ STUN ์„œ๋ฒ„๋กœ๋Š” ์ ํ•ฉํ•˜์ง€ ์•Š์Œ - ํ˜ธ์ŠคํŠธ ์„œ๋ฒ„์—์„œ ์ง์ ‘ coturn์„ ์‚ฌ์šฉํ•˜๋„๋ก ์ˆ˜์ • --- backend/config/nginx/default.conf | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/backend/config/nginx/default.conf b/backend/config/nginx/default.conf index d69adef9..acc382c9 100644 --- a/backend/config/nginx/default.conf +++ b/backend/config/nginx/default.conf @@ -7,20 +7,6 @@ server { root /var/www/certbot; } - location /turn { - proxy_pass http://coturn-server:3478; - proxy_redirect default; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-Host $server_name; - - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - } - location /signal { proxy_pass http://signal-blue:3001; proxy_redirect default; @@ -62,20 +48,6 @@ server { include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; - location /turn { - proxy_pass http://coturn-server:3478; - proxy_redirect default; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-Host $server_name; - - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - } - location /signal { proxy_pass http://signal-blue:3001; proxy_redirect default; From 546bd7b27b137b59ae5acb3396953b5ab5834a92 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sat, 9 Dec 2023 23:42:47 +0900 Subject: [PATCH 23/67] =?UTF-8?q?fix:=20docker-compose=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - nginx๋กœ ํ”„๋ก์‹œ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅ ํ•˜๋ฏ€๋กœ coturn์„ ํ˜ธ์ŠคํŠธ ์„œ๋ฒ„์—์„œ ๋„์šฐ๊ธฐ๋กœ ๊ฒฐ์ • - coturn-server ์ด๋ฏธ์ง€ ์ œ๊ฑฐ --- backend/docker-compose.blue.yml | 11 ----------- backend/docker-compose.green.yml | 11 ----------- 2 files changed, 22 deletions(-) diff --git a/backend/docker-compose.blue.yml b/backend/docker-compose.blue.yml index ed84586c..e3d73bd3 100644 --- a/backend/docker-compose.blue.yml +++ b/backend/docker-compose.blue.yml @@ -36,16 +36,6 @@ services: expose: - "3001" - coturn-server: - image: "coturn/coturn" - container_name: "coturn-server" - environment: - - TURN_SERVER_NAME=${TURN_SERVER_NAME} - - TURN_SERVER_USER=${TURN_SERVER_USER} - - TURN_SERVER_PASSWORD=${TURN_SERVER_PASSWORD} - expose: - - "3478" - nginx: container_name: "nginx-reverse-proxy" build: @@ -57,7 +47,6 @@ services: depends_on: - was-blue - signal-blue - - coturn-server - certbot volumes: - /var/log/nginx:/var/log/nginx diff --git a/backend/docker-compose.green.yml b/backend/docker-compose.green.yml index 0c2f9889..4c3cfa32 100644 --- a/backend/docker-compose.green.yml +++ b/backend/docker-compose.green.yml @@ -36,16 +36,6 @@ services: expose: - "3003" - coturn-server: - image: "coturn/coturn" - container_name: "coturn-server" - environment: - - TURN_SERVER_NAME=${TURN_SERVER_NAME} - - TURN_SERVER_USER=${TURN_SERVER_USER} - - TURN_SERVER_PASSWORD=${TURN_SERVER_PASSWORD} - expose: - - "3478" - nginx: container_name: "nginx-reverse-proxy" build: @@ -57,7 +47,6 @@ services: depends_on: - was-green - signal-green - - coturn-server - certbot volumes: - /var/log/nginx:/var/log/nginx From 4a8db1cf4a3c4213e2fd0d2215df41464097c722 Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Sun, 10 Dec 2023 13:43:08 +0900 Subject: [PATCH 24/67] =?UTF-8?q?refactor:=20dataChannel=EC=9D=84=20WebRTC?= =?UTF-8?q?=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=95=88=EC=AA=BD=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=84=A3=EC=9D=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์œผ๋กœ ๋˜์–ด์žˆ๋Š” ๊ฐ์ฒด์—์„œ ์‚ฌ์šฉํ•˜๋ฉด๋จ --- .../useChatMessage/useHumanChatMessage.ts | 14 ++--- .../useTarotSpread/useHumanTarotSpread.tsx | 21 +++---- .../hooks/useWebRTC/useDataChannel.ts | 63 ++++++------------- .../hooks/useWebRTC/useRTCPeerConnection.ts | 25 +++++--- .../src/pages/HumanChatPage/HumanChatPage.tsx | 8 ++- .../useSettingPageProfileNicknameSetting.ts | 25 ++++---- 6 files changed, 68 insertions(+), 88 deletions(-) diff --git a/frontend/src/business/hooks/useChatMessage/useHumanChatMessage.ts b/frontend/src/business/hooks/useChatMessage/useHumanChatMessage.ts index f51b4f29..1b2d45c5 100644 --- a/frontend/src/business/hooks/useChatMessage/useHumanChatMessage.ts +++ b/frontend/src/business/hooks/useChatMessage/useHumanChatMessage.ts @@ -12,7 +12,7 @@ import useChatMessage from './useChatMessage'; const { PICK_CARD, CHAT_MESSAGE } = HumanChatEvents; -export function useHumanChatMessage(chatChannel: React.MutableRefObject) { +export function useHumanChatMessage(chatChannel: RTCDataChannel | undefined) { const { messages, pushMessage } = useChatMessage(); const [inputDisabled, setInputDisabled] = useState(true); @@ -48,20 +48,20 @@ export function useHumanChatMessage(chatChannel: React.MutableRefObject { - if (chatChannel.current) { - chatChannel.current.addEventListener('open', () => { + if (chatChannel) { + chatChannel.addEventListener('open', () => { setInputDisabled(false); }); - chatChannel.current.addEventListener('close', () => { + chatChannel.addEventListener('close', () => { setInputDisabled(true); }); - chatChannel.current.addEventListener('message', event => { + chatChannel.addEventListener('message', event => { const message = JSON.parse(event.data); if (message.type === CHAT_MESSAGE) { @@ -72,7 +72,7 @@ export function useHumanChatMessage(chatChannel: React.MutableRefObject { addMessage('left', { tarotId }); diff --git a/frontend/src/business/hooks/useTarotSpread/useHumanTarotSpread.tsx b/frontend/src/business/hooks/useTarotSpread/useHumanTarotSpread.tsx index 9ca09b02..0cd5a447 100644 --- a/frontend/src/business/hooks/useTarotSpread/useHumanTarotSpread.tsx +++ b/frontend/src/business/hooks/useTarotSpread/useHumanTarotSpread.tsx @@ -12,15 +12,12 @@ import { useTarotSpread } from './useTarotSpread'; const { PICK_CARD, TAROT_SPREAD } = HumanChatEvents; -export function useHumanTarotSpread( - chatChannel: React.MutableRefObject, - onPickCard: (idx: number) => void, -) { +export function useHumanTarotSpread(chatChannel: RTCDataChannel | undefined, onPickCard: (idx: number) => void) { const [tarotButtonDisabled, setTarotButtonDisabled] = useState(true); const pickCard = (idx: number) => { const payload = { type: PICK_CARD, content: idx }; - chatChannel.current?.send(JSON.stringify(payload)); + chatChannel?.send(JSON.stringify(payload)); onPickCard(idx); }; @@ -46,22 +43,20 @@ export function useHumanTarotSpread( const requestTarotSpread = () => { setTarotButtonDisabled(true); const payload = { type: TAROT_SPREAD }; - chatChannel.current?.send(JSON.stringify(payload)); + chatChannel?.send(JSON.stringify(payload)); }; useEffect(() => { - if (chatChannel.current) { - chatChannel.current.addEventListener('open', () => { - console.log('datachannel open'); + if (chatChannel) { + chatChannel.addEventListener('open', () => { setTarotButtonDisabled(false); }); - chatChannel.current.addEventListener('close', () => { - console.log('datachannel close'); + chatChannel.addEventListener('close', () => { setTarotButtonDisabled(true); }); - chatChannel.current.addEventListener('message', event => { + chatChannel.addEventListener('message', event => { const message = JSON.parse(event.data); if (message.type === TAROT_SPREAD) { @@ -73,7 +68,7 @@ export function useHumanTarotSpread( } }); } - }, [chatChannel.current]); + }, [chatChannel]); return { tarotButtonClick, tarotButtonDisabled }; } diff --git a/frontend/src/business/hooks/useWebRTC/useDataChannel.ts b/frontend/src/business/hooks/useWebRTC/useDataChannel.ts index 5afeb1f8..5ac03fa5 100644 --- a/frontend/src/business/hooks/useWebRTC/useDataChannel.ts +++ b/frontend/src/business/hooks/useWebRTC/useDataChannel.ts @@ -1,14 +1,11 @@ -import { useRef } from 'react'; - import { useMediaInfo } from '@stores/zustandStores/useMediaInfo'; import { useProfileInfo } from '@stores/zustandStores/useProfileInfo'; import { array2ArrayBuffer } from '@utils/array'; -interface useDataChannelParams { - peerConnectionRef: React.MutableRefObject; -} -export function useDataChannel({ peerConnectionRef }: useDataChannelParams) { +import WebRTC from './WebRTC'; + +export function useDataChannel() { const { myMicOn, myVideoOn, setRemoteMicOn, setRemoteVideoOn } = useMediaInfo(state => ({ myMicOn: state.myMicOn, myVideoOn: state.myVideoOn, @@ -22,18 +19,12 @@ export function useDataChannel({ peerConnectionRef }: useDataChannelParams) { myProfile: state.myProfile, })); - const mediaInfoChannel = useRef(); - const chatChannel = useRef(); - const profileChannel = useRef(); - const nicknameChannel = useRef(); + const { addDataChannel } = WebRTC.getInstace(); const initMediaInfoChannel = () => { - mediaInfoChannel.current = peerConnectionRef.current?.createDataChannel('mediaInfoChannel', { - negotiated: true, - id: 0, - }); + const mediaInfoChannel = addDataChannel('mediaInfoChannel'); - mediaInfoChannel.current?.addEventListener('message', ({ data }) => { + mediaInfoChannel?.addEventListener('message', ({ data }) => { const mediaInfoArray = JSON.parse(data); mediaInfoArray.forEach(({ type, onOrOff }: { type: string; onOrOff: boolean }) => { @@ -45,8 +36,8 @@ export function useDataChannel({ peerConnectionRef }: useDataChannelParams) { }); }); - mediaInfoChannel.current?.addEventListener('open', () => { - mediaInfoChannel.current?.send( + mediaInfoChannel?.addEventListener('open', function () { + this.send( JSON.stringify([ { type: 'audio', onOrOff: myMicOn }, { type: 'video', onOrOff: myVideoOn }, @@ -56,23 +47,13 @@ export function useDataChannel({ peerConnectionRef }: useDataChannelParams) { }; const initChatChannel = () => { - chatChannel.current = peerConnectionRef.current?.createDataChannel('chat', { - negotiated: true, - id: 1, - }); + addDataChannel('chatChannel'); }; const initProfileChannel = () => { - profileChannel.current = peerConnectionRef.current?.createDataChannel('profile', { - negotiated: true, - id: 2, - }); - - if (!profileChannel.current) { - return; - } + const profileChannel = addDataChannel('profileChannel'); - profileChannel.current.addEventListener('message', ({ data }) => { + profileChannel?.addEventListener('message', ({ data }) => { const receivedData = JSON.parse(data); const { type, arrayBuffer: array } = receivedData; @@ -82,26 +63,23 @@ export function useDataChannel({ peerConnectionRef }: useDataChannelParams) { setRemoteProfileImage({ arrayBuffer, type }); }); - profileChannel.current?.addEventListener('open', () => { - profileChannel.current?.send?.(JSON.stringify({ myProfile })); + profileChannel?.addEventListener('open', function () { + this.send(JSON.stringify({ myProfile })); }); }; const initNicknameChannel = () => { - nicknameChannel.current = peerConnectionRef.current?.createDataChannel('nickname', { - negotiated: true, - id: 3, - }); + const nicknameChannel = addDataChannel('nicknameChannel'); - nicknameChannel.current?.addEventListener('message', ({ data }) => { + nicknameChannel?.addEventListener('message', ({ data }) => { setRemoteNickname(data); }); - nicknameChannel.current?.addEventListener('open', () => { + nicknameChannel?.addEventListener('open', function () { if (!myNickname) { return; } - nicknameChannel.current?.send?.(myNickname); + this.send(myNickname); }); }; @@ -112,10 +90,5 @@ export function useDataChannel({ peerConnectionRef }: useDataChannelParams) { initNicknameChannel(); }; - const closeDataChannels = () => { - mediaInfoChannel.current?.close(); - chatChannel.current?.close(); - }; - - return { mediaInfoChannel, chatChannel, profileChannel, nicknameChannel, initDataChannels, closeDataChannels }; + return { initDataChannels }; } diff --git a/frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts b/frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts index a6e4ea61..e31100d9 100644 --- a/frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts +++ b/frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts @@ -1,4 +1,4 @@ -import { useEffect } from 'react'; +import { useEffect, useRef } from 'react'; import { HumanSocketManager } from '@business/services/SocketManager'; @@ -10,14 +10,18 @@ interface useRTCPeerConnectionParams { export function useRTCPeerConnection({ remoteVideoRef }: useRTCPeerConnectionParams) { const socketManager = new HumanSocketManager(); + const remoteStreamRef = useRef(); - const webRTC = WebRTC.getInstace(); + const { addRTCPeerConnectionEventListener, connectRTCPeerConnection, setRemoteStream, remoteStream } = + WebRTC.getInstace(); - const makeRTCPeerConnection = async ({ roomName }: { roomName: string }) => { - webRTC.connectRTCPeerConnection(); + const makeRTCPeerConnection = ({ roomName }: { roomName: string }) => { + connectRTCPeerConnection(); + + addRTCPeerConnectionEventListener('track', e => { + setRemoteStream(e.streams[0]); + console.log(remoteVideoRef.current, remoteVideoRef); - webRTC.addRTCPeerConnectionEventListener('track', e => { - webRTC.setRemoteStream(e.streams[0]); if (!remoteVideoRef.current) { return; } @@ -25,7 +29,7 @@ export function useRTCPeerConnection({ remoteVideoRef }: useRTCPeerConnectionPar remoteVideoRef.current.srcObject = e.streams[0]; }); - webRTC.addRTCPeerConnectionEventListener('icecandidate', e => { + addRTCPeerConnectionEventListener('icecandidate', e => { if (!e.candidate) { return; } @@ -35,12 +39,13 @@ export function useRTCPeerConnection({ remoteVideoRef }: useRTCPeerConnectionPar }; useEffect(() => { - if (!remoteVideoRef.current || !webRTC.remoteStream) { + if (!remoteVideoRef.current || !remoteStreamRef.current) { return; } + console.log('chanred'); - remoteVideoRef.current.srcObject = webRTC.remoteStream; - }, [remoteVideoRef.current]); + remoteVideoRef.current.srcObject = remoteStreamRef.current; + }, [remoteVideoRef]); return { makeRTCPeerConnection }; } diff --git a/frontend/src/pages/HumanChatPage/HumanChatPage.tsx b/frontend/src/pages/HumanChatPage/HumanChatPage.tsx index e29dad42..12206aed 100644 --- a/frontend/src/pages/HumanChatPage/HumanChatPage.tsx +++ b/frontend/src/pages/HumanChatPage/HumanChatPage.tsx @@ -10,6 +10,7 @@ import { useBlocker } from '@business/hooks/useBlocker'; import { useHumanChatMessage } from '@business/hooks/useChatMessage'; import { useHumanTarotSpread } from '@business/hooks/useTarotSpread'; import useWebRTC from '@business/hooks/useWebRTC'; +import WebRTC from '@business/hooks/useWebRTC/WebRTC'; import { useHumanChatPageContentAnimation } from './useHumanChatPageContentAnimation'; import { ChatPageState, useHumanChatPageCreateRoomEvent } from './useHumanChatPageCreateRoomEvent'; @@ -31,8 +32,11 @@ export default function HumanChatPage() { useHumanChatPageWrongURL(); const { chatPageState, setChatPageState } = useHumanChatPageCreateRoomEvent(); - const { messages, onSubmitMessage, inputDisabled, addPickCardMessage } = useHumanChatMessage(webRTCData.chatChannel); - const { tarotButtonClick, tarotButtonDisabled } = useHumanTarotSpread(webRTCData.chatChannel, addPickCardMessage); + const { dataChannels } = WebRTC.getInstace(); + const chatDataChannel = dataChannels.get('chatChannel'); + + const { messages, onSubmitMessage, inputDisabled, addPickCardMessage } = useHumanChatMessage(chatDataChannel); + const { tarotButtonClick, tarotButtonDisabled } = useHumanTarotSpread(chatDataChannel, addPickCardMessage); const { changeContentAnimation, contentAnimation } = useHumanChatPageContentAnimation(); const [sideBarDisabled, setSideBarDisabled] = useState(false); diff --git a/frontend/src/pages/HumanChatPage/useSettingPageProfileNicknameSetting.ts b/frontend/src/pages/HumanChatPage/useSettingPageProfileNicknameSetting.ts index 92d6ae2d..b42ad4cb 100644 --- a/frontend/src/pages/HumanChatPage/useSettingPageProfileNicknameSetting.ts +++ b/frontend/src/pages/HumanChatPage/useSettingPageProfileNicknameSetting.ts @@ -1,5 +1,7 @@ import { ChangeEvent } from 'react'; -import { useNavigate, useOutletContext } from 'react-router-dom'; +import { useOutletContext } from 'react-router-dom'; + +import WebRTC from '@business/hooks/useWebRTC/WebRTC'; import { useProfileInfo } from '@stores/zustandStores/useProfileInfo'; @@ -8,8 +10,11 @@ import { arrayBuffer2Array } from '@utils/array'; import { OutletContext } from './HumanChatPage'; export function useSettingPageProfileNicknameSetting() { - const { profileChannel, nicknameChannel, setChatPageState }: OutletContext = useOutletContext(); - const navigate = useNavigate(); + const { setChatPageState }: OutletContext = useOutletContext(); + + const { dataChannels } = WebRTC.getInstace(); + const profileChannel = dataChannels.get('profileChannel'); + const nicknameChannel = dataChannels.get('nicknameChannel'); const { myNickname, myProfile, setMyNickname, setMyProfileImage } = useProfileInfo(state => ({ setMyNickname: state.setMyNickname, @@ -33,22 +38,20 @@ export function useSettingPageProfileNicknameSetting() { setMyNickname(e.target.value); }; - const sendProfileInfoWithNavigateBefore = () => { - if (profileChannel.current?.readyState === 'open' && myProfile) { + const sendProfileInfo = () => { + if (profileChannel?.readyState === 'open' && myProfile) { const dataArray = arrayBuffer2Array(myProfile.arrayBuffer); const sendJson = JSON.stringify({ arrayBuffer: dataArray, type: myProfile.type }); - profileChannel.current?.send?.(sendJson); + profileChannel?.send?.(sendJson); } - if (nicknameChannel.current?.readyState === 'open' && myNickname) { - nicknameChannel.current?.send?.(myNickname); + if (nicknameChannel?.readyState === 'open' && myNickname) { + nicknameChannel?.send?.(myNickname); } setChatPageState(prev => ({ ...prev, joined: true })); - - navigate('..'); }; - return { setLocalProfileImage, setLocalNickname, sendProfileInfoWithNavigateBefore }; + return { setLocalProfileImage, setLocalNickname, sendProfileInfo }; } From 979dcc3f5f778741c39427d4cfa7f959b72356e0 Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Sun, 10 Dec 2023 13:43:48 +0900 Subject: [PATCH 25/67] =?UTF-8?q?refactor:=20useSignalingSocket=ED=9B=85?= =?UTF-8?q?=20=EC=B4=88=EA=B8=B0=ED=99=94=20=EB=B6=80=EB=B6=84=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ํ›… ์•ˆ์— ์žˆ์„ ํ•„์š” ์—†๊ณ , ๋ฐ–์—์„œ ์ดˆ๊ธฐํ™” ํ•ด์ค˜๋„ ์ถฉ๋ถ„ํ•จ --- .../hooks/useWebRTC/useSignalingSocket.ts | 52 +------------------ frontend/src/business/services/Socket.ts | 47 +++++++++++++++++ 2 files changed, 48 insertions(+), 51 deletions(-) create mode 100644 frontend/src/business/services/Socket.ts diff --git a/frontend/src/business/hooks/useWebRTC/useSignalingSocket.ts b/frontend/src/business/hooks/useWebRTC/useSignalingSocket.ts index a64a167d..5f590b79 100644 --- a/frontend/src/business/hooks/useWebRTC/useSignalingSocket.ts +++ b/frontend/src/business/hooks/useWebRTC/useSignalingSocket.ts @@ -1,59 +1,10 @@ import { usePasswordPopup } from '@business/hooks/usePopup'; import { HumanSocketManager } from '@business/services/SocketManager'; -import { ERROR_MESSAGE } from '@constants/messages'; - -interface useSignalingSocketParams { - peerConnectionRef: React.MutableRefObject; - negotiationDataChannels: ({ roomName }: { roomName: string }) => void; -} - -export function useSignalingSocket({ peerConnectionRef, negotiationDataChannels }: useSignalingSocketParams) { +export function useSignalingSocket() { const socketManager = new HumanSocketManager(); - const { openPasswordPopup } = usePasswordPopup(); - const initSignalingSocket = ({ roomName }: { roomName: string }) => { - socketManager.on('welcome', (users: { id: string }[]) => { - if (users.length > 0) { - createOffer({ roomName }); - } - }); - - socketManager.on('offer', (sdp: RTCSessionDescription) => { - createAnswer({ roomName, sdp }); - }); - - socketManager.on('answer', async (sdp: RTCSessionDescription) => { - await peerConnectionRef.current?.setRemoteDescription(sdp); - }); - - socketManager.on('candidate', async (candidate: RTCIceCandidate) => { - await peerConnectionRef.current?.addIceCandidate(candidate); - }); - - socketManager.on('roomFull', () => { - alert(ERROR_MESSAGE.FULL_ROOM); - }); - - socketManager.on('userExit', async () => { - negotiationDataChannels({ roomName }); - }); - }; - - const createOffer = async ({ roomName }: { roomName: string }) => { - const sdp = await peerConnectionRef.current?.createOffer(); - await peerConnectionRef.current?.setLocalDescription(sdp); - socketManager.emit('offer', sdp, roomName); - }; - - const createAnswer = async ({ roomName, sdp }: { roomName: string; sdp: RTCSessionDescription }) => { - await peerConnectionRef.current?.setRemoteDescription(sdp); - const answerSdp = await peerConnectionRef.current?.createAnswer(); - peerConnectionRef.current?.setLocalDescription(answerSdp); - socketManager.emit('answer', answerSdp, roomName); - }; - const createRoom = ({ roomName, onSuccess, @@ -126,7 +77,6 @@ export function useSignalingSocket({ peerConnectionRef, negotiationDataChannels }; return { - initSignalingSocket, createRoom, joinRoom, checkRoomExist, diff --git a/frontend/src/business/services/Socket.ts b/frontend/src/business/services/Socket.ts new file mode 100644 index 00000000..7a2049c3 --- /dev/null +++ b/frontend/src/business/services/Socket.ts @@ -0,0 +1,47 @@ +import WebRTC from '@business/hooks/useWebRTC/WebRTC'; + +import { ERROR_MESSAGE } from '@constants/messages'; + +import { HumanSocketManager } from './SocketManager'; + +const { addIceCandidate, createOffer, createAnswer, setLocalDescription, setRemoteDescription } = WebRTC.getInstace(); + +const socketManager = new HumanSocketManager(); + +interface initSignalingSocketParams { + roomName: string; + onNegotiationDataChannels: () => void; +} +export const initSignalingSocket = ({ roomName, onNegotiationDataChannels }: initSignalingSocketParams) => { + socketManager.on('welcome', async (users: { id: string }[]) => { + if (users.length === 0) { + return; + } + const sdp = await createOffer(); + await setLocalDescription(sdp); + socketManager.emit('offer', sdp, roomName); + }); + + socketManager.on('offer', async (sdp: RTCSessionDescription) => { + await setRemoteDescription(sdp); + const answerSdp = await createAnswer(); + setLocalDescription(answerSdp); + socketManager.emit('answer', answerSdp, roomName); + }); + + socketManager.on('answer', async (sdp: RTCSessionDescription) => { + await setRemoteDescription(sdp); + }); + + socketManager.on('candidate', async (candidate: RTCIceCandidate) => { + await addIceCandidate(candidate); + }); + + socketManager.on('roomFull', () => { + alert(ERROR_MESSAGE.FULL_ROOM); + }); + + socketManager.on('userExit', async () => { + onNegotiationDataChannels(); + }); +}; From 5dd83fb9d93fa0fce8dd2460cb8d2db5ed5a36d6 Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Sun, 10 Dec 2023 16:20:57 +0900 Subject: [PATCH 26/67] =?UTF-8?q?refactor:=20RTCPeerConnectino=20=EB=A7=8C?= =?UTF-8?q?=EB=93=9C=EB=8A=94=20=ED=95=A8=EC=88=98=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/services/RTCPeerConnection.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 frontend/src/business/services/RTCPeerConnection.ts diff --git a/frontend/src/business/services/RTCPeerConnection.ts b/frontend/src/business/services/RTCPeerConnection.ts new file mode 100644 index 00000000..a363ea01 --- /dev/null +++ b/frontend/src/business/services/RTCPeerConnection.ts @@ -0,0 +1,23 @@ +import WebRTC from '@business/hooks/useWebRTC/WebRTC'; + +import { HumanSocketManager } from './SocketManager'; + +const socketManager = new HumanSocketManager(); + +const { addRTCPeerConnectionEventListener, connectRTCPeerConnection, setRemoteStream } = WebRTC.getInstace(); + +export const makeRTCPeerConnection = (roomName: string) => { + connectRTCPeerConnection(); + + addRTCPeerConnectionEventListener('track', e => { + setRemoteStream(e.streams[0]); + }); + + addRTCPeerConnectionEventListener('icecandidate', e => { + if (!e.candidate) { + return; + } + + socketManager.emit('candidate', e.candidate, roomName); + }); +}; From a146a4d51d97194a7b197e7424778773437be46d Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Sun, 10 Dec 2023 16:21:27 +0900 Subject: [PATCH 27/67] =?UTF-8?q?refactor:=20=20useControllMedia=ED=9B=85?= =?UTF-8?q?=20=EB=B3=84=EB=8F=84=EB=A1=9C=20=EC=82=AC=EC=9A=A9=ED=95=A0=20?= =?UTF-8?q?=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hooks/useWebRTC/useControllMedia.ts | 135 +++++++++--------- 1 file changed, 68 insertions(+), 67 deletions(-) diff --git a/frontend/src/business/hooks/useWebRTC/useControllMedia.ts b/frontend/src/business/hooks/useWebRTC/useControllMedia.ts index 693a95d4..161216e6 100644 --- a/frontend/src/business/hooks/useWebRTC/useControllMedia.ts +++ b/frontend/src/business/hooks/useWebRTC/useControllMedia.ts @@ -3,51 +3,44 @@ import { useEffect } from 'react'; import { useMediaInfo } from '@stores/zustandStores/useMediaInfo'; import WebRTC from './WebRTC'; +import { useMedia } from './useMedia'; interface useContorollMediaParams { - peerConnectionRef: React.MutableRefObject; localVideoRef: React.RefObject; - mediaInfoChannel: React.MutableRefObject; - getMedia: ({ cameraID, audioID }: { cameraID?: string; audioID?: string }) => Promise; } -export function useControllMedia({ - localVideoRef, - peerConnectionRef, - mediaInfoChannel, - getMedia, -}: useContorollMediaParams) { - const { selectedAudioID, selectedCameraID, setSelectedAudioID, setSelectedCameraID, toggleMyMic, toggleMyVideo } = - useMediaInfo(state => ({ - toggleMyVideo: state.toggleMyVideo, - toggleMyMic: state.toggleMyMic, - setSelectedAudioID: state.setSelectedAudioID, - setSelectedCameraID: state.setSelectedCameraID, - selectedAudioID: state.selectedAudioID, - selectedCameraID: state.selectedCameraID, - })); - - const webRTC = WebRTC.getInstace(); - - const addTracks = () => { - if (webRTC.localStream === undefined) { +const toggleTrack = (track: MediaStreamTrack) => { + track.enabled = !track.enabled; +}; + +export function useControllMedia({ localVideoRef }: useContorollMediaParams) { + const { + selectedCameraID, + toggleMyMic: toggleMyMicState, + toggleMyVideo: toggleMyVideoState, + } = useMediaInfo(state => ({ + toggleMyVideo: state.toggleMyVideo, + toggleMyMic: state.toggleMyMic, + setSelectedAudioID: state.setSelectedAudioID, + setSelectedCameraID: state.setSelectedCameraID, + selectedAudioID: state.selectedAudioID, + selectedCameraID: state.selectedCameraID, + })); + + const { getLocalStream } = useMedia(); + + const { + dataChannels, + replacePeerconnectionAudioTrack2NowLocalStream, + replacePeerconnectionVideoTrack2NowLocalStream, + setLocalStream, + } = WebRTC.getInstace(); + + const setLocalVideoSrcObj = (stream: MediaStream) => { + if (!localVideoRef.current) { return; } - webRTC.localStream.getTracks().forEach(track => { - peerConnectionRef.current?.addTrack(track, webRTC.localStream!); - }); - }; - - const changeVideoTrack = () => { - const nowTrack = webRTC.localStream?.getVideoTracks()[0]; - const sender = peerConnectionRef.current?.getSenders().find(sender => sender.track?.kind === 'video'); - sender?.replaceTrack(nowTrack!); - }; - - const changeAudioTrack = () => { - const nowTrack = webRTC.localStream?.getAudioTracks()[0]; - const sender = peerConnectionRef.current?.getSenders().find(sender => sender.track?.kind === 'audio'); - sender?.replaceTrack(nowTrack!); + localVideoRef.current.srcObject = stream; }; const toggleVideo = () => { @@ -56,11 +49,16 @@ export function useControllMedia({ } const videoTrack = localVideoRef.current.srcObject as MediaStream; - videoTrack.getVideoTracks().forEach(track => (track.enabled = !track.enabled)); - toggleMyVideo(); - // ์—ฌ๊ธฐ์„œ dataChannel๋กœ ๋น„๋””์˜ค on/off๋ฅผ ๋ณด๋‚ด์ค˜์•ผ ํ•จ - if (!mediaInfoChannel.current || mediaInfoChannel.current.readyState !== 'open') return; - mediaInfoChannel.current.send(JSON.stringify([{ type: 'video', onOrOff: videoTrack.getVideoTracks()[0].enabled }])); + videoTrack.getVideoTracks().forEach(toggleTrack); + toggleMyVideoState(); + + const mediaInfoChannel = dataChannels.get('mediaInfoChannel'); + if (!mediaInfoChannel || mediaInfoChannel.readyState !== 'open') { + return; + } + + const videoTrackenabled = videoTrack.getVideoTracks()[0].enabled; + mediaInfoChannel.send(JSON.stringify([{ type: 'video', onOrOff: videoTrackenabled }])); }; const toggleAudio = () => { @@ -69,44 +67,47 @@ export function useControllMedia({ } const audioTrack = localVideoRef.current.srcObject as MediaStream; - audioTrack.getAudioTracks().forEach(track => (track.enabled = !track.enabled)); - toggleMyMic(); - // ์—ฌ๊ธฐ์„œ dataChannel๋กœ ์˜ค๋””์˜ค on/off๋ฅผ ๋ณด๋‚ด์ค˜์•ผ ํ•จ - if (!mediaInfoChannel.current || mediaInfoChannel.current.readyState !== 'open') return; - mediaInfoChannel.current.send(JSON.stringify([{ type: 'audio', onOrOff: audioTrack.getAudioTracks()[0].enabled }])); + audioTrack.getAudioTracks().forEach(toggleTrack); + toggleMyMicState(); + + const mediaInfoChannel = dataChannels.get('mediaInfoChannel'); + if (!mediaInfoChannel || mediaInfoChannel.readyState !== 'open') { + return; + } + + const audioTrackenabled = audioTrack.getAudioTracks()[0].enabled; + mediaInfoChannel.send(JSON.stringify([{ type: 'audio', onOrOff: audioTrackenabled }])); }; - const changeMyVideoTrack = async (id?: string) => { - const cameraID = id || selectedCameraID; + const changeMyVideoTrack = async () => { + const stream = await getLocalStream({ cameraID: selectedCameraID }); - setSelectedCameraID(cameraID); - await getMedia({ cameraID }); - changeVideoTrack(); + setLocalVideoSrcObj(stream); + setLocalStream(stream); + replacePeerconnectionVideoTrack2NowLocalStream(); }; const changeMyAudioTrack = async (id?: string) => { - const audioID = id || selectedAudioID; + const stream = await getLocalStream({ audioID: id }); - setSelectedAudioID(audioID); - await getMedia({ audioID: audioID }); - changeAudioTrack(); + setLocalVideoSrcObj(stream); + setLocalStream(stream); + replacePeerconnectionAudioTrack2NowLocalStream(); }; + // TODO mediaInfoChannel ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋–„ ๋กœ์ง์„ WebRTC ํด๋ž˜์Šค๋กœ ์˜ฎ๊ธฐ๊ธฐ. useEffect(() => { - if (!mediaInfoChannel.current) return; + const mediaInfoChannel = dataChannels.get('mediaInfoChannel'); + if (!mediaInfoChannel) return; - mediaInfoChannel.current.addEventListener('open', () => { + mediaInfoChannel.addEventListener('open', () => { const audioTrack = localVideoRef.current?.srcObject as MediaStream; const videoTrack = localVideoRef.current?.srcObject as MediaStream; - mediaInfoChannel.current?.send( - JSON.stringify([{ type: 'audio', onOrOff: audioTrack.getAudioTracks()[0].enabled }]), - ); - mediaInfoChannel.current?.send( - JSON.stringify([{ type: 'video', onOrOff: videoTrack.getVideoTracks()[0].enabled }]), - ); + mediaInfoChannel?.send(JSON.stringify([{ type: 'audio', onOrOff: audioTrack.getAudioTracks()[0].enabled }])); + mediaInfoChannel?.send(JSON.stringify([{ type: 'video', onOrOff: videoTrack.getVideoTracks()[0].enabled }])); }); - }, [mediaInfoChannel.current]); + }, []); - return { addTracks, changeMyVideoTrack, changeMyAudioTrack, toggleVideo, toggleAudio }; + return { changeMyVideoTrack, changeMyAudioTrack, toggleVideo, toggleAudio }; } From f31092abe3e6582affee147007ffaf62b686c01c Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Sun, 10 Dec 2023 16:21:42 +0900 Subject: [PATCH 28/67] =?UTF-8?q?refactor:=20useMedia=ED=9B=85=20=EB=B3=84?= =?UTF-8?q?=EB=8F=84=EB=A1=9C=20=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/business/hooks/useWebRTC/useMedia.ts | 27 +++---------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/frontend/src/business/hooks/useWebRTC/useMedia.ts b/frontend/src/business/hooks/useWebRTC/useMedia.ts index f9306d7c..7dbb89d0 100644 --- a/frontend/src/business/hooks/useWebRTC/useMedia.ts +++ b/frontend/src/business/hooks/useWebRTC/useMedia.ts @@ -1,11 +1,7 @@ -import { RefObject } from 'react'; - import { getUserMediaStream } from '@business/services/Media'; import { useMediaInfo } from '@stores/zustandStores/useMediaInfo'; -import WebRTC from './WebRTC'; - export function useMedia() { const { myMicOn, myVideoOn, selectedAudioID, selectedCameraID } = useMediaInfo(state => ({ selectedAudioID: state.selectedAudioID, @@ -14,23 +10,7 @@ export function useMedia() { myVideoOn: state.myVideoOn, })); - const webRTC = WebRTC.getInstace(); - - const setLocalVideoWithLocalStream = ({ - stream, - localVideoRef, - }: { - stream: MediaStream; - localVideoRef: RefObject; - }) => { - if (!localVideoRef.current) { - return; - } - localVideoRef.current.srcObject = stream; - webRTC.setLocalStream(stream); - }; - - const getMedia = async ({ audioID, cameraID }: { cameraID?: string; audioID?: string } = {}) => { + const getLocalStream = async ({ audioID, cameraID }: { cameraID?: string; audioID?: string } = {}) => { const nowSelectedAudioID = audioID || selectedAudioID; const nowSelectedCameraID = cameraID || selectedCameraID; @@ -54,10 +34,11 @@ export function useMedia() { if (!myMicOn) { stream.getAudioTracks().forEach(track => (track.enabled = false)); } + + return stream; }; return { - getMedia, - setLocalVideoWithLocalStream, + getLocalStream, }; } From 36f1ee677002c85b941826f9fae20ef4f6355948 Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Sun, 10 Dec 2023 18:11:20 +0900 Subject: [PATCH 29/67] =?UTF-8?q?refactor:=20useWebRTC=20=ED=9B=85=20?= =?UTF-8?q?=EC=95=88=EC=AA=BD=EC=9D=98=20=ED=9B=85=EB=93=A4=EC=9D=98=20?= =?UTF-8?q?=EC=9D=98=EC=A1=B4=EA=B4=80=EA=B3=84=EB=A5=BC=20=EB=82=AE?= =?UTF-8?q?=EC=B6=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - WebRTC๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์„ธ๋ถ€๋กœ์ง์€ WebRTC ํด๋ž˜์Šค๋กœ ๋„ฃ์–ด์คŒ - media๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ๋ถ€๋ถ„์€ useControllMedia ํ›…์œผ๋กœ ๋„ฃ์–ด์คŒ - Media๋ฅผ ๋ฐ›์•„์˜ค๋Š” ๋ถ€๋ถ„๋„ ํ•จ์ˆ˜๋กœ ๋”ฐ๋กœ ๋ถ„๋ฆฌ - makeRTCPeerConnection๋Š” ๋ณ„๋„์˜ ํ•จ์ˆ˜๋กœ ์žˆ์—ˆ๋Š”๋ฐ ํด๋ž˜์Šค๋กœ ํ•ฉ์ณ์คŒ. --- .../src/business/hooks/useWebRTC/WebRTC.ts | 21 --- .../hooks/useWebRTC/useControllMedia.ts | 36 +--- .../hooks/useWebRTC/useDataChannel.ts | 32 ++-- .../hooks/useWebRTC/useRTCPeerConnection.ts | 51 ------ .../src/business/hooks/useWebRTC/useWebRTC.ts | 87 ++++------ .../business/services/RTCPeerConnection.ts | 23 --- frontend/src/business/services/Socket.ts | 25 +-- frontend/src/business/services/WebRTC.ts | 155 ++++++++++++++++++ .../src/pages/HumanChatPage/ChattingPage.tsx | 36 +++- .../src/pages/HumanChatPage/HumanChatPage.tsx | 3 +- .../src/pages/HumanChatPage/SettingPage.tsx | 18 +- .../useChattingPageChangeVideoTrackJoined.ts | 17 -- .../useChattingPageCreateJoinRoomPopup.ts | 5 +- .../useSettingPageProfileNicknameSetting.ts | 2 +- 14 files changed, 273 insertions(+), 238 deletions(-) delete mode 100644 frontend/src/business/hooks/useWebRTC/WebRTC.ts delete mode 100644 frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts delete mode 100644 frontend/src/business/services/RTCPeerConnection.ts create mode 100644 frontend/src/business/services/WebRTC.ts delete mode 100644 frontend/src/pages/HumanChatPage/useChattingPageChangeVideoTrackJoined.ts diff --git a/frontend/src/business/hooks/useWebRTC/WebRTC.ts b/frontend/src/business/hooks/useWebRTC/WebRTC.ts deleted file mode 100644 index 57c64cd3..00000000 --- a/frontend/src/business/hooks/useWebRTC/WebRTC.ts +++ /dev/null @@ -1,21 +0,0 @@ -export default class WebRTC { - public localStream: MediaStream | undefined; - public remoteStream: MediaStream | undefined; - - private static instance: WebRTC | undefined; - constructor() {} - - static getInstace() { - if (!this.instance) { - this.instance = new WebRTC(); - } - return this.instance; - } - - public setLocalStream(stream: MediaStream) { - this.localStream = stream; - } - public setRemoteStream(stream: MediaStream) { - this.remoteStream = stream; - } -} diff --git a/frontend/src/business/hooks/useWebRTC/useControllMedia.ts b/frontend/src/business/hooks/useWebRTC/useControllMedia.ts index 161216e6..071ec2af 100644 --- a/frontend/src/business/hooks/useWebRTC/useControllMedia.ts +++ b/frontend/src/business/hooks/useWebRTC/useControllMedia.ts @@ -1,8 +1,7 @@ -import { useEffect } from 'react'; +import WebRTC from '../../services/WebRTC'; import { useMediaInfo } from '@stores/zustandStores/useMediaInfo'; -import WebRTC from './WebRTC'; import { useMedia } from './useMedia'; interface useContorollMediaParams { @@ -29,12 +28,7 @@ export function useControllMedia({ localVideoRef }: useContorollMediaParams) { const { getLocalStream } = useMedia(); - const { - dataChannels, - replacePeerconnectionAudioTrack2NowLocalStream, - replacePeerconnectionVideoTrack2NowLocalStream, - setLocalStream, - } = WebRTC.getInstace(); + const webRTC = WebRTC.getInstace(); const setLocalVideoSrcObj = (stream: MediaStream) => { if (!localVideoRef.current) { @@ -52,7 +46,7 @@ export function useControllMedia({ localVideoRef }: useContorollMediaParams) { videoTrack.getVideoTracks().forEach(toggleTrack); toggleMyVideoState(); - const mediaInfoChannel = dataChannels.get('mediaInfoChannel'); + const mediaInfoChannel = webRTC.dataChannels.get('mediaInfoChannel'); if (!mediaInfoChannel || mediaInfoChannel.readyState !== 'open') { return; } @@ -70,7 +64,7 @@ export function useControllMedia({ localVideoRef }: useContorollMediaParams) { audioTrack.getAudioTracks().forEach(toggleTrack); toggleMyMicState(); - const mediaInfoChannel = dataChannels.get('mediaInfoChannel'); + const mediaInfoChannel = webRTC.dataChannels.get('mediaInfoChannel'); if (!mediaInfoChannel || mediaInfoChannel.readyState !== 'open') { return; } @@ -83,31 +77,17 @@ export function useControllMedia({ localVideoRef }: useContorollMediaParams) { const stream = await getLocalStream({ cameraID: selectedCameraID }); setLocalVideoSrcObj(stream); - setLocalStream(stream); - replacePeerconnectionVideoTrack2NowLocalStream(); + webRTC.setLocalStream(stream); + webRTC.replacePeerconnectionVideoTrack2NowLocalStream(); }; const changeMyAudioTrack = async (id?: string) => { const stream = await getLocalStream({ audioID: id }); setLocalVideoSrcObj(stream); - setLocalStream(stream); - replacePeerconnectionAudioTrack2NowLocalStream(); + webRTC.setLocalStream(stream); + webRTC.replacePeerconnectionAudioTrack2NowLocalStream(); }; - // TODO mediaInfoChannel ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋–„ ๋กœ์ง์„ WebRTC ํด๋ž˜์Šค๋กœ ์˜ฎ๊ธฐ๊ธฐ. - useEffect(() => { - const mediaInfoChannel = dataChannels.get('mediaInfoChannel'); - if (!mediaInfoChannel) return; - - mediaInfoChannel.addEventListener('open', () => { - const audioTrack = localVideoRef.current?.srcObject as MediaStream; - const videoTrack = localVideoRef.current?.srcObject as MediaStream; - - mediaInfoChannel?.send(JSON.stringify([{ type: 'audio', onOrOff: audioTrack.getAudioTracks()[0].enabled }])); - mediaInfoChannel?.send(JSON.stringify([{ type: 'video', onOrOff: videoTrack.getVideoTracks()[0].enabled }])); - }); - }, []); - return { changeMyVideoTrack, changeMyAudioTrack, toggleVideo, toggleAudio }; } diff --git a/frontend/src/business/hooks/useWebRTC/useDataChannel.ts b/frontend/src/business/hooks/useWebRTC/useDataChannel.ts index 5ac03fa5..9109e9b5 100644 --- a/frontend/src/business/hooks/useWebRTC/useDataChannel.ts +++ b/frontend/src/business/hooks/useWebRTC/useDataChannel.ts @@ -1,14 +1,15 @@ +import WebRTC from '../../services/WebRTC'; + import { useMediaInfo } from '@stores/zustandStores/useMediaInfo'; import { useProfileInfo } from '@stores/zustandStores/useProfileInfo'; import { array2ArrayBuffer } from '@utils/array'; -import WebRTC from './WebRTC'; - -export function useDataChannel() { - const { myMicOn, myVideoOn, setRemoteMicOn, setRemoteVideoOn } = useMediaInfo(state => ({ - myMicOn: state.myMicOn, - myVideoOn: state.myVideoOn, +interface useDataChannelParams { + localVideoRef: React.RefObject; +} +export function useDataChannel({ localVideoRef }: useDataChannelParams) { + const { setRemoteMicOn, setRemoteVideoOn } = useMediaInfo(state => ({ setRemoteMicOn: state.setRemoteMicOn, setRemoteVideoOn: state.setRemoteVideoOn, })); @@ -19,10 +20,10 @@ export function useDataChannel() { myProfile: state.myProfile, })); - const { addDataChannel } = WebRTC.getInstace(); + const webRTC = WebRTC.getInstace(); const initMediaInfoChannel = () => { - const mediaInfoChannel = addDataChannel('mediaInfoChannel'); + const mediaInfoChannel = webRTC.addDataChannel('mediaInfoChannel'); mediaInfoChannel?.addEventListener('message', ({ data }) => { const mediaInfoArray = JSON.parse(data); @@ -37,21 +38,24 @@ export function useDataChannel() { }); mediaInfoChannel?.addEventListener('open', function () { - this.send( + const audioTrack = localVideoRef.current?.srcObject as MediaStream; + const videoTrack = localVideoRef.current?.srcObject as MediaStream; + + mediaInfoChannel?.send( JSON.stringify([ - { type: 'audio', onOrOff: myMicOn }, - { type: 'video', onOrOff: myVideoOn }, + { type: 'audio', onOrOff: audioTrack.getAudioTracks()[0].enabled }, + { type: 'video', onOrOff: videoTrack.getVideoTracks()[0].enabled }, ]), ); }); }; const initChatChannel = () => { - addDataChannel('chatChannel'); + webRTC.addDataChannel('chatChannel'); }; const initProfileChannel = () => { - const profileChannel = addDataChannel('profileChannel'); + const profileChannel = webRTC.addDataChannel('profileChannel'); profileChannel?.addEventListener('message', ({ data }) => { const receivedData = JSON.parse(data); @@ -69,7 +73,7 @@ export function useDataChannel() { }; const initNicknameChannel = () => { - const nicknameChannel = addDataChannel('nicknameChannel'); + const nicknameChannel = webRTC.addDataChannel('nicknameChannel'); nicknameChannel?.addEventListener('message', ({ data }) => { setRemoteNickname(data); diff --git a/frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts b/frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts deleted file mode 100644 index e31100d9..00000000 --- a/frontend/src/business/hooks/useWebRTC/useRTCPeerConnection.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { useEffect, useRef } from 'react'; - -import { HumanSocketManager } from '@business/services/SocketManager'; - -import WebRTC from './WebRTC'; - -interface useRTCPeerConnectionParams { - remoteVideoRef: React.RefObject; -} - -export function useRTCPeerConnection({ remoteVideoRef }: useRTCPeerConnectionParams) { - const socketManager = new HumanSocketManager(); - const remoteStreamRef = useRef(); - - const { addRTCPeerConnectionEventListener, connectRTCPeerConnection, setRemoteStream, remoteStream } = - WebRTC.getInstace(); - - const makeRTCPeerConnection = ({ roomName }: { roomName: string }) => { - connectRTCPeerConnection(); - - addRTCPeerConnectionEventListener('track', e => { - setRemoteStream(e.streams[0]); - console.log(remoteVideoRef.current, remoteVideoRef); - - if (!remoteVideoRef.current) { - return; - } - - remoteVideoRef.current.srcObject = e.streams[0]; - }); - - addRTCPeerConnectionEventListener('icecandidate', e => { - if (!e.candidate) { - return; - } - - socketManager.emit('candidate', e.candidate, roomName); - }); - }; - - useEffect(() => { - if (!remoteVideoRef.current || !remoteStreamRef.current) { - return; - } - console.log('chanred'); - - remoteVideoRef.current.srcObject = remoteStreamRef.current; - }, [remoteVideoRef]); - - return { makeRTCPeerConnection }; -} diff --git a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts index 1c44d10f..44a169b5 100644 --- a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts +++ b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts @@ -1,79 +1,64 @@ -import { useEffect } from 'react'; +import WebRTC from '../../services/WebRTC'; +import { useEffect, useRef } from 'react'; + +import { initSignalingSocket } from '@business/services/Socket'; -import WebRTC from './WebRTC'; -import { useControllMedia } from './useControllMedia'; import { useDataChannel } from './useDataChannel'; import { useMedia } from './useMedia'; -import { useRTCPeerConnection } from './useRTCPeerConnection'; -import { useSignalingSocket } from './useSignalingSocket'; export default function useWebRTC() { const webRTC = WebRTC.getInstace(); - const { localVideoRef, remoteVideoRef, getMedia } = useMedia(); - - const { makeRTCPeerConnection } = useRTCPeerConnection({ remoteVideoRef }); - - const { initDataChannels } = useDataChannel({}); - - const { addTracks, changeMyAudioTrack, changeMyVideoTrack, toggleAudio, toggleVideo } = useControllMedia({ - localVideoRef, - getMedia, - }); + const localVideoRef = useRef(null); + const remoteVideoRef = useRef(null); - const negotiationDataChannels = ({ roomName }: { roomName: string }) => { - webRTC.closeRTCPeerConnection(); - closeDataChannels(); - makeRTCPeerConnection({ roomName }); - initDataChannels(); - addTracks(); - }; + const { getLocalStream } = useMedia(); - const { initSignalingSocket, createRoom, joinRoom, checkRoomExist } = useSignalingSocket({ - negotiationDataChannels, - }); + const { initDataChannels } = useDataChannel({ localVideoRef }); const startWebRTC = async ({ roomName }: { roomName: string }) => { if (webRTC.isConnectedPeerConnection()) { return; } - await getMedia({}); - initSignalingSocket({ roomName }); - makeRTCPeerConnection({ roomName }); - initDataChannels(); - addTracks(); - }; - const endWebRTC = () => { - if (webRTC.isConnectedPeerConnection()) { - webRTC.closeRTCPeerConnection(); - closeDataChannels(); - } + const stream = await getLocalStream(); + webRTC.setLocalStream(stream); + localVideoRef.current!.srcObject = stream; + + initSignalingSocket({ + roomName, + onExitUser: () => { + webRTC.closeRTCPeerConnection(); + webRTC.closeDataChannels(); + webRTC.connectRTCPeerConnection(roomName); + initDataChannels(); + webRTC.addTracks(); + }, + }); + + webRTC.connectRTCPeerConnection(roomName); + initDataChannels(); + webRTC.addTracks(); }; useEffect(() => { return () => { - endWebRTC(); + webRTC.closeRTCPeerConnection(); + webRTC.closeDataChannels(); }; }, []); + useEffect(() => { + if (!remoteVideoRef.current || !webRTC.remoteStream) { + return; + } + console.log('chanted track'); + remoteVideoRef.current.srcObject = webRTC.remoteStream as MediaStream; + }, [webRTC.remoteStream?.id]); + return { localVideoRef, remoteVideoRef, - mediaInfoChannel, - chatChannel, - profileChannel, - nicknameChannel, - toggleAudio, - toggleVideo, - addTracks, - changeMyAudioTrack, - changeMyVideoTrack, - getMedia, startWebRTC, - endWebRTC, - createRoom, - joinRoom, - checkRoomExist, }; } diff --git a/frontend/src/business/services/RTCPeerConnection.ts b/frontend/src/business/services/RTCPeerConnection.ts deleted file mode 100644 index a363ea01..00000000 --- a/frontend/src/business/services/RTCPeerConnection.ts +++ /dev/null @@ -1,23 +0,0 @@ -import WebRTC from '@business/hooks/useWebRTC/WebRTC'; - -import { HumanSocketManager } from './SocketManager'; - -const socketManager = new HumanSocketManager(); - -const { addRTCPeerConnectionEventListener, connectRTCPeerConnection, setRemoteStream } = WebRTC.getInstace(); - -export const makeRTCPeerConnection = (roomName: string) => { - connectRTCPeerConnection(); - - addRTCPeerConnectionEventListener('track', e => { - setRemoteStream(e.streams[0]); - }); - - addRTCPeerConnectionEventListener('icecandidate', e => { - if (!e.candidate) { - return; - } - - socketManager.emit('candidate', e.candidate, roomName); - }); -}; diff --git a/frontend/src/business/services/Socket.ts b/frontend/src/business/services/Socket.ts index 7a2049c3..89c21c8d 100644 --- a/frontend/src/business/services/Socket.ts +++ b/frontend/src/business/services/Socket.ts @@ -1,40 +1,40 @@ -import WebRTC from '@business/hooks/useWebRTC/WebRTC'; +import WebRTC from '@business/services/WebRTC'; import { ERROR_MESSAGE } from '@constants/messages'; import { HumanSocketManager } from './SocketManager'; -const { addIceCandidate, createOffer, createAnswer, setLocalDescription, setRemoteDescription } = WebRTC.getInstace(); +const webRTC = WebRTC.getInstace(); const socketManager = new HumanSocketManager(); interface initSignalingSocketParams { roomName: string; - onNegotiationDataChannels: () => void; + onExitUser: () => void; } -export const initSignalingSocket = ({ roomName, onNegotiationDataChannels }: initSignalingSocketParams) => { +export const initSignalingSocket = ({ roomName, onExitUser }: initSignalingSocketParams) => { socketManager.on('welcome', async (users: { id: string }[]) => { if (users.length === 0) { return; } - const sdp = await createOffer(); - await setLocalDescription(sdp); + const sdp = await webRTC.createOffer(); + await webRTC.setLocalDescription(sdp); socketManager.emit('offer', sdp, roomName); }); socketManager.on('offer', async (sdp: RTCSessionDescription) => { - await setRemoteDescription(sdp); - const answerSdp = await createAnswer(); - setLocalDescription(answerSdp); + await webRTC.setRemoteDescription(sdp); + const answerSdp = await webRTC.createAnswer(); + webRTC.setLocalDescription(answerSdp); socketManager.emit('answer', answerSdp, roomName); }); socketManager.on('answer', async (sdp: RTCSessionDescription) => { - await setRemoteDescription(sdp); + await webRTC.setRemoteDescription(sdp); }); socketManager.on('candidate', async (candidate: RTCIceCandidate) => { - await addIceCandidate(candidate); + await webRTC.addIceCandidate(candidate); }); socketManager.on('roomFull', () => { @@ -42,6 +42,7 @@ export const initSignalingSocket = ({ roomName, onNegotiationDataChannels }: ini }); socketManager.on('userExit', async () => { - onNegotiationDataChannels(); + console.log('userExit'); + onExitUser(); }); }; diff --git a/frontend/src/business/services/WebRTC.ts b/frontend/src/business/services/WebRTC.ts new file mode 100644 index 00000000..c92af529 --- /dev/null +++ b/frontend/src/business/services/WebRTC.ts @@ -0,0 +1,155 @@ +import { iceServers } from '@constants/urls'; + +import { HumanSocketManager } from './SocketManager'; + +type RTCDataChannelKey = 'mediaInfoChannel' | 'chatChannel' | 'profileChannel' | 'nicknameChannel'; + +export default class WebRTC { + public localStream: MediaStream | undefined; + public remoteStream: MediaStream | undefined; + public peerConnection: RTCPeerConnection | null = null; + public dataChannels: Map = new Map(); + + private static instance: WebRTC | undefined; + private nextDataChannelId = 0; + + socketManager = new HumanSocketManager(); + + constructor() {} + + static getInstace() { + if (!this.instance) { + this.instance = new WebRTC(); + } + return this.instance; + } + + public setLocalStream = (stream: MediaStream) => { + this.localStream = stream; + }; + public setRemoteStream = (stream: MediaStream) => { + this.remoteStream = stream; + }; + + public connectRTCPeerConnection = (roomName: string) => { + const devIceServerConfig = [{ urls: iceServers }]; + + this.peerConnection = new RTCPeerConnection({ + // TODO: TURN/STUN์„œ๋ฒ„ ์ถ”๊ฐ€์‹œ ๋ณ€๊ฒฝํ•ด์•ผํ•จ. + iceServers: import.meta.env.MODE === 'development' ? devIceServerConfig : devIceServerConfig, + }); + + this.addRTCPeerConnectionEventListener('track', e => { + this.setRemoteStream(e.streams[0]); + }); + + this.addRTCPeerConnectionEventListener('icecandidate', e => { + if (!e.candidate) { + return; + } + + this.socketManager.emit('candidate', e.candidate, roomName); + }); + }; + + public createOffer = async () => { + const sdp = await this.peerConnection?.createOffer(); + if (!sdp) { + throw new Error('createOffer ๋„์ค‘ ์—๋Ÿฌ, sdp๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'); + } + return sdp; + }; + + public createAnswer = async () => { + const answer = await this.peerConnection?.createAnswer(); + if (!answer) { + throw new Error('createAnswer ๋„์ค‘ ์—๋Ÿฌ, answer๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'); + } + return answer; + }; + + public setRemoteDescription = async (sdp?: RTCSessionDescriptionInit) => { + if (!sdp) { + throw new Error('setRemoteDescription ๋„์ค‘ ์—๋Ÿฌ, sdp๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'); + } + await this.peerConnection?.setRemoteDescription(sdp); + }; + + public setLocalDescription = async (sdp?: RTCSessionDescriptionInit) => { + if (!sdp) { + throw new Error('setLocalDescription ๋„์ค‘ ์—๋Ÿฌ, sdp๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'); + } + await this.peerConnection?.setLocalDescription(sdp); + }; + + public addRTCPeerConnectionEventListener = ( + type: K, + listener: (this: RTCPeerConnection, ev: RTCPeerConnectionEventMap[K]) => any, + options?: boolean | AddEventListenerOptions, + ): void => { + this.peerConnection?.addEventListener(type, listener, options); + }; + + public addIceCandidate = async (candidate?: RTCIceCandidateInit) => { + if (!candidate) { + throw new Error('addIceCandidate ๋„์ค‘ ์—๋Ÿฌ, candidate๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.'); + } + await this.peerConnection?.addIceCandidate(candidate); + }; + + public closeRTCPeerConnection = () => { + this.peerConnection?.close(); + this.peerConnection = null; + }; + + public isConnectedPeerConnection = () => { + if (!this?.peerConnection) { + return false; + } + return this.peerConnection?.iceConnectionState === 'connected'; + }; + + public addDataChannel = (key: RTCDataChannelKey) => { + const dataChannel = this.peerConnection?.createDataChannel(key, { + negotiated: true, + id: this.nextDataChannelId++, + }); + + if (dataChannel) { + this.dataChannels.set(key, dataChannel); + } + + return dataChannel; + }; + + public closeDataChannels = () => { + this.dataChannels.forEach(dataChannel => { + dataChannel.close(); + }); + this.dataChannels.clear(); + this.dataChannels = new Map(); + this.nextDataChannelId = 0; + }; + + public addTracks = () => { + if (this.localStream === undefined) { + return; + } + + this.localStream.getTracks().forEach(track => { + this.peerConnection?.addTrack(track, this.localStream!); + }); + }; + + public replacePeerconnectionVideoTrack2NowLocalStream = () => { + const nowVideoTrack = this.localStream?.getVideoTracks()[0]; + const sender = this.peerConnection?.getSenders().find(sender => sender.track?.kind === 'video'); + sender?.replaceTrack(nowVideoTrack!); + }; + + public replacePeerconnectionAudioTrack2NowLocalStream = () => { + const nowAudioTrack = this.localStream?.getAudioTracks()[0]; + const sender = this.peerConnection?.getSenders().find(sender => sender.track?.kind === 'audio'); + sender?.replaceTrack(nowAudioTrack!); + }; +} diff --git a/frontend/src/pages/HumanChatPage/ChattingPage.tsx b/frontend/src/pages/HumanChatPage/ChattingPage.tsx index 002d808f..8befb6b2 100644 --- a/frontend/src/pages/HumanChatPage/ChattingPage.tsx +++ b/frontend/src/pages/HumanChatPage/ChattingPage.tsx @@ -1,10 +1,13 @@ +import { useEffect } from 'react'; import { useNavigate, useOutletContext } from 'react-router-dom'; import { IconButton } from '@components/Buttons'; import CamContainer from '@components/CamContainer'; +import { useControllMedia } from '@business/hooks/useWebRTC/useControllMedia'; +import WebRTC from '@business/services/WebRTC'; + import type { OutletContext } from './HumanChatPage'; -import { useChattingPageChangeVideoTrackJoined } from './useChattingPageChangeVideoTrackJoined'; import { useChattingPageCreateJoinRoomPasswordPopup } from './useChattingPageCreateJoinRoomPopup'; export default function ChattingPage() { @@ -12,15 +15,40 @@ export default function ChattingPage() { localVideoRef, remoteVideoRef, tarotButtonDisabled, - toggleVideo, - toggleAudio, tarotButtonClick, enableSideBar, chatPageState: { joined }, unblockGoBack, }: OutletContext = useOutletContext(); - useChattingPageChangeVideoTrackJoined(); + const { toggleAudio, toggleVideo, changeMyVideoTrack } = useControllMedia({ localVideoRef }); + const webRTC = WebRTC.getInstace(); + + useEffect(() => { + if (joined) { + changeMyVideoTrack(); + } + }, [joined]); + + useEffect(() => { + if ( + !remoteVideoRef.current || + !webRTC.remoteStream || + (remoteVideoRef.current.srcObject as MediaStream)?.id === webRTC.remoteStream?.id + ) { + return; + } + + remoteVideoRef.current.srcObject = webRTC.remoteStream as MediaStream; + }, [remoteVideoRef.current]); + + // useEffect(() => { + // if (!remoteVideoRef.current || !webRTC.remoteStream) { + // return; + // } + // remoteVideoRef.current.srcObject = webRTC.remoteStream as MediaStream; + // }, [webRTC.remoteStream?.id, remoteVideoRef.current]); + useChattingPageCreateJoinRoomPasswordPopup({ unblockGoBack, enableSideBar }); const navigate = useNavigate(); diff --git a/frontend/src/pages/HumanChatPage/HumanChatPage.tsx b/frontend/src/pages/HumanChatPage/HumanChatPage.tsx index 12206aed..762927c6 100644 --- a/frontend/src/pages/HumanChatPage/HumanChatPage.tsx +++ b/frontend/src/pages/HumanChatPage/HumanChatPage.tsx @@ -10,7 +10,7 @@ import { useBlocker } from '@business/hooks/useBlocker'; import { useHumanChatMessage } from '@business/hooks/useChatMessage'; import { useHumanTarotSpread } from '@business/hooks/useTarotSpread'; import useWebRTC from '@business/hooks/useWebRTC'; -import WebRTC from '@business/hooks/useWebRTC/WebRTC'; +import WebRTC from '@business/services/WebRTC'; import { useHumanChatPageContentAnimation } from './useHumanChatPageContentAnimation'; import { ChatPageState, useHumanChatPageCreateRoomEvent } from './useHumanChatPageCreateRoomEvent'; @@ -28,6 +28,7 @@ export interface OutletContext extends ReturnType { export default function HumanChatPage() { const webRTCData = useWebRTC(); + useEffect(() => {}, [webRTCData.remoteVideoRef, webRTCData.remoteVideoRef.current]); useHumanChatPageWrongURL(); const { chatPageState, setChatPageState } = useHumanChatPageCreateRoomEvent(); diff --git a/frontend/src/pages/HumanChatPage/SettingPage.tsx b/frontend/src/pages/HumanChatPage/SettingPage.tsx index 8908d524..db203ce6 100644 --- a/frontend/src/pages/HumanChatPage/SettingPage.tsx +++ b/frontend/src/pages/HumanChatPage/SettingPage.tsx @@ -3,6 +3,7 @@ import { useNavigate, useOutletContext } from 'react-router-dom'; import ProfileSetting from '@components/ProfileSetting'; +import { useControllMedia } from '@business/hooks/useWebRTC/useControllMedia'; import { HumanSocketManager } from '@business/services/SocketManager'; import type { OutletContext } from './HumanChatPage'; @@ -14,15 +15,8 @@ export default function ChattingPage() { const navigate = useNavigate(); - const { - localVideoRef, - toggleVideo, - toggleAudio, - changeMyVideoTrack, - changeMyAudioTrack, - enableSideBar, - disableSideBar, - }: OutletContext = useOutletContext(); + const { localVideoRef, enableSideBar, disableSideBar }: OutletContext = useOutletContext(); + const { changeMyAudioTrack, changeMyVideoTrack, toggleAudio, toggleVideo } = useControllMedia({ localVideoRef }); useEffect(() => { disableSideBar(); @@ -33,8 +27,7 @@ export default function ChattingPage() { changeMyVideoTrack(); }, []); - const { setLocalNickname, setLocalProfileImage, sendProfileInfoWithNavigateBefore } = - useSettingPageProfileNicknameSetting(); + const { setLocalNickname, setLocalProfileImage, sendProfileInfo } = useSettingPageProfileNicknameSetting(); const { mediaOptions } = useSettingPageMediaOptinos(); @@ -48,8 +41,9 @@ export default function ChattingPage() { micList={mediaOptions.audio} videoRef={localVideoRef} onConfirm={() => { - sendProfileInfoWithNavigateBefore(); + sendProfileInfo(); enableSideBar(); + navigate('..'); }} onChangeProfileImage={setLocalProfileImage} onChangeNickname={setLocalNickname} diff --git a/frontend/src/pages/HumanChatPage/useChattingPageChangeVideoTrackJoined.ts b/frontend/src/pages/HumanChatPage/useChattingPageChangeVideoTrackJoined.ts deleted file mode 100644 index cbe31c31..00000000 --- a/frontend/src/pages/HumanChatPage/useChattingPageChangeVideoTrackJoined.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { useEffect } from 'react'; -import { useOutletContext } from 'react-router-dom'; - -import { OutletContext } from './HumanChatPage'; - -export function useChattingPageChangeVideoTrackJoined() { - const { - chatPageState: { joined }, - changeMyVideoTrack, - }: OutletContext = useOutletContext(); - - useEffect(() => { - if (joined) { - changeMyVideoTrack(); - } - }, [joined]); -} diff --git a/frontend/src/pages/HumanChatPage/useChattingPageCreateJoinRoomPopup.ts b/frontend/src/pages/HumanChatPage/useChattingPageCreateJoinRoomPopup.ts index 2973eda2..98c550dd 100644 --- a/frontend/src/pages/HumanChatPage/useChattingPageCreateJoinRoomPopup.ts +++ b/frontend/src/pages/HumanChatPage/useChattingPageCreateJoinRoomPopup.ts @@ -1,6 +1,7 @@ import { useEffect } from 'react'; import { useNavigate, useOutletContext, useParams } from 'react-router-dom'; +import { useSignalingSocket } from '@business/hooks/useWebRTC/useSignalingSocket'; import { HumanSocketManager } from '@business/services/SocketManager'; import { ERROR_MESSAGE } from '@constants/messages'; @@ -18,12 +19,10 @@ export function useChattingPageCreateJoinRoomPasswordPopup({ const { chatPageState: { host, joined }, startWebRTC, - joinRoom, - createRoom, - checkRoomExist, }: OutletContext = useOutletContext(); const humanSocket = new HumanSocketManager(); + const { createRoom, joinRoom, checkRoomExist } = useSignalingSocket(); const { roomName } = useParams(); const navigate = useNavigate(); diff --git a/frontend/src/pages/HumanChatPage/useSettingPageProfileNicknameSetting.ts b/frontend/src/pages/HumanChatPage/useSettingPageProfileNicknameSetting.ts index b42ad4cb..bba41a8e 100644 --- a/frontend/src/pages/HumanChatPage/useSettingPageProfileNicknameSetting.ts +++ b/frontend/src/pages/HumanChatPage/useSettingPageProfileNicknameSetting.ts @@ -1,7 +1,7 @@ import { ChangeEvent } from 'react'; import { useOutletContext } from 'react-router-dom'; -import WebRTC from '@business/hooks/useWebRTC/WebRTC'; +import WebRTC from '@business/services/WebRTC'; import { useProfileInfo } from '@stores/zustandStores/useProfileInfo'; From 09b315dd63a76b747071e3b8c4208ae1b0f38e28 Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Sun, 10 Dec 2023 18:17:43 +0900 Subject: [PATCH 30/67] =?UTF-8?q?fix:=20SocketManager=20=EC=8B=B1=EA=B8=80?= =?UTF-8?q?=ED=86=A4=20=ED=8C=A8=ED=84=B4=20=EC=A0=9C=EB=8C=80=EB=A1=9C=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hooks/useChatMessage/useAiChatMessage.ts | 9 +-------- .../hooks/useTarotSpread/useAiTarotSpread.tsx | 2 +- .../business/hooks/useWebRTC/useSignalingSocket.ts | 2 +- frontend/src/business/services/Socket.ts | 2 +- .../services/SocketManager/AISocketManager.ts | 11 ++++++++++- .../services/SocketManager/HumanSocketManager.ts | 12 ++++++++---- .../business/services/SocketManager/SocketManager.ts | 8 ++++---- frontend/src/business/services/WebRTC.ts | 2 +- frontend/src/pages/HumanChatPage/SettingPage.tsx | 2 +- .../useChattingPageCreateJoinRoomPopup.ts | 2 +- .../HumanChatPage/useHumanChatPageCreateRoomEvent.ts | 2 +- 11 files changed, 30 insertions(+), 24 deletions(-) diff --git a/frontend/src/business/hooks/useChatMessage/useAiChatMessage.ts b/frontend/src/business/hooks/useChatMessage/useAiChatMessage.ts index 51390610..24da50d8 100644 --- a/frontend/src/business/hooks/useChatMessage/useAiChatMessage.ts +++ b/frontend/src/business/hooks/useChatMessage/useAiChatMessage.ts @@ -2,19 +2,16 @@ import { useEffect, useState } from 'react'; import { MessageButton } from '@components/ChatContainer'; -// import useTOLD from '@business/hooks/useTOLD'; import { AISocketManager } from '@business/services/SocketManager'; import useChatMessage from './useChatMessage'; export function useAiChatMessage() { - const socketManager = new AISocketManager(); + const socketManager = AISocketManager.getInstance(); const { messages, pushMessage, updateMessage } = useChatMessage(); const [inputDisabled, setInputDisabled] = useState(true); - // const { displayTold } = useTOLD('AI'); - const addMessage = ( type: 'left' | 'right', options: { message?: string; tarotId?: number; button?: MessageButton }, @@ -40,15 +37,11 @@ export function useAiChatMessage() { socketManager.on('tarotCard', () => setInputDisabled(true)); - // const requestFeedbackMessage = '์ด๋ฒˆ ์ƒ๋‹ด์€ ์–ด๋• ์–ด?\nํ”ผ๋“œ๋ฐฑ์„ ๋‚จ๊ฒจ์ฃผ๋ฉด ๋‚ด๊ฐ€ ๋” ๋ฐœ์ „ํ•  ์ˆ˜ ์žˆ์–ด!'; - // const button = { content: 'ํ”ผ๋“œ๋ฐฑํ•˜๊ธฐ', onClick: displayTold }; - socketManager.on('chatEnd', (id: string) => { setInputDisabled(true); const shareLinkId: string = id; updateMessage(message => ({ ...message, shareLinkId })); - // setTimeout(() => addMessage('left', { message: requestFeedbackMessage, button }), 5000); }); }, []); diff --git a/frontend/src/business/hooks/useTarotSpread/useAiTarotSpread.tsx b/frontend/src/business/hooks/useTarotSpread/useAiTarotSpread.tsx index 88fb2277..47bf9cc1 100644 --- a/frontend/src/business/hooks/useTarotSpread/useAiTarotSpread.tsx +++ b/frontend/src/business/hooks/useTarotSpread/useAiTarotSpread.tsx @@ -5,7 +5,7 @@ import { AISocketManager } from '@business/services/SocketManager'; import { useTarotSpread } from './useTarotSpread'; export function useAiTarotSpread(onPickCard: (idx: number) => void) { - const socketManager = new AISocketManager(); + const socketManager = AISocketManager.getInstance(); const pickCard = (idx: number) => { socketManager.emit('tarotRead', idx); diff --git a/frontend/src/business/hooks/useWebRTC/useSignalingSocket.ts b/frontend/src/business/hooks/useWebRTC/useSignalingSocket.ts index 5f590b79..b37a064f 100644 --- a/frontend/src/business/hooks/useWebRTC/useSignalingSocket.ts +++ b/frontend/src/business/hooks/useWebRTC/useSignalingSocket.ts @@ -2,7 +2,7 @@ import { usePasswordPopup } from '@business/hooks/usePopup'; import { HumanSocketManager } from '@business/services/SocketManager'; export function useSignalingSocket() { - const socketManager = new HumanSocketManager(); + const socketManager = HumanSocketManager.getInstance(); const { openPasswordPopup } = usePasswordPopup(); const createRoom = ({ diff --git a/frontend/src/business/services/Socket.ts b/frontend/src/business/services/Socket.ts index 89c21c8d..cf31ecf3 100644 --- a/frontend/src/business/services/Socket.ts +++ b/frontend/src/business/services/Socket.ts @@ -6,7 +6,7 @@ import { HumanSocketManager } from './SocketManager'; const webRTC = WebRTC.getInstace(); -const socketManager = new HumanSocketManager(); +const socketManager = HumanSocketManager.getInstance(); interface initSignalingSocketParams { roomName: string; diff --git a/frontend/src/business/services/SocketManager/AISocketManager.ts b/frontend/src/business/services/SocketManager/AISocketManager.ts index f73c9647..30246ee9 100644 --- a/frontend/src/business/services/SocketManager/AISocketManager.ts +++ b/frontend/src/business/services/SocketManager/AISocketManager.ts @@ -3,10 +3,19 @@ import { AIClientEvent, AIServerEvent } from '@tarotmilktea/ai-socketio-event'; import SocketManager from './SocketManager'; class AISocketManager extends SocketManager { - constructor() { + static instance: AISocketManager | null = null; + + private constructor() { super(import.meta.env.VITE_WAS_URL); } + static getInstance(): AISocketManager { + if (!this.instance) { + this.instance = new AISocketManager(); + } + return this.instance; + } + on(eventName: AIServerEvent, eventListener: (args: U) => void) { super.on(eventName, eventListener); } diff --git a/frontend/src/business/services/SocketManager/HumanSocketManager.ts b/frontend/src/business/services/SocketManager/HumanSocketManager.ts index cd8cec12..45160a67 100644 --- a/frontend/src/business/services/SocketManager/HumanSocketManager.ts +++ b/frontend/src/business/services/SocketManager/HumanSocketManager.ts @@ -5,13 +5,17 @@ import SocketManager from './SocketManager'; class HumanSocketManager extends SocketManager { static instance: HumanSocketManager | null = null; - constructor() { - if (HumanSocketManager.instance) { - return HumanSocketManager.instance; - } + private constructor() { super(import.meta.env.VITE_HUMAN_SOCKET_URL, '/signal'); } + static getInstance(): HumanSocketManager { + if (!this.instance) { + this.instance = new HumanSocketManager(); + } + return this.instance; + } + on(eventName: HumanServerEvent, eventListener: (args: U) => void) { super.on(eventName, eventListener); } diff --git a/frontend/src/business/services/SocketManager/SocketManager.ts b/frontend/src/business/services/SocketManager/SocketManager.ts index 6e510995..f95e387b 100644 --- a/frontend/src/business/services/SocketManager/SocketManager.ts +++ b/frontend/src/business/services/SocketManager/SocketManager.ts @@ -1,7 +1,7 @@ import { Socket, io } from 'socket.io-client'; class SocketManager { - static #socket: Socket | undefined; + #socket: Socket | undefined; #url: string; #path?: string; @@ -12,7 +12,7 @@ class SocketManager { } get socket(): Socket | undefined { - return SocketManager.#socket; + return this.#socket; } get connected(): boolean { @@ -24,7 +24,7 @@ class SocketManager { if (this.socket) { this.socket.disconnect(); } - SocketManager.#socket = io(this.#url, { path: this.#path }); + this.#socket = io(this.#url, { path: this.#path }); } disconnect() { @@ -32,7 +32,7 @@ class SocketManager { throw new Error('์†Œ์ผ“์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.'); } this.socket.disconnect(); - SocketManager.#socket = undefined; + this.#socket = undefined; } on(eventName: string, eventListener: (args: U) => void) { diff --git a/frontend/src/business/services/WebRTC.ts b/frontend/src/business/services/WebRTC.ts index c92af529..60f67633 100644 --- a/frontend/src/business/services/WebRTC.ts +++ b/frontend/src/business/services/WebRTC.ts @@ -13,7 +13,7 @@ export default class WebRTC { private static instance: WebRTC | undefined; private nextDataChannelId = 0; - socketManager = new HumanSocketManager(); + socketManager = HumanSocketManager.getInstance(); constructor() {} diff --git a/frontend/src/pages/HumanChatPage/SettingPage.tsx b/frontend/src/pages/HumanChatPage/SettingPage.tsx index db203ce6..a149aec2 100644 --- a/frontend/src/pages/HumanChatPage/SettingPage.tsx +++ b/frontend/src/pages/HumanChatPage/SettingPage.tsx @@ -11,7 +11,7 @@ import { useSettingPageMediaOptinos } from './useSettingPageMediaOptions'; import { useSettingPageProfileNicknameSetting } from './useSettingPageProfileNicknameSetting'; export default function ChattingPage() { - const socketManager = new HumanSocketManager(); + const socketManager = HumanSocketManager.getInstance(); const navigate = useNavigate(); diff --git a/frontend/src/pages/HumanChatPage/useChattingPageCreateJoinRoomPopup.ts b/frontend/src/pages/HumanChatPage/useChattingPageCreateJoinRoomPopup.ts index 98c550dd..dc88190c 100644 --- a/frontend/src/pages/HumanChatPage/useChattingPageCreateJoinRoomPopup.ts +++ b/frontend/src/pages/HumanChatPage/useChattingPageCreateJoinRoomPopup.ts @@ -21,7 +21,7 @@ export function useChattingPageCreateJoinRoomPasswordPopup({ startWebRTC, }: OutletContext = useOutletContext(); - const humanSocket = new HumanSocketManager(); + const humanSocket = HumanSocketManager.getInstance(); const { createRoom, joinRoom, checkRoomExist } = useSignalingSocket(); const { roomName } = useParams(); diff --git a/frontend/src/pages/HumanChatPage/useHumanChatPageCreateRoomEvent.ts b/frontend/src/pages/HumanChatPage/useHumanChatPageCreateRoomEvent.ts index c74b5a8b..c0c2c008 100644 --- a/frontend/src/pages/HumanChatPage/useHumanChatPageCreateRoomEvent.ts +++ b/frontend/src/pages/HumanChatPage/useHumanChatPageCreateRoomEvent.ts @@ -10,7 +10,7 @@ export interface ChatPageState { host: boolean; } export function useHumanChatPageCreateRoomEvent() { - const humanSocket = new HumanSocketManager(); + const humanSocket = HumanSocketManager.getInstance(); const navigate = useNavigate(); const location = useLocation(); From c768250564dd045d003e68365f9878cc2165d1df Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Sun, 10 Dec 2023 19:23:19 +0900 Subject: [PATCH 31/67] =?UTF-8?q?remove:=20console.log=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/business/hooks/useWebRTC/useWebRTC.ts | 1 - frontend/src/business/services/Socket.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts index 44a169b5..acb4a701 100644 --- a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts +++ b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts @@ -52,7 +52,6 @@ export default function useWebRTC() { if (!remoteVideoRef.current || !webRTC.remoteStream) { return; } - console.log('chanted track'); remoteVideoRef.current.srcObject = webRTC.remoteStream as MediaStream; }, [webRTC.remoteStream?.id]); diff --git a/frontend/src/business/services/Socket.ts b/frontend/src/business/services/Socket.ts index cf31ecf3..3938ae3e 100644 --- a/frontend/src/business/services/Socket.ts +++ b/frontend/src/business/services/Socket.ts @@ -42,7 +42,6 @@ export const initSignalingSocket = ({ roomName, onExitUser }: initSignalingSocke }); socketManager.on('userExit', async () => { - console.log('userExit'); onExitUser(); }); }; From 5fe904e1eeb0c14228de23df042e3076f224f6bb Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Sun, 10 Dec 2023 20:42:26 +0900 Subject: [PATCH 32/67] =?UTF-8?q?refactor:=20if=EB=AC=B8=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=20=EC=9D=BD=EA=B8=B0=EC=89=BD=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ๊ทธ๋Œ€๋กœ ๋‚˜์—ด๋˜์–ด ์žˆ๋Š”๊ฑธ ๋ณ€์ˆ˜ ์ด๋ฆ„์„ ๋ณด๊ธฐ ์‰ฝ๋„๋ก ๋ฐ”๊ฟˆ --- .../src/pages/HumanChatPage/ChattingPage.tsx | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/frontend/src/pages/HumanChatPage/ChattingPage.tsx b/frontend/src/pages/HumanChatPage/ChattingPage.tsx index 8befb6b2..a8b4129e 100644 --- a/frontend/src/pages/HumanChatPage/ChattingPage.tsx +++ b/frontend/src/pages/HumanChatPage/ChattingPage.tsx @@ -31,24 +31,16 @@ export default function ChattingPage() { }, [joined]); useEffect(() => { - if ( - !remoteVideoRef.current || - !webRTC.remoteStream || - (remoteVideoRef.current.srcObject as MediaStream)?.id === webRTC.remoteStream?.id - ) { + const existRemoteVideo = remoteVideoRef.current; + const existRemoteStream = webRTC.remoteStream; + const remoteStreamChanged = (remoteVideoRef.current?.srcObject as MediaStream)?.id !== webRTC.remoteStream?.id; + if (!existRemoteVideo || !existRemoteStream || !remoteStreamChanged) { return; } remoteVideoRef.current.srcObject = webRTC.remoteStream as MediaStream; }, [remoteVideoRef.current]); - // useEffect(() => { - // if (!remoteVideoRef.current || !webRTC.remoteStream) { - // return; - // } - // remoteVideoRef.current.srcObject = webRTC.remoteStream as MediaStream; - // }, [webRTC.remoteStream?.id, remoteVideoRef.current]); - useChattingPageCreateJoinRoomPasswordPopup({ unblockGoBack, enableSideBar }); const navigate = useNavigate(); From 9c67f2e1b3f956e951e56d7472504394f135a4da Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Sun, 10 Dec 2023 20:43:28 +0900 Subject: [PATCH 33/67] =?UTF-8?q?fix:=20SettingPage=20=EC=B9=B4=EB=A9=94?= =?UTF-8?q?=EB=9D=BC=20=EC=84=A0=ED=83=9D=20=EC=A0=9C=EB=8C=80=EB=A1=9C=20?= =?UTF-8?q?=EB=90=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95=ED=95=A8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SettingPage์—์„œ ์นด๋ฉ”๋ผ๋‚˜ ์˜ค๋””์˜ค ์„ ํƒ์‹œ ์ „์—ญ์ƒํƒœ์— ์ €์žฅ์ด ์•ˆ๋์Œ. - ๊ทธ๋ž˜์„œ ์ „์—ญ์ƒํƒœ์— ์ €์žฅ์„ ํ•˜๊ณ , ๊ทธ ๊ฐ’์„ ๋ฐ›์•„์™€ ๊ฐ’์ด ์žˆ์œผ๋ฉด ๊ทธ ๊ฐ’์„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ง€์ •ํ•ด์คŒ --- .../business/hooks/useWebRTC/useControllMedia.ts | 13 ++++++++++--- .../src/components/ProfileSetting/DeviceSelect.tsx | 4 +++- .../components/ProfileSetting/ProfileSetting.tsx | 8 +++++--- frontend/src/components/Select/Select.tsx | 6 ++++-- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/frontend/src/business/hooks/useWebRTC/useControllMedia.ts b/frontend/src/business/hooks/useWebRTC/useControllMedia.ts index 071ec2af..eb032288 100644 --- a/frontend/src/business/hooks/useWebRTC/useControllMedia.ts +++ b/frontend/src/business/hooks/useWebRTC/useControllMedia.ts @@ -14,9 +14,10 @@ const toggleTrack = (track: MediaStreamTrack) => { export function useControllMedia({ localVideoRef }: useContorollMediaParams) { const { - selectedCameraID, toggleMyMic: toggleMyMicState, toggleMyVideo: toggleMyVideoState, + setSelectedAudioID, + setSelectedCameraID, } = useMediaInfo(state => ({ toggleMyVideo: state.toggleMyVideo, toggleMyMic: state.toggleMyMic, @@ -73,9 +74,12 @@ export function useControllMedia({ localVideoRef }: useContorollMediaParams) { mediaInfoChannel.send(JSON.stringify([{ type: 'audio', onOrOff: audioTrackenabled }])); }; - const changeMyVideoTrack = async () => { - const stream = await getLocalStream({ cameraID: selectedCameraID }); + const changeMyVideoTrack = async (id?: string) => { + const stream = await getLocalStream({ cameraID: id }); + if (id) { + setSelectedCameraID(id); + } setLocalVideoSrcObj(stream); webRTC.setLocalStream(stream); webRTC.replacePeerconnectionVideoTrack2NowLocalStream(); @@ -84,6 +88,9 @@ export function useControllMedia({ localVideoRef }: useContorollMediaParams) { const changeMyAudioTrack = async (id?: string) => { const stream = await getLocalStream({ audioID: id }); + if (id) { + setSelectedAudioID(id); + } setLocalVideoSrcObj(stream); webRTC.setLocalStream(stream); webRTC.replacePeerconnectionAudioTrack2NowLocalStream(); diff --git a/frontend/src/components/ProfileSetting/DeviceSelect.tsx b/frontend/src/components/ProfileSetting/DeviceSelect.tsx index 5bf6cde9..621dcd42 100644 --- a/frontend/src/components/ProfileSetting/DeviceSelect.tsx +++ b/frontend/src/components/ProfileSetting/DeviceSelect.tsx @@ -4,9 +4,10 @@ interface DeviceSelectProps { name: string; deviceList: SelectOptions[]; onChange: (deviceId: string) => void; + defaultId?: string; } -export default function DeviceSelect({ name, deviceList, onChange }: DeviceSelectProps) { +export default function DeviceSelect({ name, deviceList, defaultId, onChange }: DeviceSelectProps) { return (
    ์‚ฌ์šฉํ•  {name} ์žฅ์น˜๋ฅผ ์„ ํƒํ•˜์„ธ์š”. @@ -14,6 +15,7 @@ export default function DeviceSelect({ name, deviceList, onChange }: DeviceSelec width="w-full" options={deviceList} onChange={({ value }) => onChange(value)} + defaultId={defaultId} />
    ); diff --git a/frontend/src/components/ProfileSetting/ProfileSetting.tsx b/frontend/src/components/ProfileSetting/ProfileSetting.tsx index 08d7a138..d93cb2bf 100644 --- a/frontend/src/components/ProfileSetting/ProfileSetting.tsx +++ b/frontend/src/components/ProfileSetting/ProfileSetting.tsx @@ -39,11 +39,11 @@ export default function ProfileSetting({ myProfile: state.myProfile, })); - const { myMicOn, myVideoOn } = useMediaInfo(state => ({ + const { myMicOn, myVideoOn, selectedAudioID, selectedCameraID } = useMediaInfo(state => ({ myMicOn: state.myMicOn, myVideoOn: state.myVideoOn, - remoteMicOn: state.remoteMicOn, - remoteVideoOn: state.remoteVideoOn, + selectedAudioID: state.selectedAudioID, + selectedCameraID: state.selectedCameraID, })); return ( @@ -85,6 +85,7 @@ export default function ProfileSetting({ name="์นด๋ฉ”๋ผ" deviceList={camList} onChange={changeMyCamera} + defaultId={selectedCameraID} />
    @@ -92,6 +93,7 @@ export default function ProfileSetting({ name="๋งˆ์ดํฌ" deviceList={micList} onChange={changeMyAudio} + defaultId={selectedAudioID} />
    diff --git a/frontend/src/components/Select/Select.tsx b/frontend/src/components/Select/Select.tsx index 9ad2d2c2..bd62ec53 100644 --- a/frontend/src/components/Select/Select.tsx +++ b/frontend/src/components/Select/Select.tsx @@ -10,18 +10,20 @@ export interface SelectOptions { interface SelectProps { width?: string; options: SelectOptions[]; + defaultId?: string; autoFocus?: boolean; onChange?: ({ value, label }: SelectOptions) => void; } -export default function Select({ width, options, autoFocus, onChange }: SelectProps) { +export default function Select({ width, options, autoFocus, defaultId, onChange }: SelectProps) { const [opened, setOpened] = useState(false); const inputRef = useRef(null); const [selected, setSelected] = useState({ value: '', label: '' }); useEffect(() => { if (options.length && !selected.value && !selected.label) { - setSelected(options[0]); + const defaultOption = options.find(({ value }) => value === defaultId); + setSelected(defaultOption ?? options[0]); } }, [options]); From c2c28c94556e749059fe556c2e74d9804798cf0e Mon Sep 17 00:00:00 2001 From: KimYujeong Date: Mon, 11 Dec 2023 17:55:12 +0900 Subject: [PATCH 34/67] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜ ๋ฐ ๊ธฐ์ˆ  ์Šคํƒ ์—…๋ฐ์ดํŠธ --- README.md | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b184733f..23733c26 100644 --- a/README.md +++ b/README.md @@ -38,11 +38,69 @@ +
    ## ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜ +
    + +
    -![image](https://github.com/boostcampwm2023/web09-MagicConch/assets/78946499/dee03d42-2b4d-4bcd-bdfa-dc10f06e973a) +
    + +## ๊ธฐ์ˆ  ์Šคํƒ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ๊ตฌ๋ถ„๊ธฐ์ˆ  ์Šคํƒ
    common + + + + + +
    frontend + + + + + +
    backend + + +
    DB + +
    CI/CD + +
    deployment + + + + +

    From 1e69f26c049ca803b39cf305777191d0a837d3e3 Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Mon, 11 Dec 2023 19:04:04 +0900 Subject: [PATCH 35/67] docs: Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ์ฃผ์š”๊ธฐ๋Šฅ ์„ค๋ช… ์ถ”๊ฐ€ --- README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/README.md b/README.md index 23733c26..b16dd14e 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,36 @@
    +## ์ฃผ์š”๊ธฐ๋Šฅ +### AI์—๊ฒŒ ์ƒ๋‹ดํ•˜๊ธฐ + +https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/862982e4-8a8f-460a-a966-f81c285afdcf + +### ์ƒ๋‹ด ๊ฒฐ๊ณผ ๊ณต์œ ํ•˜๊ธฐ + +https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/12967650-654e-47e8-aa81-6ef6b34f7a92 + +3 แ„แ…กแ„แ…กแ„‹แ…ฉแ„แ…ฉแ†จแ„‹แ…ณแ„…แ…ฉ แ„€แ…ฉแ†ผแ„‹แ…ฒแ„€แ…ก แ„ƒแ…ฌแ†ซแ„ƒแ…ก +### ๋ฐฉ ์ƒ์„ฑ ํ›„ ์˜ฌ๋ฐ”๋ฅธ ์•”ํ˜ธ ์ž…๋ ฅํ•ด์•ผ ์ž…์žฅ ๊ฐ€๋Šฅ + +https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/9471a299-1256-4a43-8796-077154453642 + +### ๋ฐฉ์—๋Š” ์ตœ๋Œ€ 2๋ช…๋งŒ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ์Œ + +https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/df87cf58-08a2-4975-be6f-ce9fb13f8cef + +### ๋‹‰๋„ค์ž„๊ณผ ํ”„๋กœํ•„ ์‚ฌ์ง„์˜ ์„ค์ •์ด ๊ฐ€๋Šฅํ•จ + +https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/28b8975a-ab5a-4ad6-b1cf-8a78af6e1407 + +### ํ˜ธ์ŠคํŠธ๊ฐ€ ๊ฒŒ์ŠคํŠธ์—๊ฒŒ ์นด๋“œ๋ฅผ ๋ฝ‘๊ฒŒํ•˜๊ณ , ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Œ + +https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/f4d3c979-a655-429f-9652-30e908eacce5 + +### ์ฑ„ํŒ…๊ธฐ๋Šฅ + +https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/c1943d53-efda-4b65-b7e4-919872eacad3 + ## ๊ธฐ์ˆ  ์Šคํƒ From ebf9e8c722e4afc8d8f2586e86ce3ac72025eedc Mon Sep 17 00:00:00 2001 From: KimYujeong Date: Mon, 11 Dec 2023 19:20:39 +0900 Subject: [PATCH 36/67] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ ์—…๋ฐ์ดํŠธ --- README.md | 90 +++++++++++++++++++++++++++---------------------------- 1 file changed, 44 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index b16dd14e..f4733a89 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,9 @@ -# ๐Ÿš AI ํƒ€๋กœ ์ƒ๋‹ด ํ”Œ๋žซํผ, ๋งˆ๋ฒ•์˜ ์†Œ๋ผ๊ณ ๋‘ฅ +

    +
    + + AI ํƒ€๋กœ ์ƒ๋‹ด ํ”Œ๋žซํผ, ๋งˆ๋ฒ•์˜ ์†Œ๋ผ๊ณ ๋‘ฅ +
    +

    @@ -6,78 +11,71 @@
    -## ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ - - - -
    - -## ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜ -
    - +
    +

    +
    ๐Ÿ”ฎ ๋งค๋ ฅ์ ์ธ ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ ํ•จ๊ป˜ ์ฆ๊ธฐ๋Š” AIโ€ข์‹ค์‹œ๊ฐ„ ํ™”์ƒ ํƒ€๋กœ ์ƒ๋‹ด ๐ŸŒ 
    +

    +
    ํ•œ ๋ฒˆ์ฏค์€ ํƒ€๋กœ ์ ์„ ์ณ๋ณด๊ณ  ์‹ถ์ง€๋งŒ, ์‹œ๊ฐ„๊ณผ ๋ˆ์„ ํˆฌ์žํ•˜๋ฉด์„œ ๋ณด๊ธด ๊ท€์ฐฎ์•„..."
    +
    +
    ๊ฑฑ์ •ํ•˜์ง€ ๋งˆ์„ธ์š”! AI ํƒ€๋กœ ์ƒ๋‹ด์‚ฌ์™€ ํ•จ๊ป˜ ์–ธ์ œ ์–ด๋””์„œ๋“  ๋ฌด๋ฃŒ๋กœ ํƒ€๋กœ ์ƒ๋‹ด์„ ์ฆ๊ธธ ์ˆ˜ ์žˆ์–ด์š” ๐Ÿ’ซ
    ์›ํ•˜๋Š” ํƒ€๋กœ ์ƒ๋‹ด์‚ฌ์™€ ์‹ค์‹œ๊ฐ„ ํ™”์ƒ ํƒ€๋กœ ์ƒ๋‹ด๋„ ๊ฐ€๋Šฅํ•˜๋‹ต๋‹ˆ๋‹ค.
    ๊ณ ๋ฏผ์ด๋‚˜ ๊ถ๊ธˆ์ฆ, ์–ด๋–ค ์ฃผ์ œ๋“  ์ž์œ ๋กญ๊ฒŒ ์ด์•ผ๊ธฐํ•ด๋ณด์„ธ์š”! ๐ŸŒŒ
    +
    +
    ํ•จ๊ป˜ ๋‚˜๋ˆ„๋Š” ์ด์•ผ๊ธฐ๋ฅผ ํ†ตํ•ด, ๋” ๋‚˜์€ ๋ฏธ๋ž˜๋ฅผ ์ƒ์ƒํ•˜๋Š” ์‹œ๊ฐ„์ด ๋˜๊ธธ ๋ฐ”๋ผ์š” ๐Ÿ”ฎ
    ์ƒ๋™์ ์ธ ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ ํ•จ๊ป˜, ๋‹น์‹ ๋งŒ์˜ ํŠน๋ณ„ํ•œ ํƒ€๋กœ ์ฒดํ—˜์„ ์ฆ๊ฒจ๋ณด์„ธ์š”โœจ
    +

    +

    ## ์ฃผ์š”๊ธฐ๋Šฅ -### AI์—๊ฒŒ ์ƒ๋‹ดํ•˜๊ธฐ +#### AI์—๊ฒŒ ์ƒ๋‹ดํ•˜๊ธฐ https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/862982e4-8a8f-460a-a966-f81c285afdcf -### ์ƒ๋‹ด ๊ฒฐ๊ณผ ๊ณต์œ ํ•˜๊ธฐ +#### ์ƒ๋‹ด ๊ฒฐ๊ณผ ๊ณต์œ ํ•˜๊ธฐ https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/12967650-654e-47e8-aa81-6ef6b34f7a92 3 แ„แ…กแ„แ…กแ„‹แ…ฉแ„แ…ฉแ†จแ„‹แ…ณแ„…แ…ฉ แ„€แ…ฉแ†ผแ„‹แ…ฒแ„€แ…ก แ„ƒแ…ฌแ†ซแ„ƒแ…ก -### ๋ฐฉ ์ƒ์„ฑ ํ›„ ์˜ฌ๋ฐ”๋ฅธ ์•”ํ˜ธ ์ž…๋ ฅํ•ด์•ผ ์ž…์žฅ ๊ฐ€๋Šฅ + +#### ๋ฐฉ ์ƒ์„ฑ ํ›„ ์˜ฌ๋ฐ”๋ฅธ ์•”ํ˜ธ ์ž…๋ ฅํ•ด์•ผ ์ž…์žฅ ๊ฐ€๋Šฅ https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/9471a299-1256-4a43-8796-077154453642 -### ๋ฐฉ์—๋Š” ์ตœ๋Œ€ 2๋ช…๋งŒ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ์Œ +#### ๋ฐฉ์—๋Š” ์ตœ๋Œ€ 2๋ช…๋งŒ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ์Œ https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/df87cf58-08a2-4975-be6f-ce9fb13f8cef -### ๋‹‰๋„ค์ž„๊ณผ ํ”„๋กœํ•„ ์‚ฌ์ง„์˜ ์„ค์ •์ด ๊ฐ€๋Šฅํ•จ +#### ๋‹‰๋„ค์ž„๊ณผ ํ”„๋กœํ•„ ์‚ฌ์ง„์˜ ์„ค์ •์ด ๊ฐ€๋Šฅํ•จ https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/28b8975a-ab5a-4ad6-b1cf-8a78af6e1407 -### ํ˜ธ์ŠคํŠธ๊ฐ€ ๊ฒŒ์ŠคํŠธ์—๊ฒŒ ์นด๋“œ๋ฅผ ๋ฝ‘๊ฒŒํ•˜๊ณ , ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Œ +#### ํ˜ธ์ŠคํŠธ๊ฐ€ ๊ฒŒ์ŠคํŠธ์—๊ฒŒ ์นด๋“œ๋ฅผ ๋ฝ‘๊ฒŒํ•˜๊ณ , ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Œ https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/f4d3c979-a655-429f-9652-30e908eacce5 -### ์ฑ„ํŒ…๊ธฐ๋Šฅ +#### ์ฑ„ํŒ…๊ธฐ๋Šฅ https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/c1943d53-efda-4b65-b7e4-919872eacad3 +
    + +## ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜ +
    + +
    + +
    + ## ๊ธฐ์ˆ  ์Šคํƒ
    ๊ตฌ๋ถ„
    From 53029f19d5febf24ebbced30a7dd6ac310629d00 Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Mon, 11 Dec 2023 19:29:20 +0900 Subject: [PATCH 37/67] docs: Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ๊ฐ€์šด๋ฐ ์ •๋ ฌ + ๋งํฌ ๋ณ€๊ฒฝ --- README.md | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index f4733a89..d369b090 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@
    -
    +

    ๐Ÿ”ฎ ๋งค๋ ฅ์ ์ธ ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ ํ•จ๊ป˜ ์ฆ๊ธฐ๋Š” AIโ€ข์‹ค์‹œ๊ฐ„ ํ™”์ƒ ํƒ€๋กœ ์ƒ๋‹ด ๐ŸŒ 

    @@ -20,18 +20,11 @@
    ๊ฑฑ์ •ํ•˜์ง€ ๋งˆ์„ธ์š”! AI ํƒ€๋กœ ์ƒ๋‹ด์‚ฌ์™€ ํ•จ๊ป˜ ์–ธ์ œ ์–ด๋””์„œ๋“  ๋ฌด๋ฃŒ๋กœ ํƒ€๋กœ ์ƒ๋‹ด์„ ์ฆ๊ธธ ์ˆ˜ ์žˆ์–ด์š” ๐Ÿ’ซ
    ์›ํ•˜๋Š” ํƒ€๋กœ ์ƒ๋‹ด์‚ฌ์™€ ์‹ค์‹œ๊ฐ„ ํ™”์ƒ ํƒ€๋กœ ์ƒ๋‹ด๋„ ๊ฐ€๋Šฅํ•˜๋‹ต๋‹ˆ๋‹ค.
    ๊ณ ๋ฏผ์ด๋‚˜ ๊ถ๊ธˆ์ฆ, ์–ด๋–ค ์ฃผ์ œ๋“  ์ž์œ ๋กญ๊ฒŒ ์ด์•ผ๊ธฐํ•ด๋ณด์„ธ์š”! ๐ŸŒŒ

    ํ•จ๊ป˜ ๋‚˜๋ˆ„๋Š” ์ด์•ผ๊ธฐ๋ฅผ ํ†ตํ•ด, ๋” ๋‚˜์€ ๋ฏธ๋ž˜๋ฅผ ์ƒ์ƒํ•˜๋Š” ์‹œ๊ฐ„์ด ๋˜๊ธธ ๋ฐ”๋ผ์š” ๐Ÿ”ฎ
    ์ƒ๋™์ ์ธ ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ ํ•จ๊ป˜, ๋‹น์‹ ๋งŒ์˜ ํŠน๋ณ„ํ•œ ํƒ€๋กœ ์ฒดํ—˜์„ ์ฆ๊ฒจ๋ณด์„ธ์š”โœจ
    -

    - +

    + +[์„œ๋น„์Šค](https://web09-magicconch.pages.dev) +[ํŒ€ ๋…ธํŠธ](https://season-broccoli-784.notion.site/Team-note-9d1bcc23f7ba463384fae13743f42c16?pvs=4) +[์œ„ํ‚ค](https://github.com/boostcampwm2023/web09-MagicConch/wiki)

    From 09ab209330cdc8d76d3b4dd45fcd77e0bde97d74 Mon Sep 17 00:00:00 2001 From: KimYujeong Date: Mon, 11 Dec 2023 20:24:36 +0900 Subject: [PATCH 38/67] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ์ œ๋ชฉ ๋ฐ ๋งํฌ ๋ ˆ์ด์•„์›ƒ ์ˆ˜์ • --- README.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index d369b090..a47d40c5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

    - AI ํƒ€๋กœ ์ƒ๋‹ด ํ”Œ๋žซํผ, ๋งˆ๋ฒ•์˜ ์†Œ๋ผ๊ณ ๋‘ฅ + AI โ€ข ์‹ค์‹œ๊ฐ„ ํ™”์ƒ ํƒ€๋กœ ์ƒ๋‹ด ์ƒ๋‹ด ํ”Œ๋žซํผ, ๋งˆ๋ฒ•์˜ ์†Œ๋ผ๊ณ ๋‘ฅ

    @@ -15,16 +15,21 @@

    ๐Ÿ”ฎ ๋งค๋ ฅ์ ์ธ ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ ํ•จ๊ป˜ ์ฆ๊ธฐ๋Š” AIโ€ข์‹ค์‹œ๊ฐ„ ํ™”์ƒ ํƒ€๋กœ ์ƒ๋‹ด ๐ŸŒ 

    -
    ํ•œ ๋ฒˆ์ฏค์€ ํƒ€๋กœ ์ ์„ ์ณ๋ณด๊ณ  ์‹ถ์ง€๋งŒ, ์‹œ๊ฐ„๊ณผ ๋ˆ์„ ํˆฌ์žํ•˜๋ฉด์„œ ๋ณด๊ธด ๊ท€์ฐฎ์•„..."
    +
    "ํ•œ ๋ฒˆ์ฏค์€ ํƒ€๋กœ ์ ์„ ์ณ๋ณด๊ณ  ์‹ถ์ง€๋งŒ, ์‹œ๊ฐ„๊ณผ ๋ˆ์„ ํˆฌ์žํ•˜๋ฉด์„œ ๋ณด๊ธด ๊ท€์ฐฎ์•„..."

    -
    ๊ฑฑ์ •ํ•˜์ง€ ๋งˆ์„ธ์š”! AI ํƒ€๋กœ ์ƒ๋‹ด์‚ฌ์™€ ํ•จ๊ป˜ ์–ธ์ œ ์–ด๋””์„œ๋“  ๋ฌด๋ฃŒ๋กœ ํƒ€๋กœ ์ƒ๋‹ด์„ ์ฆ๊ธธ ์ˆ˜ ์žˆ์–ด์š” ๐Ÿ’ซ
    ์›ํ•˜๋Š” ํƒ€๋กœ ์ƒ๋‹ด์‚ฌ์™€ ์‹ค์‹œ๊ฐ„ ํ™”์ƒ ํƒ€๋กœ ์ƒ๋‹ด๋„ ๊ฐ€๋Šฅํ•˜๋‹ต๋‹ˆ๋‹ค.
    ๊ณ ๋ฏผ์ด๋‚˜ ๊ถ๊ธˆ์ฆ, ์–ด๋–ค ์ฃผ์ œ๋“  ์ž์œ ๋กญ๊ฒŒ ์ด์•ผ๊ธฐํ•ด๋ณด์„ธ์š”! ๐ŸŒŒ
    +
    ๊ฑฑ์ •ํ•˜์ง€ ๋งˆ์„ธ์š”!
    AI ํƒ€๋กœ ์ƒ๋‹ด์‚ฌ์™€ ํ•จ๊ป˜ ์–ธ์ œ ์–ด๋””์„œ๋“  ๋ฌด๋ฃŒ๋กœ ํƒ€๋กœ ์ƒ๋‹ด์„ ์ฆ๊ธธ ์ˆ˜ ์žˆ์–ด์š” ๐Ÿ’ซ
    ์›ํ•˜๋Š” ํƒ€๋กœ ์ƒ๋‹ด์‚ฌ์™€ ์‹ค์‹œ๊ฐ„ ํ™”์ƒ ํƒ€๋กœ ์ƒ๋‹ด๋„ ๊ฐ€๋Šฅํ•˜๋‹ต๋‹ˆ๋‹ค.
    ๊ณ ๋ฏผ์ด๋‚˜ ๊ถ๊ธˆ์ฆ, ์–ด๋–ค ์ฃผ์ œ๋“  ์ž์œ ๋กญ๊ฒŒ ์ด์•ผ๊ธฐํ•ด๋ณด์„ธ์š” ๐ŸŒŒ

    -
    ํ•จ๊ป˜ ๋‚˜๋ˆ„๋Š” ์ด์•ผ๊ธฐ๋ฅผ ํ†ตํ•ด, ๋” ๋‚˜์€ ๋ฏธ๋ž˜๋ฅผ ์ƒ์ƒํ•˜๋Š” ์‹œ๊ฐ„์ด ๋˜๊ธธ ๋ฐ”๋ผ์š” ๐Ÿ”ฎ
    ์ƒ๋™์ ์ธ ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ ํ•จ๊ป˜, ๋‹น์‹ ๋งŒ์˜ ํŠน๋ณ„ํ•œ ํƒ€๋กœ ์ฒดํ—˜์„ ์ฆ๊ฒจ๋ณด์„ธ์š”โœจ
    +
    ํ•จ๊ป˜ ๋‚˜๋ˆ„๋Š” ์ด์•ผ๊ธฐ๋ฅผ ํ†ตํ•ด, ๋” ๋‚˜์€ ๋ฏธ๋ž˜๋ฅผ ์ƒ์ƒํ•˜๋Š” ์‹œ๊ฐ„์ด ๋˜๊ธธ ๋ฐ”๋ผ์š” ๐Ÿ”ฎ
    ์ƒ๋™์ ์ธ ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ ํ•จ๊ป˜, ๋‹น์‹ ๋งŒ์˜ ํŠน๋ณ„ํ•œ ํƒ€๋กœ ์ฒดํ—˜์„ ์ฆ๊ฒจ๋ณด์„ธ์š” โœจ


    - -[์„œ๋น„์Šค](https://web09-magicconch.pages.dev) -[ํŒ€ ๋…ธํŠธ](https://season-broccoli-784.notion.site/Team-note-9d1bcc23f7ba463384fae13743f42c16?pvs=4) -[์œ„ํ‚ค](https://github.com/boostcampwm2023/web09-MagicConch/wiki) + +

    +

    From 690af4768f6ba1269987f0dbb7a7346ea41d3943 Mon Sep 17 00:00:00 2001 From: KimYujeong Date: Mon, 11 Dec 2023 20:26:03 +0900 Subject: [PATCH 39/67] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ์ œ๋ชฉ ๊ณต๋ฐฑ ์ œ๊ฑฐ --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a47d40c5..cb431a24 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

    - AI โ€ข ์‹ค์‹œ๊ฐ„ ํ™”์ƒ ํƒ€๋กœ ์ƒ๋‹ด ์ƒ๋‹ด ํ”Œ๋žซํผ, ๋งˆ๋ฒ•์˜ ์†Œ๋ผ๊ณ ๋‘ฅ + AIโ€ข์‹ค์‹œ๊ฐ„ ํ™”์ƒ ํƒ€๋กœ ์ƒ๋‹ด ์ƒ๋‹ด ํ”Œ๋žซํผ, ๋งˆ๋ฒ•์˜ ์†Œ๋ผ๊ณ ๋‘ฅ

    From 9c56d46b1f9aff810216ca56f01c6d2888929f53 Mon Sep 17 00:00:00 2001 From: KimYujeong Date: Mon, 11 Dec 2023 20:27:32 +0900 Subject: [PATCH 40/67] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ์˜คํƒ€ ์ˆ˜์ • --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cb431a24..eba8222a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@

    - - AIโ€ข์‹ค์‹œ๊ฐ„ ํ™”์ƒ ํƒ€๋กœ ์ƒ๋‹ด ์ƒ๋‹ด ํ”Œ๋žซํผ, ๋งˆ๋ฒ•์˜ ์†Œ๋ผ๊ณ ๋‘ฅ + + AIโ€ข์‹ค์‹œ๊ฐ„ ํ™”์ƒ ํƒ€๋กœ ์ƒ๋‹ด ํ”Œ๋žซํผ, ๋งˆ๋ฒ•์˜ ์†Œ๋ผ๊ณ ๋‘ฅ

    From 3bc540d5da3b7270a5907a142ed772d6beadc9d2 Mon Sep 17 00:00:00 2001 From: KimYujeong Date: Tue, 12 Dec 2023 00:25:31 +0900 Subject: [PATCH 41/67] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ๋ฉ”์ธ ์‚ฌ์ง„ ๋ณ€๊ฒฝ - ์ค„๋ฐ”๊ฟˆ ์ฒ˜๋ฆฌ - ์„œ๋น„์Šค ๋Œ€์ƒ ๋ฐ ๊ธฐ๋Œ€ํšจ๊ณผ ์ž‘์„ฑ --- README.md | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index eba8222a..1ea050c1 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,20 @@

    - + AIโ€ข์‹ค์‹œ๊ฐ„ ํ™”์ƒ ํƒ€๋กœ ์ƒ๋‹ด ํ”Œ๋žซํผ, ๋งˆ๋ฒ•์˜ ์†Œ๋ผ๊ณ ๋‘ฅ

    - +
    +

    -
    ๐Ÿ”ฎ ๋งค๋ ฅ์ ์ธ ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ ํ•จ๊ป˜ ์ฆ๊ธฐ๋Š” AIโ€ข์‹ค์‹œ๊ฐ„ ํ™”์ƒ ํƒ€๋กœ ์ƒ๋‹ด ๐ŸŒ 
    +
    ๐ŸŒ ๋งค๋ ฅ์ ์ธ ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ ํ•จ๊ป˜ ์ฆ๊ธฐ๋Š”๐ŸŒ 
    ๐Ÿ”ฎAIโ€ข์‹ค์‹œ๊ฐ„ ํ™”์ƒ ํƒ€๋กœ ์ƒ๋‹ด๐Ÿ”ฎ

    "ํ•œ ๋ฒˆ์ฏค์€ ํƒ€๋กœ ์ ์„ ์ณ๋ณด๊ณ  ์‹ถ์ง€๋งŒ, ์‹œ๊ฐ„๊ณผ ๋ˆ์„ ํˆฌ์žํ•˜๋ฉด์„œ ๋ณด๊ธด ๊ท€์ฐฎ์•„..."

    @@ -22,14 +23,23 @@
    ํ•จ๊ป˜ ๋‚˜๋ˆ„๋Š” ์ด์•ผ๊ธฐ๋ฅผ ํ†ตํ•ด, ๋” ๋‚˜์€ ๋ฏธ๋ž˜๋ฅผ ์ƒ์ƒํ•˜๋Š” ์‹œ๊ฐ„์ด ๋˜๊ธธ ๋ฐ”๋ผ์š” ๐Ÿ”ฎ
    ์ƒ๋™์ ์ธ ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ ํ•จ๊ป˜, ๋‹น์‹ ๋งŒ์˜ ํŠน๋ณ„ํ•œ ํƒ€๋กœ ์ฒดํ—˜์„ ์ฆ๊ฒจ๋ณด์„ธ์š” โœจ


    -

    +
    +

    +

    ๐Ÿ‘ญ ๋ˆ„๊ฐ€ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์„๊นŒ์š”?

    + ๊ณ ๋ฏผ์„ ํ„ธ์–ด๋†“๊ณ  ์‹ถ์€ ๋ถ„ ๐Ÿ—ฃ๏ธ
    + ๋ฏธ๋ž˜์— ๊ถ๊ธˆํ•œ ๊ฒŒ ์žˆ๋Š” ๋ถ„ ๐Ÿ”ฎ
    + ์˜จ๋ผ์ธ์—์„œ ๋ถ€์—…์„ ๊ฟˆ๊พธ๋Š” ๋ถ„
    +
    +

    ๐Ÿ‘ ์šฐ๋ฆฌ ์„œ๋น„์Šค์˜ ์žฅ์ 

    + AI ์ฑ—๋ด‡์„ ํ™œ์šฉํ•ด์„œ ์–ธ์ œ๋“ ์ง€ ํŽธํ•˜๊ฒŒ ํƒ€๋กœ ์ƒ๋‹ด์„ ๋ฐ›์•„๋ณผ ์ˆ˜ ์žˆ์–ด์š” ๐Ÿค–
    + ์‹ค์‹œ๊ฐ„ ํ™”์ƒ ์ฑ„ํŒ…์œผ๋กœ ๊ฑฐ๋ฆฌ์™€ ์ƒ๊ด€์—†์ด ํƒ€๋กœ ์ƒ๋‹ด์‚ฌ์™€ ์†Œํ†ตํ•  ์ˆ˜ ์žˆ์–ด์š” ๐ŸŒˆ

    From 5efe8b29f3d5bf8670cb569af6a5fe5089aeb80a Mon Sep 17 00:00:00 2001 From: KimYujeong Date: Tue, 12 Dec 2023 01:46:44 +0900 Subject: [PATCH 42/67] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ๋™์˜์ƒ์ด ์ž˜ ์•ˆ ๋– ์„œ ์œ„ํ‚ค์— ์‹œ๋‚˜๋ฆฌ์˜ค ํŽ˜์ด์ง€๋กœ ๋ถ„๋ฆฌ - ๋ฆฌ๋“œ๋ฏธ์—๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค ๋งํฌ๋งŒ ์ฒจ๋ถ€ - ์ฃผ์š” ๊ธฐ๋Šฅ ์‚ฌ์ง„ ์ฒจ๋ถ€ (์ถ”ํ›„ ๋‚ด์šฉ ์ข€ ๋” ๋ณด์™„ ํ•„์š”) --- README.md | 95 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 1ea050c1..dfa2ca84 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ ๐Ÿ—’๏ธํŒ€ ๋…ธ์…˜ | ๐ŸŒ ์œ„ํ‚ค + | + ๐ŸŽฅ์‹œ๋‚˜๋ฆฌ์˜ค
    @@ -45,35 +47,82 @@
    ## ์ฃผ์š”๊ธฐ๋Šฅ -#### AI์—๊ฒŒ ์ƒ๋‹ดํ•˜๊ธฐ - -https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/862982e4-8a8f-460a-a966-f81c285afdcf - -#### ์ƒ๋‹ด ๊ฒฐ๊ณผ ๊ณต์œ ํ•˜๊ธฐ - -https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/12967650-654e-47e8-aa81-6ef6b34f7a92 - -3 แ„แ…กแ„แ…กแ„‹แ…ฉแ„แ…ฉแ†จแ„‹แ…ณแ„…แ…ฉ แ„€แ…ฉแ†ผแ„‹แ…ฒแ„€แ…ก แ„ƒแ…ฌแ†ซแ„ƒแ…ก - -#### ๋ฐฉ ์ƒ์„ฑ ํ›„ ์˜ฌ๋ฐ”๋ฅธ ์•”ํ˜ธ ์ž…๋ ฅํ•ด์•ผ ์ž…์žฅ ๊ฐ€๋Šฅ - -https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/9471a299-1256-4a43-8796-077154453642 -#### ๋ฐฉ์—๋Š” ์ตœ๋Œ€ 2๋ช…๋งŒ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ์Œ +### ๐Ÿค– AI ํƒ€๋กœ ์ƒ๋‹ด ์„œ๋น„์Šค +> AI ์ฑ—๋ด‡์—๊ฒŒ ๊ณ ๋ฏผ์„ ํ„ธ์–ด๋†“๊ณ  ํƒ€๋กœ ์ƒ๋‹ด์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์–ด์š”. -https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/df87cf58-08a2-4975-be6f-ce9fb13f8cef - -#### ๋‹‰๋„ค์ž„๊ณผ ํ”„๋กœํ•„ ์‚ฌ์ง„์˜ ์„ค์ •์ด ๊ฐ€๋Šฅํ•จ - -https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/28b8975a-ab5a-4ad6-b1cf-8a78af6e1407 +
    ๊ตฌ๋ถ„
    + + + + + + + + + + + + +
    AI ์ฑ„ํŒ… ํ™”๋ฉด์นด๋“œ ๋ฝ‘๊ธฐ ํ™”๋ฉด๊ฒฐ๊ณผ ๊ณต์œ  ํ™”๋ฉด
    + + + + + +
    -#### ํ˜ธ์ŠคํŠธ๊ฐ€ ๊ฒŒ์ŠคํŠธ์—๊ฒŒ ์นด๋“œ๋ฅผ ๋ฝ‘๊ฒŒํ•˜๊ณ , ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Œ +
    -https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/f4d3c979-a655-429f-9652-30e908eacce5 -#### ์ฑ„ํŒ…๊ธฐ๋Šฅ +### ๐Ÿ—ฃ๏ธ ์‹ค์‹œ๊ฐ„ ํ™”์ƒ ํƒ€๋กœ ์ƒ๋‹ด ์„œ๋น„์Šค +> ํ™”์ƒ ์ƒ๋‹ด ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•˜์—ฌ ์‹ค์ œ ํƒ€๋กœ ์ƒ๋‹ด์‚ฌ์—๊ฒŒ ํƒ€๋กœ ์ƒ๋‹ด์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์–ด์š”.
    +> ์šฐ์ธก ์ƒ๋‹จ์˜ ์ฑ„ํŒ… ๋ฒ„ํŠผ์œผ๋กœ ํƒ€๋กœ ์นด๋“œ์™€ ํ•ด์„ค ๋‚ด์šฉ์„ ์ฃผ๊ณ  ๋ฐ›์„ ์ˆ˜๋„ ์žˆ์–ด์š”. -https://github.com/boostcampwm2023/web09-MagicConch/assets/43428643/c1943d53-efda-4b65-b7e4-919872eacad3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ํ˜ธ์ŠคํŠธ ํ™”๋ฉด (์ƒ๋‹ด์‚ฌ)๊ฒŒ์ŠคํŠธ ํ™”๋ฉด (์ƒ๋‹ด์ž)
    + + + +
    ํ˜ธ์ŠคํŠธ๊ฐ€ ํƒ€๋กœ ์ƒ๋‹ด์„ ์ง„ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์œ„ํ•ด ์ฑ„ํŒ…๋ฐฉ์„ ๊ฐœ์„คํ•ด์š”๊ฒŒ์ŠคํŠธ๊ฐ€ ํƒ€๋กœ ์ƒ๋‹ด์„ ๋ฐ›๊ธฐ ์œ„ํ•ด ์ฑ„ํŒ…๋ฐฉ์— ๋“ค์–ด๊ฐ€์š”
    + + + +
    ํ˜ธ์ŠคํŠธ๋Š” ๋ฐฉ์— ์ž…์žฅํ•  ๋•Œ ๋‹‰๋„ค์ž„ ๋ฐ ํ”„๋กœํ•„์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์–ด์š”๊ฒŒ์ŠคํŠธ๋Š” ๋ฐฉ์— ์ž…์žฅํ•  ๋•Œ ๋‹‰๋„ค์ž„ ๋ฐ ํ”„๋กœํ•„์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์–ด์š”
    + + + +
    ํ˜ธ์ŠคํŠธ๋Š” ํƒ€๋กœ ์นด๋“œ ํŽผ์น˜๊ธฐ ๋ฒ„ํŠผ์œผ๋กœ ๊ฒŒ์ŠคํŠธ์—๊ฒŒ ์นด๋“œ๋ฅผ ํŽผ์ณ์š”๊ฒŒ์ŠคํŠธ๋Š” ํŽผ์ณ์ง„ ์นด๋“œ ๋”๋ฏธ์—์„œ ํƒ€๋กœ ์นด๋“œ๋ฅผ ๋ฝ‘์„ ์ˆ˜ ์žˆ์–ด์š”

    From 07559e8bb755203b25d8a99e69b1a0f1129a19bb Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Tue, 12 Dec 2023 17:26:18 +0900 Subject: [PATCH 43/67] =?UTF-8?q?fix:=20=EC=86=8C=EC=BC=93=EC=9D=B4=20?= =?UTF-8?q?=EC=97=AC=EB=9F=AC=EB=B2=88=20=EC=9E=AC=EC=97=B0=EA=B2=B0=20?= =?UTF-8?q?=EB=90=98=EC=A7=80=20=EC=95=8A=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ๊ธฐ์กด์—๋Š” ์—ฌ๋Ÿฌ๋ฒˆ ์žฌ์—ฐ๊ฒฐ์ด ์ง„ํ–‰๋˜์—ˆ์Œ. --- frontend/src/business/services/SocketManager/SocketManager.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/business/services/SocketManager/SocketManager.ts b/frontend/src/business/services/SocketManager/SocketManager.ts index f95e387b..76cc16b9 100644 --- a/frontend/src/business/services/SocketManager/SocketManager.ts +++ b/frontend/src/business/services/SocketManager/SocketManager.ts @@ -21,8 +21,8 @@ class SocketManager { } connect() { - if (this.socket) { - this.socket.disconnect(); + if (this.socket?.connected) { + return; } this.#socket = io(this.#url, { path: this.#path }); } From c3529d1df190680033aa25f287529f7242e4fd33 Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Tue, 12 Dec 2023 17:27:57 +0900 Subject: [PATCH 44/67] =?UTF-8?q?refactor:=20useDataChannel=EC=9D=B4=20loc?= =?UTF-8?q?alVideoRef=EB=A5=BC=20=EB=B0=9B=EC=A7=80=20=EC=95=8A=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - WebRTC ๋ชจ๋“ˆ์˜ localStream์„ ์‚ฌ์šฉํ•˜๋ฉด๋จ --- .../src/business/hooks/useWebRTC/useDataChannel.ts | 13 +++++-------- frontend/src/business/hooks/useWebRTC/useWebRTC.ts | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/frontend/src/business/hooks/useWebRTC/useDataChannel.ts b/frontend/src/business/hooks/useWebRTC/useDataChannel.ts index 9109e9b5..c8e8414c 100644 --- a/frontend/src/business/hooks/useWebRTC/useDataChannel.ts +++ b/frontend/src/business/hooks/useWebRTC/useDataChannel.ts @@ -5,10 +5,7 @@ import { useProfileInfo } from '@stores/zustandStores/useProfileInfo'; import { array2ArrayBuffer } from '@utils/array'; -interface useDataChannelParams { - localVideoRef: React.RefObject; -} -export function useDataChannel({ localVideoRef }: useDataChannelParams) { +export function useDataChannel() { const { setRemoteMicOn, setRemoteVideoOn } = useMediaInfo(state => ({ setRemoteMicOn: state.setRemoteMicOn, setRemoteVideoOn: state.setRemoteVideoOn, @@ -38,13 +35,13 @@ export function useDataChannel({ localVideoRef }: useDataChannelParams) { }); mediaInfoChannel?.addEventListener('open', function () { - const audioTrack = localVideoRef.current?.srcObject as MediaStream; - const videoTrack = localVideoRef.current?.srcObject as MediaStream; + const audioTrack = webRTC.localStream?.getAudioTracks()[0]; + const videoTrack = webRTC.localStream?.getVideoTracks()[0]; mediaInfoChannel?.send( JSON.stringify([ - { type: 'audio', onOrOff: audioTrack.getAudioTracks()[0].enabled }, - { type: 'video', onOrOff: videoTrack.getVideoTracks()[0].enabled }, + { type: 'audio', onOrOff: audioTrack?.enabled }, + { type: 'video', onOrOff: videoTrack?.enabled }, ]), ); }); diff --git a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts index acb4a701..8e6510a2 100644 --- a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts +++ b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts @@ -14,7 +14,7 @@ export default function useWebRTC() { const { getLocalStream } = useMedia(); - const { initDataChannels } = useDataChannel({ localVideoRef }); + const { initDataChannels } = useDataChannel(); const startWebRTC = async ({ roomName }: { roomName: string }) => { if (webRTC.isConnectedPeerConnection()) { From 1b267fb845daf9fba7c0b25e8614b9c423e2a684 Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Tue, 12 Dec 2023 17:29:49 +0900 Subject: [PATCH 45/67] =?UTF-8?q?refactor:=20useHumanChatMessage,=20useHum?= =?UTF-8?q?anTarotSpread=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ์™ธ๋ถ€์—์„œ ๋ฐ์ดํ„ฐ ์ฑ„๋„์„ ๊ฐ€์ ธ์˜ค์ง€ ์•Š๊ณ  WebRTC์—์„œ ์ง์ ‘ ๊ฐ€์ ธ์˜ด --- .../business/hooks/useChatMessage/useHumanChatMessage.ts | 7 ++++++- .../business/hooks/useTarotSpread/useHumanTarotSpread.tsx | 6 +++++- frontend/src/pages/HumanChatPage/HumanChatPage.tsx | 7 ++----- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/frontend/src/business/hooks/useChatMessage/useHumanChatMessage.ts b/frontend/src/business/hooks/useChatMessage/useHumanChatMessage.ts index 1b2d45c5..30aec625 100644 --- a/frontend/src/business/hooks/useChatMessage/useHumanChatMessage.ts +++ b/frontend/src/business/hooks/useChatMessage/useHumanChatMessage.ts @@ -2,6 +2,8 @@ import { useEffect, useRef, useState } from 'react'; import { MessageButton } from '@components/ChatContainer'; +import WebRTC from '@business/services/WebRTC'; + import { ProfileInfo, useProfileInfo } from '@stores/zustandStores/useProfileInfo'; import { arrayBuffer2Blob } from '@utils/array'; @@ -12,7 +14,10 @@ import useChatMessage from './useChatMessage'; const { PICK_CARD, CHAT_MESSAGE } = HumanChatEvents; -export function useHumanChatMessage(chatChannel: RTCDataChannel | undefined) { +export function useHumanChatMessage() { + const { dataChannels } = WebRTC.getInstace(); + const chatChannel = dataChannels.get('chatChannel'); + const { messages, pushMessage } = useChatMessage(); const [inputDisabled, setInputDisabled] = useState(true); diff --git a/frontend/src/business/hooks/useTarotSpread/useHumanTarotSpread.tsx b/frontend/src/business/hooks/useTarotSpread/useHumanTarotSpread.tsx index 0cd5a447..54af11ab 100644 --- a/frontend/src/business/hooks/useTarotSpread/useHumanTarotSpread.tsx +++ b/frontend/src/business/hooks/useTarotSpread/useHumanTarotSpread.tsx @@ -3,6 +3,7 @@ import { useEffect, useState } from 'react'; import Popup from '@components/Popup'; import useOverlay from '@business/hooks/useOverlay'; +import WebRTC from '@business/services/WebRTC'; import { HumanChatEvents } from '@constants/events'; import { POPUP_MESSAGE } from '@constants/messages'; @@ -12,7 +13,10 @@ import { useTarotSpread } from './useTarotSpread'; const { PICK_CARD, TAROT_SPREAD } = HumanChatEvents; -export function useHumanTarotSpread(chatChannel: RTCDataChannel | undefined, onPickCard: (idx: number) => void) { +export function useHumanTarotSpread(onPickCard: (idx: number) => void) { + const { dataChannels } = WebRTC.getInstace(); + const chatChannel = dataChannels.get('chatChannel'); + const [tarotButtonDisabled, setTarotButtonDisabled] = useState(true); const pickCard = (idx: number) => { diff --git a/frontend/src/pages/HumanChatPage/HumanChatPage.tsx b/frontend/src/pages/HumanChatPage/HumanChatPage.tsx index 762927c6..f401a691 100644 --- a/frontend/src/pages/HumanChatPage/HumanChatPage.tsx +++ b/frontend/src/pages/HumanChatPage/HumanChatPage.tsx @@ -33,11 +33,8 @@ export default function HumanChatPage() { useHumanChatPageWrongURL(); const { chatPageState, setChatPageState } = useHumanChatPageCreateRoomEvent(); - const { dataChannels } = WebRTC.getInstace(); - const chatDataChannel = dataChannels.get('chatChannel'); - - const { messages, onSubmitMessage, inputDisabled, addPickCardMessage } = useHumanChatMessage(chatDataChannel); - const { tarotButtonClick, tarotButtonDisabled } = useHumanTarotSpread(chatDataChannel, addPickCardMessage); + const { messages, onSubmitMessage, inputDisabled, addPickCardMessage } = useHumanChatMessage(); + const { tarotButtonClick, tarotButtonDisabled } = useHumanTarotSpread(addPickCardMessage); const { changeContentAnimation, contentAnimation } = useHumanChatPageContentAnimation(); const [sideBarDisabled, setSideBarDisabled] = useState(false); From 58ee53c0887e246a4dd9a76da18062d040a9998a Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Tue, 12 Dec 2023 17:30:05 +0900 Subject: [PATCH 46/67] =?UTF-8?q?remove:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/pages/HumanChatPage/HumanChatPage.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/pages/HumanChatPage/HumanChatPage.tsx b/frontend/src/pages/HumanChatPage/HumanChatPage.tsx index f401a691..585ad7b1 100644 --- a/frontend/src/pages/HumanChatPage/HumanChatPage.tsx +++ b/frontend/src/pages/HumanChatPage/HumanChatPage.tsx @@ -28,7 +28,6 @@ export interface OutletContext extends ReturnType { export default function HumanChatPage() { const webRTCData = useWebRTC(); - useEffect(() => {}, [webRTCData.remoteVideoRef, webRTCData.remoteVideoRef.current]); useHumanChatPageWrongURL(); const { chatPageState, setChatPageState } = useHumanChatPageCreateRoomEvent(); From 272c3228fb136c054e6ad8a056b271d6dc29467e Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Tue, 12 Dec 2023 17:51:15 +0900 Subject: [PATCH 47/67] =?UTF-8?q?fix:=20=EC=86=8C=EC=BC=93=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0=20=EB=81=8A=EC=9D=84=20=EB=95=8C=20=EC=86=8C=EC=BC=93?= =?UTF-8?q?=EC=9D=B4=20=EC=97=86=EC=96=B4=EB=8F=84=20=EC=98=A4=EB=A5=98?= =?UTF-8?q?=EB=A5=BC=20=EB=B1=89=EC=A7=80=20=EC=95=8A=EC=9D=8C.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/business/services/SocketManager/SocketManager.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/business/services/SocketManager/SocketManager.ts b/frontend/src/business/services/SocketManager/SocketManager.ts index 76cc16b9..a4966898 100644 --- a/frontend/src/business/services/SocketManager/SocketManager.ts +++ b/frontend/src/business/services/SocketManager/SocketManager.ts @@ -28,8 +28,8 @@ class SocketManager { } disconnect() { - if (!this.socket) { - throw new Error('์†Œ์ผ“์ด ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.'); + if (!this.socket?.connected) { + return; } this.socket.disconnect(); this.#socket = undefined; From b782aaf1494bf25f81be0857244e2cad2ae7bce7 Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Tue, 12 Dec 2023 17:51:58 +0900 Subject: [PATCH 48/67] =?UTF-8?q?rafactor:=20useWebRTC=20ref=20=EB=B0=9B?= =?UTF-8?q?=EC=95=84=EC=98=A4=EB=8A=94=20=ED=9B=85=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?->=20useStreamVideoRef?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ๋”์ด์ƒ useWebRTC์—์„œ ๋‚˜์˜จ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„ ์“ธ ํ•„์š”๊ฐ€ ์—†์Œ. --- .../hooks/useWebRTC/useStreamVideoRef.tsx | 30 +++++++++++++++++++ .../src/business/hooks/useWebRTC/useWebRTC.ts | 15 +--------- .../src/pages/HumanChatPage/ChattingPage.tsx | 21 ++++--------- .../src/pages/HumanChatPage/SettingPage.tsx | 4 ++- .../pages/HumanChatPage/useHumanSocket.tsx | 13 ++++++++ 5 files changed, 52 insertions(+), 31 deletions(-) create mode 100644 frontend/src/business/hooks/useWebRTC/useStreamVideoRef.tsx create mode 100644 frontend/src/pages/HumanChatPage/useHumanSocket.tsx diff --git a/frontend/src/business/hooks/useWebRTC/useStreamVideoRef.tsx b/frontend/src/business/hooks/useWebRTC/useStreamVideoRef.tsx new file mode 100644 index 00000000..2c1afc3c --- /dev/null +++ b/frontend/src/business/hooks/useWebRTC/useStreamVideoRef.tsx @@ -0,0 +1,30 @@ +import { useEffect, useRef } from 'react'; + +import WebRTC from '@business/services/WebRTC'; + +export function useStreamVideoRef() { + const webRTC = WebRTC.getInstace(); + + const localVideoRef = useRef(null); + const remoteVideoRef = useRef(null); + + useEffect(() => { + if (!remoteVideoRef.current || !webRTC.remoteStream) { + return; + } + remoteVideoRef.current.srcObject = webRTC.remoteStream as MediaStream; + }, [webRTC.remoteStream?.id]); + + useEffect(() => { + const existRemoteVideo = remoteVideoRef.current; + const existRemoteStream = webRTC.remoteStream; + const remoteStreamChanged = (remoteVideoRef.current?.srcObject as MediaStream)?.id !== webRTC.remoteStream?.id; + if (!existRemoteVideo || !existRemoteStream || !remoteStreamChanged) { + return; + } + + remoteVideoRef.current.srcObject = webRTC.remoteStream as MediaStream; + }, [remoteVideoRef.current]); + + return { localVideoRef, remoteVideoRef }; +} diff --git a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts index 8e6510a2..d7534dbe 100644 --- a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts +++ b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts @@ -1,5 +1,5 @@ import WebRTC from '../../services/WebRTC'; -import { useEffect, useRef } from 'react'; +import { useEffect } from 'react'; import { initSignalingSocket } from '@business/services/Socket'; @@ -9,9 +9,6 @@ import { useMedia } from './useMedia'; export default function useWebRTC() { const webRTC = WebRTC.getInstace(); - const localVideoRef = useRef(null); - const remoteVideoRef = useRef(null); - const { getLocalStream } = useMedia(); const { initDataChannels } = useDataChannel(); @@ -23,7 +20,6 @@ export default function useWebRTC() { const stream = await getLocalStream(); webRTC.setLocalStream(stream); - localVideoRef.current!.srcObject = stream; initSignalingSocket({ roomName, @@ -48,16 +44,7 @@ export default function useWebRTC() { }; }, []); - useEffect(() => { - if (!remoteVideoRef.current || !webRTC.remoteStream) { - return; - } - remoteVideoRef.current.srcObject = webRTC.remoteStream as MediaStream; - }, [webRTC.remoteStream?.id]); - return { - localVideoRef, - remoteVideoRef, startWebRTC, }; } diff --git a/frontend/src/pages/HumanChatPage/ChattingPage.tsx b/frontend/src/pages/HumanChatPage/ChattingPage.tsx index a8b4129e..b838fe2e 100644 --- a/frontend/src/pages/HumanChatPage/ChattingPage.tsx +++ b/frontend/src/pages/HumanChatPage/ChattingPage.tsx @@ -5,6 +5,7 @@ import { IconButton } from '@components/Buttons'; import CamContainer from '@components/CamContainer'; import { useControllMedia } from '@business/hooks/useWebRTC/useControllMedia'; +import { useStreamVideoRef } from '@business/hooks/useWebRTC/useStreamVideoRef'; import WebRTC from '@business/services/WebRTC'; import type { OutletContext } from './HumanChatPage'; @@ -12,8 +13,8 @@ import { useChattingPageCreateJoinRoomPasswordPopup } from './useChattingPageCre export default function ChattingPage() { const { - localVideoRef, - remoteVideoRef, + // localVideoRef, + // remoteVideoRef, tarotButtonDisabled, tarotButtonClick, enableSideBar, @@ -21,8 +22,9 @@ export default function ChattingPage() { unblockGoBack, }: OutletContext = useOutletContext(); + useChattingPageCreateJoinRoomPasswordPopup({ unblockGoBack, enableSideBar }); + const { localVideoRef, remoteVideoRef } = useStreamVideoRef(); const { toggleAudio, toggleVideo, changeMyVideoTrack } = useControllMedia({ localVideoRef }); - const webRTC = WebRTC.getInstace(); useEffect(() => { if (joined) { @@ -30,19 +32,6 @@ export default function ChattingPage() { } }, [joined]); - useEffect(() => { - const existRemoteVideo = remoteVideoRef.current; - const existRemoteStream = webRTC.remoteStream; - const remoteStreamChanged = (remoteVideoRef.current?.srcObject as MediaStream)?.id !== webRTC.remoteStream?.id; - if (!existRemoteVideo || !existRemoteStream || !remoteStreamChanged) { - return; - } - - remoteVideoRef.current.srcObject = webRTC.remoteStream as MediaStream; - }, [remoteVideoRef.current]); - - useChattingPageCreateJoinRoomPasswordPopup({ unblockGoBack, enableSideBar }); - const navigate = useNavigate(); const goSettingPage = () => navigate('setting'); diff --git a/frontend/src/pages/HumanChatPage/SettingPage.tsx b/frontend/src/pages/HumanChatPage/SettingPage.tsx index a149aec2..52716e65 100644 --- a/frontend/src/pages/HumanChatPage/SettingPage.tsx +++ b/frontend/src/pages/HumanChatPage/SettingPage.tsx @@ -4,6 +4,7 @@ import { useNavigate, useOutletContext } from 'react-router-dom'; import ProfileSetting from '@components/ProfileSetting'; import { useControllMedia } from '@business/hooks/useWebRTC/useControllMedia'; +import { useStreamVideoRef } from '@business/hooks/useWebRTC/useStreamVideoRef'; import { HumanSocketManager } from '@business/services/SocketManager'; import type { OutletContext } from './HumanChatPage'; @@ -15,7 +16,8 @@ export default function ChattingPage() { const navigate = useNavigate(); - const { localVideoRef, enableSideBar, disableSideBar }: OutletContext = useOutletContext(); + const { localVideoRef } = useStreamVideoRef(); + const { enableSideBar, disableSideBar }: OutletContext = useOutletContext(); const { changeMyAudioTrack, changeMyVideoTrack, toggleAudio, toggleVideo } = useControllMedia({ localVideoRef }); useEffect(() => { diff --git a/frontend/src/pages/HumanChatPage/useHumanSocket.tsx b/frontend/src/pages/HumanChatPage/useHumanSocket.tsx new file mode 100644 index 00000000..1e4b97f2 --- /dev/null +++ b/frontend/src/pages/HumanChatPage/useHumanSocket.tsx @@ -0,0 +1,13 @@ +import { useEffect } from 'react'; + +import { HumanSocketManager } from '@business/services/SocketManager'; + +export function useHumanSocket({ disconnect = false }) { + const humanSocket = HumanSocketManager.getInstance(); + useEffect(() => { + humanSocket.connect(); + if (!disconnect) { + humanSocket.connect(); + } + }, []); +} From a542af89e6ee2aceb23e8867c6fc129396a9d6d1 Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Tue, 12 Dec 2023 18:01:32 +0900 Subject: [PATCH 49/67] =?UTF-8?q?remove:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/pages/HumanChatPage/ChattingPage.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/frontend/src/pages/HumanChatPage/ChattingPage.tsx b/frontend/src/pages/HumanChatPage/ChattingPage.tsx index b838fe2e..82d88b1a 100644 --- a/frontend/src/pages/HumanChatPage/ChattingPage.tsx +++ b/frontend/src/pages/HumanChatPage/ChattingPage.tsx @@ -6,15 +6,12 @@ import CamContainer from '@components/CamContainer'; import { useControllMedia } from '@business/hooks/useWebRTC/useControllMedia'; import { useStreamVideoRef } from '@business/hooks/useWebRTC/useStreamVideoRef'; -import WebRTC from '@business/services/WebRTC'; import type { OutletContext } from './HumanChatPage'; import { useChattingPageCreateJoinRoomPasswordPopup } from './useChattingPageCreateJoinRoomPopup'; export default function ChattingPage() { const { - // localVideoRef, - // remoteVideoRef, tarotButtonDisabled, tarotButtonClick, enableSideBar, From f8bae04cb6c645bf0f1bf06379e5601b2a25239e Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Tue, 12 Dec 2023 18:02:57 +0900 Subject: [PATCH 50/67] =?UTF-8?q?refactor:=20useWebRTC=ED=9B=85=EC=9D=80?= =?UTF-8?q?=20WebRTC=EB=A5=BC=20=EC=8B=9C=EC=9E=91=ED=95=98=EA=B1=B0?= =?UTF-8?q?=EB=82=98,=20=EC=A2=85=EB=A3=8C=ED=95=98=EB=8A=94=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=EB=A7=8C=20=EB=A6=AC=ED=84=B4=ED=95=A8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ์ด์ œ ๋”์ด์ƒ useWebRTCํ›…์ด ๋ชจ๋“ ๊ฑธ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๊ณ  ์ฒ˜๋ฆฌํ•˜๋Š” ํ›…์„ ๋ถ„๋ฆฌ์‹œํ‚ด. - useWebRTCํ›… ์•ˆ์—์„œ ์˜์กด๊ด€๊ณ„๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋˜ ๋…€์„๋“ค์„ WebRTC ๋ชจ๋“ˆ์„ ์˜์กด์‹œํ‚ค๋„๋ก ํ•จ. --- .../src/business/hooks/useWebRTC/useWebRTC.ts | 15 ++++++++------- .../src/pages/HumanChatPage/HumanChatPage.tsx | 12 ++++++++---- .../useChattingPageCreateJoinRoomPopup.ts | 3 ++- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts index d7534dbe..2b51fe33 100644 --- a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts +++ b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts @@ -1,13 +1,14 @@ import WebRTC from '../../services/WebRTC'; -import { useEffect } from 'react'; import { initSignalingSocket } from '@business/services/Socket'; +import { HumanSocketManager } from '@business/services/SocketManager'; import { useDataChannel } from './useDataChannel'; import { useMedia } from './useMedia'; export default function useWebRTC() { const webRTC = WebRTC.getInstace(); + const humanSocket = HumanSocketManager.getInstance(); const { getLocalStream } = useMedia(); @@ -37,14 +38,14 @@ export default function useWebRTC() { webRTC.addTracks(); }; - useEffect(() => { - return () => { - webRTC.closeRTCPeerConnection(); - webRTC.closeDataChannels(); - }; - }, []); + const endWebRTC = () => { + webRTC.closeRTCPeerConnection(); + webRTC.closeDataChannels(); + humanSocket.disconnect(); + }; return { startWebRTC, + endWebRTC, }; } diff --git a/frontend/src/pages/HumanChatPage/HumanChatPage.tsx b/frontend/src/pages/HumanChatPage/HumanChatPage.tsx index 585ad7b1..7ba76c3f 100644 --- a/frontend/src/pages/HumanChatPage/HumanChatPage.tsx +++ b/frontend/src/pages/HumanChatPage/HumanChatPage.tsx @@ -10,13 +10,12 @@ import { useBlocker } from '@business/hooks/useBlocker'; import { useHumanChatMessage } from '@business/hooks/useChatMessage'; import { useHumanTarotSpread } from '@business/hooks/useTarotSpread'; import useWebRTC from '@business/hooks/useWebRTC'; -import WebRTC from '@business/services/WebRTC'; import { useHumanChatPageContentAnimation } from './useHumanChatPageContentAnimation'; import { ChatPageState, useHumanChatPageCreateRoomEvent } from './useHumanChatPageCreateRoomEvent'; import { useHumanChatPageWrongURL } from './useHumanChatPageWrongURL'; -export interface OutletContext extends ReturnType { +export interface OutletContext { tarotButtonClick: () => void; tarotButtonDisabled: boolean; chatPageState: ChatPageState; @@ -27,7 +26,7 @@ export interface OutletContext extends ReturnType { } export default function HumanChatPage() { - const webRTCData = useWebRTC(); + const { endWebRTC } = useWebRTC(); useHumanChatPageWrongURL(); const { chatPageState, setChatPageState } = useHumanChatPageCreateRoomEvent(); @@ -57,6 +56,12 @@ export default function HumanChatPage() { onConfirm: () => navigate('/'), }); + useEffect(() => { + return () => { + endWebRTC(); + }; + }, []); + return (
    Date: Tue, 12 Dec 2023 23:23:27 +0900 Subject: [PATCH 51/67] =?UTF-8?q?=08docs:=20=ED=8C=80=EC=9B=90=EC=86=8C?= =?UTF-8?q?=EA=B0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 100 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 70 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index dfa2ca84..134151b5 100644 --- a/README.md +++ b/README.md @@ -191,34 +191,74 @@ ## ๐Ÿ”ฎ๐Ÿฅ› ํƒ€๋กœ ๋ฐ€ํฌํ‹ฐ: ํŒ€์› - - - - - - - - - - - - - - - - - - - - - - +
    J027J028J072J165
    ๊น€์œ ์ • - ๊น€์œ ์ง„ - ์†ก๋ฏผํ˜• - ํ—ˆ์ง€์˜ˆ -
    Backend - Frontend - Frontend - Frontend -
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    J027J028J072J165
    ๊น€์œ ์ •๊น€์œ ์ง„์†ก๋ฏผํ˜•ํ—ˆ์ง€์˜ˆ
    @kimyu0218@iQuQi@Doosies@HeoJiye
    BackendFrontendFrontendFrontend
    +
      +
    • DB ๋ฐ API ์„ค๊ณ„
    • +
    • ์†Œ์ผ“ ์ œ์™ธ BE ๋กœ์ง ๊ตฌํ˜„
    • +
    • BE ๋ฐฐํฌ
    • +
    • ์ธํ”„๋ผ
    • +
    +
    +
      +
    • AI ์ฑ„ํŒ… ๋ฐ ํƒ€๋กœ์นด๋“œ ํ™”๋ฉด ๊ตฌํ˜„
    • +
    • ๋ฐ˜์‘ํ˜• ์›น (๋ชจ๋ฐ”์ผ & ํ…Œ๋ธ”๋ฆฟ & PC)
    • +
    • ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ์›น (์ปค์Šคํ…€ ๋งˆ์šฐ์Šค & ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ž‘์—…)
    • +
    +
    +
      +
    • WebRTC ํ†ต์‹  ๋ชจ๋“ˆ๊ณผ ํ›… ๊ตฌํ˜„
    • +
    • RTCPeerConnection์„ ํ†ตํ•œ ์‹ค์‹œ๊ฐ„ ์˜์ƒ๊ณต์œ  ๊ตฌํ˜„
    • +
    • WebRTC Data Channel์„ ํ†ตํ•œ ์ด๋ฏธ์ง€/ํ…์ŠคํŠธ ์ „์†ก ๊ตฌํ˜„
    • +
    +
    +
      +
    • AI ์ฑ„ํŒ… ์†Œ์ผ“ ํ†ต์‹  ๋กœ์ง ๊ตฌํ˜„ (server & client)
    • +
    • WebRTC Data Channel ์ฑ„ํŒ… ๊ตฌํ˜„
    • +
    • clova studio api ์—ฐ๋™ (with stream)
    • +
    +
    From 1c4011e77ca2520ca09092db9c20077d93d2f13c Mon Sep 17 00:00:00 2001 From: YUJIN KIM <69742775+iQuQi@users.noreply.github.com> Date: Tue, 12 Dec 2023 23:43:50 +0900 Subject: [PATCH 52/67] =?UTF-8?q?docs:=20=ED=8C=80=EC=9B=90=EC=86=8C?= =?UTF-8?q?=EA=B0=9C=20=EB=B3=B5=EC=9B=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ๋„ˆ๋น„ ๊ณ ์ • ์•ˆ๋จ --- README.md | 100 ++++++++++++++++-------------------------------------- 1 file changed, 30 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index 134151b5..dfa2ca84 100644 --- a/README.md +++ b/README.md @@ -191,74 +191,34 @@ ## ๐Ÿ”ฎ๐Ÿฅ› ํƒ€๋กœ ๋ฐ€ํฌํ‹ฐ: ํŒ€์› - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
    J027J028J072J165
    ๊น€์œ ์ •๊น€์œ ์ง„์†ก๋ฏผํ˜•ํ—ˆ์ง€์˜ˆ
    @kimyu0218@iQuQi@Doosies@HeoJiye
    BackendFrontendFrontendFrontend
    -
      -
    • DB ๋ฐ API ์„ค๊ณ„
    • -
    • ์†Œ์ผ“ ์ œ์™ธ BE ๋กœ์ง ๊ตฌํ˜„
    • -
    • BE ๋ฐฐํฌ
    • -
    • ์ธํ”„๋ผ
    • -
    -
    -
      -
    • AI ์ฑ„ํŒ… ๋ฐ ํƒ€๋กœ์นด๋“œ ํ™”๋ฉด ๊ตฌํ˜„
    • -
    • ๋ฐ˜์‘ํ˜• ์›น (๋ชจ๋ฐ”์ผ & ํ…Œ๋ธ”๋ฆฟ & PC)
    • -
    • ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ์›น (์ปค์Šคํ…€ ๋งˆ์šฐ์Šค & ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ž‘์—…)
    • -
    -
    -
      -
    • WebRTC ํ†ต์‹  ๋ชจ๋“ˆ๊ณผ ํ›… ๊ตฌํ˜„
    • -
    • RTCPeerConnection์„ ํ†ตํ•œ ์‹ค์‹œ๊ฐ„ ์˜์ƒ๊ณต์œ  ๊ตฌํ˜„
    • -
    • WebRTC Data Channel์„ ํ†ตํ•œ ์ด๋ฏธ์ง€/ํ…์ŠคํŠธ ์ „์†ก ๊ตฌํ˜„
    • -
    -
    -
      -
    • AI ์ฑ„ํŒ… ์†Œ์ผ“ ํ†ต์‹  ๋กœ์ง ๊ตฌํ˜„ (server & client)
    • -
    • WebRTC Data Channel ์ฑ„ํŒ… ๊ตฌํ˜„
    • -
    • clova studio api ์—ฐ๋™ (with stream)
    • -
    -
    + + + + + + + + + + + + + + + + + + + + +
    J027J028J072J165
    ๊น€์œ ์ • + ๊น€์œ ์ง„ + ์†ก๋ฏผํ˜• + ํ—ˆ์ง€์˜ˆ +
    Backend + Frontend + Frontend + Frontend +
    From 43000cf56c4ee33749286f37bc73fa5187fdb292 Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Wed, 13 Dec 2023 12:34:55 +0900 Subject: [PATCH 53/67] =?UTF-8?q?refactor:=20HumanChatPage=20=EC=82=AC?= =?UTF-8?q?=EC=9D=B4=EB=93=9C=EB=B0=94=20=EA=B4=80=EB=A6=AC=20=ED=9B=85=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - useHumanChatPageSideBar ํ›…์—์„œ ์‚ฌ์ด๋“œ๋ฐ” ๊ด€๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•จ --- .../src/pages/HumanChatPage/HumanChatPage.tsx | 25 +++++++------------ .../HumanChatPage/useHumanChatPageSIdeBar.tsx | 24 ++++++++++++++++++ 2 files changed, 33 insertions(+), 16 deletions(-) create mode 100644 frontend/src/pages/HumanChatPage/useHumanChatPageSIdeBar.tsx diff --git a/frontend/src/pages/HumanChatPage/HumanChatPage.tsx b/frontend/src/pages/HumanChatPage/HumanChatPage.tsx index 7ba76c3f..d5a00c0d 100644 --- a/frontend/src/pages/HumanChatPage/HumanChatPage.tsx +++ b/frontend/src/pages/HumanChatPage/HumanChatPage.tsx @@ -13,6 +13,7 @@ import useWebRTC from '@business/hooks/useWebRTC'; import { useHumanChatPageContentAnimation } from './useHumanChatPageContentAnimation'; import { ChatPageState, useHumanChatPageCreateRoomEvent } from './useHumanChatPageCreateRoomEvent'; +import { useHumanChatPageSideBar } from './useHumanChatPageSIdeBar'; import { useHumanChatPageWrongURL } from './useHumanChatPageWrongURL'; export interface OutletContext { @@ -26,31 +27,23 @@ export interface OutletContext { } export default function HumanChatPage() { + useHumanChatPageWrongURL(); + + const navigate = useNavigate(); const { endWebRTC } = useWebRTC(); - useHumanChatPageWrongURL(); const { chatPageState, setChatPageState } = useHumanChatPageCreateRoomEvent(); const { messages, onSubmitMessage, inputDisabled, addPickCardMessage } = useHumanChatMessage(); const { tarotButtonClick, tarotButtonDisabled } = useHumanTarotSpread(addPickCardMessage); const { changeContentAnimation, contentAnimation } = useHumanChatPageContentAnimation(); - const [sideBarDisabled, setSideBarDisabled] = useState(false); - - const disableSideBar = () => { - changeContentAnimation(false); - setSideBarDisabled(true); - }; - - const enableSideBar = () => { - setSideBarDisabled(false); - }; - - useEffect(() => { - disableSideBar(); - }, []); + const { disableSideBar, enableSideBar, sideBarDisabled } = useHumanChatPageSideBar({ + onDisableSideBar: () => { + changeContentAnimation(false); + }, + }); - const navigate = useNavigate(); const { unblockGoBack } = useBlocker({ when: ({ nextLocation }) => nextLocation.pathname === '/' || nextLocation.pathname === '/chat/human', onConfirm: () => navigate('/'), diff --git a/frontend/src/pages/HumanChatPage/useHumanChatPageSIdeBar.tsx b/frontend/src/pages/HumanChatPage/useHumanChatPageSIdeBar.tsx new file mode 100644 index 00000000..62afdf69 --- /dev/null +++ b/frontend/src/pages/HumanChatPage/useHumanChatPageSIdeBar.tsx @@ -0,0 +1,24 @@ +import { useEffect, useState } from 'react'; + +interface useHumanChatPageSideBarParams { + onDisableSideBar: () => void; +} +export function useHumanChatPageSideBar({ onDisableSideBar }: useHumanChatPageSideBarParams) { + const [sideBarDisabled, setSideBarDisabled] = useState(false); + + const disableSideBar = () => { + onDisableSideBar(); + + setSideBarDisabled(true); + }; + + const enableSideBar = () => { + setSideBarDisabled(false); + }; + + useEffect(() => { + disableSideBar(); + }, []); + + return { disableSideBar, enableSideBar, sideBarDisabled }; +} From 6af938d8bc320889a671f137fdc8f742a46ecf8e Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Wed, 13 Dec 2023 13:32:13 +0900 Subject: [PATCH 54/67] =?UTF-8?q?style:=20import=20=EC=A0=88=EB=8C=80?= =?UTF-8?q?=EA=B2=BD=EB=A1=9C=EB=A1=9C=20=EA=B0=80=EC=A0=B8=EC=98=A4?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/business/hooks/useWebRTC/useControllMedia.ts | 2 +- frontend/src/business/hooks/useWebRTC/useDataChannel.ts | 2 +- frontend/src/business/hooks/useWebRTC/useWebRTC.ts | 3 +-- frontend/src/components/TarotSpread/TarotSpread.tsx | 3 ++- frontend/src/pages/HumanChatPage/HumanChatPage.tsx | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/src/business/hooks/useWebRTC/useControllMedia.ts b/frontend/src/business/hooks/useWebRTC/useControllMedia.ts index eb032288..ea403986 100644 --- a/frontend/src/business/hooks/useWebRTC/useControllMedia.ts +++ b/frontend/src/business/hooks/useWebRTC/useControllMedia.ts @@ -1,4 +1,4 @@ -import WebRTC from '../../services/WebRTC'; +import WebRTC from '@business/services/WebRTC'; import { useMediaInfo } from '@stores/zustandStores/useMediaInfo'; diff --git a/frontend/src/business/hooks/useWebRTC/useDataChannel.ts b/frontend/src/business/hooks/useWebRTC/useDataChannel.ts index c8e8414c..dfc01391 100644 --- a/frontend/src/business/hooks/useWebRTC/useDataChannel.ts +++ b/frontend/src/business/hooks/useWebRTC/useDataChannel.ts @@ -1,4 +1,4 @@ -import WebRTC from '../../services/WebRTC'; +import WebRTC from '@business/services/WebRTC'; import { useMediaInfo } from '@stores/zustandStores/useMediaInfo'; import { useProfileInfo } from '@stores/zustandStores/useProfileInfo'; diff --git a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts index 2b51fe33..9e4e29c9 100644 --- a/frontend/src/business/hooks/useWebRTC/useWebRTC.ts +++ b/frontend/src/business/hooks/useWebRTC/useWebRTC.ts @@ -1,7 +1,6 @@ -import WebRTC from '../../services/WebRTC'; - import { initSignalingSocket } from '@business/services/Socket'; import { HumanSocketManager } from '@business/services/SocketManager'; +import WebRTC from '@business/services/WebRTC'; import { useDataChannel } from './useDataChannel'; import { useMedia } from './useMedia'; diff --git a/frontend/src/components/TarotSpread/TarotSpread.tsx b/frontend/src/components/TarotSpread/TarotSpread.tsx index 90c193f5..86a6f22d 100644 --- a/frontend/src/components/TarotSpread/TarotSpread.tsx +++ b/frontend/src/components/TarotSpread/TarotSpread.tsx @@ -1,7 +1,8 @@ -import Background from '../Background'; import { detect } from 'detect-browser'; import React, { useEffect, useRef, useState } from 'react'; +import Background from '@components/Background'; + import { getTarotImageQuery } from '@stores/queries/getTarotImageQuery'; import { TAROT_CARDS_LENGTH } from '@constants/sizes'; diff --git a/frontend/src/pages/HumanChatPage/HumanChatPage.tsx b/frontend/src/pages/HumanChatPage/HumanChatPage.tsx index d5a00c0d..062b8493 100644 --- a/frontend/src/pages/HumanChatPage/HumanChatPage.tsx +++ b/frontend/src/pages/HumanChatPage/HumanChatPage.tsx @@ -1,4 +1,4 @@ -import { Dispatch, SetStateAction, useEffect, useState } from 'react'; +import { Dispatch, SetStateAction, useEffect } from 'react'; import { Outlet, useNavigate } from 'react-router-dom'; import Background from '@components/Background'; From ea43689e9fc17d94b8fe50692d491c0a7a2a97dd Mon Sep 17 00:00:00 2001 From: Song_Minhyung Date: Wed, 13 Dec 2023 13:47:58 +0900 Subject: [PATCH 55/67] =?UTF-8?q?fix:=20=EC=B9=B4=EB=93=9C=EB=BD=91?= =?UTF-8?q?=EA=B8=B0=20UI=20=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - z-index๋ฅผ 10์œผ๋กœ ์˜ฌ๋ ค์คŒ --- frontend/src/business/hooks/useOverlay/useOverlay.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/business/hooks/useOverlay/useOverlay.tsx b/frontend/src/business/hooks/useOverlay/useOverlay.tsx index 87eadbce..15ff4ea5 100644 --- a/frontend/src/business/hooks/useOverlay/useOverlay.tsx +++ b/frontend/src/business/hooks/useOverlay/useOverlay.tsx @@ -28,7 +28,7 @@ export default function useOverlay() { open: (OverlayElement: CreateOverlayElement) => { mount( id, -
    +
    Date: Wed, 13 Dec 2023 14:01:09 +0900 Subject: [PATCH 56/67] =?UTF-8?q?fix:=20=EB=AA=A8=EB=B0=94=EC=9D=BC=20?= =?UTF-8?q?=ED=99=98=EA=B2=BD=20input=20=ED=81=B4=EB=A6=AD=EC=8B=9C=20?= =?UTF-8?q?=ED=99=95=EB=8C=80=EB=AC=B8=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - viewport์˜ meta ์ •๋ณด๋ฅผ ๋ฐ”๊ฟ”์คŒ. - ์‹œ์ž‘์Šค์ผ€์ผ, ์ตœ๋Œ€์Šค์ผ€์ผ์€ 1์ด๊ณ  ์œ ์ €๊ฐ€ ์Šค์ผ€์ผ ์กฐ์ ˆ ๋ชปํ•˜๋„๋ก ๋ง‰๋Š” ์ฝ”๋“œ์ž„. --- frontend/index.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/index.html b/frontend/index.html index 31785190..6f415f71 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -12,8 +12,9 @@ /> + ๋งˆ๋ฒ•์˜ ์†Œ๋ผ๊ณ ๋‘ฅ