From 23fdb95b81cc20cb8499343a5311dce10b1b9609 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Mon, 21 Oct 2024 15:56:55 +0800 Subject: [PATCH 001/258] restore text centering for caption (was removed somehow) --- apps/frontend/src/app/matching/modalContent/styles.scss | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/frontend/src/app/matching/modalContent/styles.scss b/apps/frontend/src/app/matching/modalContent/styles.scss index fdd0791c98..c1a0430b09 100644 --- a/apps/frontend/src/app/matching/modalContent/styles.scss +++ b/apps/frontend/src/app/matching/modalContent/styles.scss @@ -227,3 +227,12 @@ button:disabled, .joined-match-deactivated-button { height: 60px; fill: #463F3A; } + +.user-caption { + display: flex; + justify-content: center; +} + +.avatar-caption-container { + width: 64px; +} \ No newline at end of file From bf9ce45d431db6d8e46d08f6a813e77398c24e47 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Mon, 21 Oct 2024 22:56:36 +0800 Subject: [PATCH 002/258] Fixes to matching timer (Lift timer state up into modal) --- .../src/app/matching/MatchingModal.tsx | 70 ++++++++++++++----- .../modalContent/FindMatchContent.tsx | 8 +++ .../modalContent/JoinedMatchContent.tsx | 6 +- .../modalContent/MatchFoundContent.tsx | 10 +-- .../MatchingInProgressContent.tsx | 16 ++--- 5 files changed, 74 insertions(+), 36 deletions(-) diff --git a/apps/frontend/src/app/matching/MatchingModal.tsx b/apps/frontend/src/app/matching/MatchingModal.tsx index 1a243e58cc..c63c62c961 100644 --- a/apps/frontend/src/app/matching/MatchingModal.tsx +++ b/apps/frontend/src/app/matching/MatchingModal.tsx @@ -1,5 +1,6 @@ import React, { useState, useEffect } from 'react'; import { + Button, Modal, } from 'antd'; import 'typeface-montserrat'; @@ -11,17 +12,37 @@ import JoinedMatchContent from './modalContent/JoinedMatchContent'; import MatchNotFoundContent from './modalContent/MatchNotFoundContent'; import MatchCancelledContent from './modalContent/MatchCancelledContent'; import useMatching from '../services/use-matching'; +import { useTimer } from 'react-timer-hook'; interface MatchingModalProps { isOpen: boolean; close: () => void; } +const MATCH_TIMEOUT = 30; +const JOIN_TIMEOUT = 5; + const MatchingModal: React.FC = ({ isOpen, close: _close }) => { const matchingState = useMatching(); const [closedType, setClosedType] = useState<"finding" | "cancelled" | "joined">("finding"); - const [timeoutAfter, setTimeoutAfter] = useState(9999); const isClosable = ["timeout", "closed"].includes(matchingState.state); + const { totalSeconds, pause: pauseTimer, restart: restartTimer } = useTimer({ + expiryTimestamp: new Date(Date.now() + MATCH_TIMEOUT * 1000), + autoStart: false, + onExpire() { + if (matchingState.state === "matching") { + matchingState.timeout(); + return; + } + if (matchingState.state === "found") { + matchingState.ok(); + setClosedType("joined"); + return; + } + console.warn(`matching is in ${matchingState.state}`) + }, + }); + const passed = MATCH_TIMEOUT - totalSeconds; function close() { // clean up matching and closedType State @@ -32,43 +53,57 @@ const MatchingModal: React.FC = ({ isOpen, close: _close }) _close(); } + useEffect(() => { + if (matchingState.state === "cancelling" || matchingState.state === "timeout") { + pauseTimer(); + return; + } + if (matchingState.state === "found") { + restartTimer( + new Date(Date.now() + JOIN_TIMEOUT * 1000), + ) + } + }, [matchingState]) + const renderModalContent = () => { switch (matchingState.state) { case 'closed': switch (closedType) { case "finding": - return ; + return { + restartTimer( + new Date(Date.now() + MATCH_TIMEOUT * 1000), + ); + matchingState.start(params); + }}/>; case "cancelled": return { setClosedType("finding"); }} retry={() => {}} - canceledIn={timeoutAfter} + canceledIn={passed} />; case "joined": return { - setClosedType("cancelled"); - }} - name1={matchingState.info?.myName || ""} - name2={matchingState.info?.partnerName || ""} + cancel={() => { + setClosedType("cancelled"); + }} + name1={matchingState.info?.myName ?? ""} + name2={matchingState.info?.partnerName ??""} />; } case 'matching': return { + cancelMatch={() => { setClosedType("cancelled"); - setTimeoutAfter(timeoutAfter); matchingState.cancel(); + pauseTimer(); }} - timeout={(timeoutAfter: number) => { - matchingState.timeout() - setTimeoutAfter(timeoutAfter); - }} + timePassed={passed} />; case 'cancelling': - return {}} timeout={() => {}}/>; + return {}} timePassed={passed}/>; case 'starting': return {}}/> case 'found': @@ -83,9 +118,10 @@ const MatchingModal: React.FC = ({ isOpen, close: _close }) }} name1={matchingState.info.myName} name2={matchingState.info.partnerName} - /> + joiningIn={totalSeconds} + /> case 'timeout': - return {}} timedOutIn={10}/>; + return {}} timedOutIn={passed}/>; default: throw new Error('Invalid matching state.'); } diff --git a/apps/frontend/src/app/matching/modalContent/FindMatchContent.tsx b/apps/frontend/src/app/matching/modalContent/FindMatchContent.tsx index ac65cbe033..5b5c53a3f4 100644 --- a/apps/frontend/src/app/matching/modalContent/FindMatchContent.tsx +++ b/apps/frontend/src/app/matching/modalContent/FindMatchContent.tsx @@ -62,6 +62,14 @@ const FindMatchContent: React.FC = ({ beginMatch }) => { + {text} ), }, @@ -458,7 +458,7 @@ export default function Home() { query: { data: question.docRefId }, // the data }} > - + {text} ), }, From 0fe7a7c744a2175159ffaeabd7e3ca500c373a3e Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Thu, 24 Oct 2024 20:03:53 +0800 Subject: [PATCH 014/258] feat: update models --- apps/matching-service/databases/userqueue.go | 8 +++---- .../models/{complexity.go => difficulty.go} | 0 apps/matching-service/models/match.go | 24 ++++++++++++++----- .../processes/performmatches.go | 6 ++--- 4 files changed, 25 insertions(+), 13 deletions(-) rename apps/matching-service/models/{complexity.go => difficulty.go} (100%) diff --git a/apps/matching-service/databases/userqueue.go b/apps/matching-service/databases/userqueue.go index fed980d3cc..ff42f6c169 100644 --- a/apps/matching-service/databases/userqueue.go +++ b/apps/matching-service/databases/userqueue.go @@ -174,10 +174,10 @@ func FindMatchingUser(tx *redis.Tx, username string, ctx context.Context) (*mode commonDifficulty := models.GetCommonDifficulty(user.Difficulties, matchedUser.Difficulties) matchFound := models.MatchFound{ - Type: "match_found", - MatchedUser: potentialMatch, - Topic: topic, - Difficulty: commonDifficulty, + Type: "match_found", + MatchedUser: potentialMatch, + MatchedTopics: topic, + MatchedDifficulties: commonDifficulty, } return &matchFound, nil diff --git a/apps/matching-service/models/complexity.go b/apps/matching-service/models/difficulty.go similarity index 100% rename from apps/matching-service/models/complexity.go rename to apps/matching-service/models/difficulty.go diff --git a/apps/matching-service/models/match.go b/apps/matching-service/models/match.go index ad555b555b..eaf2dd98c9 100644 --- a/apps/matching-service/models/match.go +++ b/apps/matching-service/models/match.go @@ -8,12 +8,24 @@ type MatchRequest struct { } type MatchFound struct { - Type string `json:"type"` - MatchID string `json:"matchId"` - User string `json:"user"` // username - MatchedUser string `json:"matchedUser"` // matched username - Topic string `json:"topic"` // matched topic - Difficulty string `json:"difficulty"` // matched difficulty + Type string `json:"type"` + MatchID string `json:"match_id"` + User string `json:"user"` + MatchedUser string `json:"matched_user"` + MatchedTopics []string `json:"matched_topic"` + MatchedDifficulties []string `json:"question_topics"` +} + +type MatchQuestionFound struct { + Type string `json:"type"` + MatchID string `json:"match_id"` + User string `json:"user"` + MatchedUser string `json:"matched_user"` + MatchedTopics []string `json:"matched_topic"` + QuestionID int64 `json:"question_id"` + QuestionName string `json:"question_name"` + QuestionDifficulty string `json:"question_difficulty"` + QuestionTopics []string `json:"question_topics"` } type Timeout struct { diff --git a/apps/matching-service/processes/performmatches.go b/apps/matching-service/processes/performmatches.go index 34e98bd591..68279fd4d8 100644 --- a/apps/matching-service/processes/performmatches.go +++ b/apps/matching-service/processes/performmatches.go @@ -52,8 +52,8 @@ func PerformMatching(rdb *redis.Client, matchRequest models.MatchRequest, ctx co if matchFound != nil { matchedUsername := matchFound.MatchedUser - matchedTopic := matchFound.Topic - matchedDifficulty := matchFound.Difficulty + matchedTopics := matchFound.MatchedTopics + matchedDifficulties := matchFound.MatchedDifficulties // Generate a random match ID matchId, err := utils.GenerateMatchID() @@ -63,7 +63,7 @@ func PerformMatching(rdb *redis.Client, matchRequest models.MatchRequest, ctx co // Log down which users got matched matchFound.MatchID = matchId - log.Printf("Users %s and %s matched on the topic: %s with difficulty: %s", currentUsername, matchedUsername, matchedTopic, matchedDifficulty) + log.Printf("Users %s and %s matched on the topic: %s with difficulty: %s", currentUsername, matchedUsername, matchedTopics, matchedDifficulties) // Clean up redis for this match databases.CleanUpUser(tx, currentUsername, ctx) From 06eeb1d4de5d14b424cc36d660ba998add0408a7 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Thu, 24 Oct 2024 20:09:36 +0800 Subject: [PATCH 015/258] feat: validate not duplicate user --- apps/matching-service/databases/userqueue.go | 19 +++++++++++++++++-- .../processes/performmatches.go | 10 +--------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/apps/matching-service/databases/userqueue.go b/apps/matching-service/databases/userqueue.go index ff42f6c169..6656c3bce8 100644 --- a/apps/matching-service/databases/userqueue.go +++ b/apps/matching-service/databases/userqueue.go @@ -76,6 +76,21 @@ func GetAllQueuedUsers(tx *redis.Tx, ctx context.Context) ([]string, error) { return users, nil } +func ValidateNotDuplicateUser(tx *redis.Tx, ctx context.Context, currentUsername string) error { + queuedUsernames, err := GetAllQueuedUsers(tx, ctx) + if err != nil { + return err + } + + // Check that user is not part of the existing queue + for _, username := range queuedUsernames { + if username == currentUsername { + return models.ExistingUserError + } + } + return nil +} + // Add user details into hashset in Redis func StoreUserDetails(tx *redis.Tx, request models.MatchRequest, ctx context.Context) { topicsJSON, err := json.Marshal(request.Topics) @@ -171,12 +186,12 @@ func FindMatchingUser(tx *redis.Tx, username string, ctx context.Context) (*mode return nil, err } - commonDifficulty := models.GetCommonDifficulty(user.Difficulties, matchedUser.Difficulties) + commonDifficulty := models.GetCommonDifficulties(user.Difficulties, matchedUser.Difficulties) matchFound := models.MatchFound{ Type: "match_found", MatchedUser: potentialMatch, - MatchedTopics: topic, + MatchedTopics: topics, MatchedDifficulties: commonDifficulty, } diff --git a/apps/matching-service/processes/performmatches.go b/apps/matching-service/processes/performmatches.go index 68279fd4d8..945d13b60f 100644 --- a/apps/matching-service/processes/performmatches.go +++ b/apps/matching-service/processes/performmatches.go @@ -26,18 +26,10 @@ func PerformMatching(rdb *redis.Client, matchRequest models.MatchRequest, ctx co defer lock.Release(ctx) if err := rdb.Watch(ctx, func(tx *redis.Tx) error { - queuedUsernames, err := databases.GetAllQueuedUsers(tx, ctx) - if err != nil { + if err := databases.ValidateNotDuplicateUser(tx, ctx, currentUsername); err != nil { return err } - // Check that user is not part of the existing queue - for _, username := range queuedUsernames { - if username == currentUsername { - return models.ExistingUserError - } - } - databases.AddUser(tx, matchRequest, ctx) // Log queue before and after matchmaking From f9821202db4194b64b3592e7d3d5ea6da5cf85e5 Mon Sep 17 00:00:00 2001 From: bensohh Date: Fri, 25 Oct 2024 02:06:48 +0800 Subject: [PATCH 016/258] Setup the template for collaboration editor page --- apps/frontend/package.json | 4 +- apps/frontend/pnpm-lock.yaml | 142 ++++++++++++ .../src/app/collaboration/[id]/page.tsx | 218 ++++++++++++++++++ .../src/app/collaboration/[id]/styles.scss | 152 ++++++++++++ apps/frontend/src/app/question/[id]/page.tsx | 52 ++--- apps/frontend/src/app/question/page.tsx | 2 +- apps/frontend/src/utils/SelectOptions.ts | 4 + 7 files changed, 541 insertions(+), 33 deletions(-) create mode 100644 apps/frontend/src/app/collaboration/[id]/page.tsx create mode 100644 apps/frontend/src/app/collaboration/[id]/styles.scss diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 832db74f2b..20821049f0 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -12,13 +12,15 @@ "@ant-design/icons": "^5.5.1", "@ant-design/nextjs-registry": "^1.0.1", "antd": "^5.20.6", + "codemirror": "^6.0.1", "next": "14.2.13", "react": "^18.2.0", "react-dom": "^18.2.0", "react-timer-hook": "^3.0.7", "react-use-websocket": "^4.9.0", "sass": "^1.79.2", - "typeface-montserrat": "^1.1.13" + "typeface-montserrat": "^1.1.13", + "y-codemirror.next": "^0.3.5" }, "devDependencies": { "@types/node": "^20", diff --git a/apps/frontend/pnpm-lock.yaml b/apps/frontend/pnpm-lock.yaml index 26b7b90dad..2bddc21b32 100644 --- a/apps/frontend/pnpm-lock.yaml +++ b/apps/frontend/pnpm-lock.yaml @@ -14,6 +14,9 @@ dependencies: antd: specifier: ^5.20.6 version: 5.20.6(react-dom@18.2.0)(react@18.2.0) + codemirror: + specifier: ^6.0.1 + version: 6.0.1(@lezer/common@1.2.3) next: specifier: 14.2.13 version: 14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2) @@ -35,6 +38,9 @@ dependencies: typeface-montserrat: specifier: ^1.1.13 version: 1.1.13 + y-codemirror.next: + specifier: ^0.3.5 + version: 0.3.5(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(yjs@13.6.20) devDependencies: '@types/node': @@ -157,6 +163,68 @@ packages: regenerator-runtime: 0.14.1 dev: false + /@codemirror/autocomplete@6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3): + resolution: {integrity: sha512-iWHdj/B1ethnHRTwZj+C1obmmuCzquH29EbcKr0qIjA9NfDeBDJ7vs+WOHsFeLeflE4o+dHfYndJloMKHUkWUA==} + peerDependencies: + '@codemirror/language': ^6.0.0 + '@codemirror/state': ^6.0.0 + '@codemirror/view': ^6.0.0 + '@lezer/common': ^1.0.0 + dependencies: + '@codemirror/language': 6.10.3 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + '@lezer/common': 1.2.3 + dev: false + + /@codemirror/commands@6.7.1: + resolution: {integrity: sha512-llTrboQYw5H4THfhN4U3qCnSZ1SOJ60ohhz+SzU0ADGtwlc533DtklQP0vSFaQuCPDn3BPpOd1GbbnUtwNjsrw==} + dependencies: + '@codemirror/language': 6.10.3 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + '@lezer/common': 1.2.3 + dev: false + + /@codemirror/language@6.10.3: + resolution: {integrity: sha512-kDqEU5sCP55Oabl6E7m5N+vZRoc0iWqgDVhEKifcHzPzjqCegcO4amfrYVL9PmPZpl4G0yjkpTpUO/Ui8CzO8A==} + dependencies: + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + style-mod: 4.1.2 + dev: false + + /@codemirror/lint@6.8.2: + resolution: {integrity: sha512-PDFG5DjHxSEjOXk9TQYYVjZDqlZTFaDBfhQixHnQOEVDDNHUbEh/hstAjcQJaA6FQdZTD1hquXTK0rVBLADR1g==} + dependencies: + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + crelt: 1.0.6 + dev: false + + /@codemirror/search@6.5.6: + resolution: {integrity: sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==} + dependencies: + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + crelt: 1.0.6 + dev: false + + /@codemirror/state@6.4.1: + resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==} + dev: false + + /@codemirror/view@6.34.1: + resolution: {integrity: sha512-t1zK/l9UiRqwUNPm+pdIT0qzJlzuVckbTEMVNFhfWkGiBQClstzg+78vedCvLSX0xJEZ6lwZbPpnljL7L6iwMQ==} + dependencies: + '@codemirror/state': 6.4.1 + style-mod: 4.1.2 + w3c-keyname: 2.2.8 + dev: false + /@ctrl/tinycolor@3.6.1: resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} engines: {node: '>=10'} @@ -231,6 +299,22 @@ packages: wrap-ansi-cjs: /wrap-ansi@7.0.0 dev: true + /@lezer/common@1.2.3: + resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==} + dev: false + + /@lezer/highlight@1.2.1: + resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==} + dependencies: + '@lezer/common': 1.2.3 + dev: false + + /@lezer/lr@1.4.2: + resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==} + dependencies: + '@lezer/common': 1.2.3 + dev: false + /@next/env@14.2.13: resolution: {integrity: sha512-s3lh6K8cbW1h5Nga7NNeXrbe0+2jIIYK9YaA9T7IufDWnZpozdFUp6Hf0d5rNWUKu4fEuSX2rCKlGjCrtylfDw==} dev: false @@ -951,6 +1035,20 @@ packages: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} dev: false + /codemirror@6.0.1(@lezer/common@1.2.3): + resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==} + dependencies: + '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3) + '@codemirror/commands': 6.7.1 + '@codemirror/language': 6.10.3 + '@codemirror/lint': 6.8.2 + '@codemirror/search': 6.5.6 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + transitivePeerDependencies: + - '@lezer/common' + dev: false + /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -976,6 +1074,10 @@ packages: toggle-selection: 1.0.6 dev: false + /crelt@1.0.6: + resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + dev: false + /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -2034,6 +2136,10 @@ packages: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true + /isomorphic.js@0.2.5: + resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} + dev: false + /iterator.prototype@1.1.2: resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} dependencies: @@ -2123,6 +2229,14 @@ packages: type-check: 0.4.0 dev: true + /lib0@0.2.98: + resolution: {integrity: sha512-XteTiNO0qEXqqweWx+b21p/fBnNHUA1NwAtJNJek1oPrewEZs2uiT4gWivHKr9GqCjDPAhchz0UQO8NwU3bBNA==} + engines: {node: '>=16'} + hasBin: true + dependencies: + isomorphic.js: 0.2.5 + dev: false + /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true @@ -3255,6 +3369,10 @@ packages: engines: {node: '>=8'} dev: true + /style-mod@4.1.2: + resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} + dev: false + /styled-jsx@5.1.1(react@18.2.0): resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} engines: {node: '>= 12.0.0'} @@ -3420,6 +3538,10 @@ packages: resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==} dev: true + /w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + dev: false + /which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} dependencies: @@ -3503,3 +3625,23 @@ packages: /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true + + /y-codemirror.next@0.3.5(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(yjs@13.6.20): + resolution: {integrity: sha512-VluNu3e5HfEXybnypnsGwKAj+fKLd4iAnR7JuX1Sfyydmn1jCBS5wwEL/uS04Ch2ib0DnMAOF6ZRR/8kK3wyGw==} + peerDependencies: + '@codemirror/state': ^6.0.0 + '@codemirror/view': ^6.0.0 + yjs: ^13.5.6 + dependencies: + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + lib0: 0.2.98 + yjs: 13.6.20 + dev: false + + /yjs@13.6.20: + resolution: {integrity: sha512-Z2YZI+SYqK7XdWlloI3lhMiKnCdFCVC4PchpdO+mCYwtiTwncjUbnRK9R1JmkNfdmHyDXuWN3ibJAt0wsqTbLQ==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + dependencies: + lib0: 0.2.98 + dev: false diff --git a/apps/frontend/src/app/collaboration/[id]/page.tsx b/apps/frontend/src/app/collaboration/[id]/page.tsx new file mode 100644 index 0000000000..b12f916f33 --- /dev/null +++ b/apps/frontend/src/app/collaboration/[id]/page.tsx @@ -0,0 +1,218 @@ +"use client"; +import Header from "@/components/Header/header"; +import { + Button, + Col, + Input, + Layout, + Row, + Select, + Tabs, + TabsProps, + Tag, + Typography, +} from "antd"; +import { Content } from "antd/es/layout/layout"; +import "./styles.scss"; +import { useRouter, useSearchParams } from "next/navigation"; +import { useEffect, useState } from "react"; +import { GetSingleQuestion, Question } from "@/app/services/question"; +import { + ClockCircleOutlined, + CodeOutlined, + FileDoneOutlined, + MessageOutlined, + PlayCircleOutlined, + SendOutlined, +} from "@ant-design/icons"; +import { ProgrammingLanguageOptions } from "@/utils/SelectOptions"; + +interface CollaborationProps {} + +export default function CollaborationPage(props: CollaborationProps) { + const [isLoading, setIsLoading] = useState(false); + + // Code Editor States + const [questionTitle, setQuestionTitle] = useState( + undefined + ); + const [complexity, setComplexity] = useState(undefined); + const [categories, setCategories] = useState([]); // Store the selected filter categories + const [description, setDescription] = useState(undefined); + const [selectedLanguage, setSelectedLanguage] = useState("javascript"); // State to hold the selected language item + + // Session states + const [collaborationId, setCollaborationId] = useState( + undefined + ); + const [matchedUser, setMatchedUser] = useState(undefined); + + // Manual test case states + const [manualTestCase, setManualTestCase] = useState( + undefined + ); + + // Retrieve the docRefId from query params during page navigation + // const searchParams = useSearchParams(); + + // Fetch the question on initialisation + useEffect(() => { + if (!isLoading) { + setIsLoading(true); + } + + // Retrieve details from localstorage + const docRefId: string = localStorage.getItem("docRefId") ?? ""; + const collabId: string = localStorage.getItem("collabId") ?? ""; + const matchedUser: string = localStorage.getItem("matchedUser") ?? ""; + + // Set states from localstorage + setCollaborationId(collabId); + setMatchedUser(matchedUser); + + GetSingleQuestion(docRefId).then((data: Question) => { + setQuestionTitle(`${data.id}. ${data.title}`); + setComplexity(data.complexity); + setCategories(data.categories); + setDescription(data.description); + }); + }, []); + + const items: TabsProps["items"] = [ + { + key: "1", + label: "Case 1", + children: "Insert Test Case 1", // TODO: Setup test-cases in db for each qn and pull/paste here + }, + { + key: "2", + label: "Case 2", + children: "Insert Test Case 2", + }, + { + key: "3", + label: "Case 3", + children: ( + setManualTestCase(e.target.value)} + placeholder="Input Manual Test Case" + /> + ), + }, + ]; + + return ( + +
+ + + + +
+
{questionTitle}
+
+ + {complexity && + complexity.charAt(0).toUpperCase() + complexity.slice(1)} + +
+
+ Topics: + {categories.map((category) => ( + {category} + ))} +
+
{description}
+
+
+ +
+
+
+ + Test Cases +
+ {/* TODO: Link to execution service for running code against test-cases */} + +
+
+ +
+
+
+ + + +
+
+
+ + Code +
+ {/* TODO: Link to execution service for code submission */} + +
+
+
Select Language:
+ +
-
) } -const DifficultySelector: React.FC = ({ selectedDifficulties, onChange}) => { - const handleChange = (difficulty: string) => { - const newSelectedDifficulties = selectedDifficulties.includes(difficulty) - ? selectedDifficulties.filter(selectedDifficulty => selectedDifficulty !== difficulty) - : [...selectedDifficulties, difficulty]; - onChange(newSelectedDifficulties); - } - - return ( -
- {DifficultyOption.map(difficultyOption => ( - handleChange(difficultyOption.label)} - > - {difficultyOption.label} - - ))} -
- ) -} - -const TopicSelector: React.FC = ({ selectedTopics, onChange}) => { - const topicOptions: SelectProps[] = CategoriesOption; - - const handleChange = (topics: string[]) => { - onChange(topics); - } - - return ( -
- - setSelectedLanguage(val)} /> -
- {collaborationId && currentUser && ( + */} + {collaborationId && currentUser && selectedLanguage && ( )} @@ -206,7 +220,10 @@ export default function CollaborationPage(props: CollaborationProps) { Session Details - + {/* TODO: End the collaboration session, cleanup the localstorage variables */} +
diff --git a/apps/frontend/src/app/collaboration/[id]/styles.scss b/apps/frontend/src/app/collaboration/[id]/styles.scss index 7958a76584..35f2ea7a79 100644 --- a/apps/frontend/src/app/collaboration/[id]/styles.scss +++ b/apps/frontend/src/app/collaboration/[id]/styles.scss @@ -74,10 +74,10 @@ padding: 1rem; } -.code-second-container { - display: flex; - margin: 4px 0px; -} +// .code-second-container { +// display: flex; +// margin: 4px 0px; +// } .code-language { margin: auto 8px auto 0px; @@ -150,7 +150,6 @@ } .topic-label, -.code-language, .session-duration, .session-matched-user-label { font-size: 14px; diff --git a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx index 98626becff..ad72d17ab3 100644 --- a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx +++ b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx @@ -1,17 +1,21 @@ // Referenced from example in https://www.npmjs.com/package/y-codemirror.next -import React, { useEffect, useRef } from "react"; +import React, { useEffect, useRef, useState } from "react"; import * as Y from "yjs"; import { yCollab } from "y-codemirror.next"; import { WebrtcProvider } from "y-webrtc"; import { EditorView, basicSetup } from "codemirror"; -import { EditorState } from "@codemirror/state"; +import { EditorState, Compartment } from "@codemirror/state"; import { javascript } from "@codemirror/lang-javascript"; +import { python, pythonLanguage } from "@codemirror/lang-python"; import "./styles.scss"; -import { message } from "antd"; +import { message, Select } from "antd"; +import { language } from "@codemirror/language"; +import { ProgrammingLanguageOptions } from "@/utils/SelectOptions"; interface CollaborativeEditorProps { user: string; collaborationId: string; + language: string; } export const usercolors = [ @@ -31,6 +35,29 @@ export const userColor = const CollaborativeEditor = (props: CollaborativeEditorProps) => { const editorRef = useRef(null); + // const viewRef = useRef(null); + const [selectedLanguage, setSelectedLanguage] = useState("javascript"); + const [trigger, setTrigger] = useState(false); + + const languageConf = new Compartment(); + + const autoLanguage = EditorState.transactionExtender.of((tr) => { + if (!tr.docChanged) return null; + const docIsPython = /^\s*def\s|\s*class\s/.test( + tr.newDoc.sliceString(0, 100) + ); + const stateIsPython = tr.startState.facet(language) === pythonLanguage; + if (docIsPython === stateIsPython) return null; + + const newLanguage = docIsPython ? "python" : "javascript"; + setSelectedLanguage(newLanguage); + + return { + effects: languageConf.reconfigure( + newLanguage === "python" ? python() : javascript() + ), + }; + }); const [messageApi, contextHolder] = message.useMessage(); @@ -55,6 +82,29 @@ const CollaborativeEditor = (props: CollaborativeEditorProps) => { }); }; + // const handleLanguageChange = (val: any) => { + // console.log("came in here"); + // console.log(val); + // setSelectedLanguage(val); + + // let languageExtension; + // switch (val) { + // case "python": + // languageExtension = python(); + // break; + // default: + // languageExtension = javascript(); + // } + + // // Update the language configuration + // if (viewRef.current) { + // console.log("insude here"); + // viewRef.current.dispatch({ + // effects: languageConf.reconfigure(languageExtension), + // }); + // } + // }; + useEffect(() => { if (process.env.NEXT_PUBLIC_SIGNALLING_SERVICE_URL === undefined) { error("Missing Signalling Service Url"); @@ -78,7 +128,8 @@ const CollaborativeEditor = (props: CollaborativeEditorProps) => { doc: ytext.toString(), extensions: [ basicSetup, - javascript(), + languageConf.of(javascript()), + autoLanguage, yCollab(ytext, provider.awareness, { undoManager }), ], }); @@ -88,9 +139,16 @@ const CollaborativeEditor = (props: CollaborativeEditorProps) => { parent: editorRef.current || undefined, }); + // viewRef.current = new EditorView({ + // state: state, + // parent: editorRef.current || undefined, + // }); + return () => { // Cleanup on component unmount + console.log("unmounting collaboration editor"); // TODO: remove view.destroy(); + // viewRef.current?.destroy(); provider.disconnect(); ydoc.destroy(); }; @@ -99,7 +157,27 @@ const CollaborativeEditor = (props: CollaborativeEditorProps) => { return ( <> {contextHolder} -
+
+
Select Language:
+ + +
+
+
diff --git a/apps/question-service/handlers/findmatchingquestion.go b/apps/question-service/handlers/findmatchingquestion.go index 6e48f17707..7590282ba7 100644 --- a/apps/question-service/handlers/findmatchingquestion.go +++ b/apps/question-service/handlers/findmatchingquestion.go @@ -26,7 +26,7 @@ func (s *GrpcServer) FindMatchingQuestion(ctx context.Context, req *pb.MatchQues } // 1. Match by both topic and difficulty - if len(docs) == 0 { + if len(docs) == 0 && len(req.MatchedTopics) > 0 && len(matchedDifficulties) > 0 { d, err := queryTopicAndDifficultyQuestion(s.Client, ctx, req.MatchedTopics, matchedDifficulties) if err != nil { return nil, err @@ -35,7 +35,7 @@ func (s *GrpcServer) FindMatchingQuestion(ctx context.Context, req *pb.MatchQues } // 2. Match by just topic - if len(docs) == 0 { + if len(docs) == 0 && len(req.MatchedTopics) > 0 { d, err := queryTopicQuestion(s.Client, ctx, req.MatchedTopics) if err != nil { return nil, err @@ -44,7 +44,7 @@ func (s *GrpcServer) FindMatchingQuestion(ctx context.Context, req *pb.MatchQues } // 3. Match by difficulty - if len(docs) == 0 { + if len(docs) == 0 && len(matchedDifficulties) > 0 { d, err := queryDifficultyQuestion(s.Client, ctx, matchedDifficulties) if err != nil { return nil, err @@ -81,7 +81,6 @@ func (s *GrpcServer) FindMatchingQuestion(ctx context.Context, req *pb.MatchQues } // Retrieve the document at the random offset - func retrieveRandomQuestion(docs []*firestore.DocumentSnapshot) (*models.Question, error) { // Generate a random offset randomOffset := rand.Intn(len(docs)) From 7b5e8800f7359fff66a568dd0c8d5023fdd670d3 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Fri, 25 Oct 2024 19:15:42 +0800 Subject: [PATCH 047/258] Replace button to question in question table with plain Link --- apps/frontend/src/app/question/page.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/frontend/src/app/question/page.tsx b/apps/frontend/src/app/question/page.tsx index 8fbb9502ea..63139bf7d6 100644 --- a/apps/frontend/src/app/question/page.tsx +++ b/apps/frontend/src/app/question/page.tsx @@ -287,7 +287,7 @@ export default function Home() { query: { data: question.docRefId }, // the data }} > - + {text} ), }, @@ -458,7 +458,7 @@ export default function Home() { query: { data: question.docRefId }, // the data }} > - + {text} ), }, From 125ce825499bfa123a69c54d14a4692873f2a8e0 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Fri, 25 Oct 2024 19:37:17 +0800 Subject: [PATCH 048/258] fix: proto dependency --- apps/matching-service/go.mod | 1 + .../matching-service/processes/findmatches.go | 38 ++- .../processes/performmatches.go | 7 +- .../proto/questionmatching.pb.go | 230 ------------------ .../proto/questionmatching_grpc.pb.go | 122 ---------- apps/matching-service/servers/grpc.go | 2 +- 6 files changed, 34 insertions(+), 366 deletions(-) delete mode 100644 apps/matching-service/proto/questionmatching.pb.go delete mode 100644 apps/matching-service/proto/questionmatching_grpc.pb.go diff --git a/apps/matching-service/go.mod b/apps/matching-service/go.mod index 5e0c70dc49..0dee610491 100644 --- a/apps/matching-service/go.mod +++ b/apps/matching-service/go.mod @@ -11,6 +11,7 @@ require ( github.com/redis/go-redis/v9 v9.6.2 google.golang.org/grpc v1.67.1 google.golang.org/protobuf v1.35.1 + proto v0.0.0-00010101000000-000000000000 ) require ( diff --git a/apps/matching-service/processes/findmatches.go b/apps/matching-service/processes/findmatches.go index e5e9632020..338f82006b 100644 --- a/apps/matching-service/processes/findmatches.go +++ b/apps/matching-service/processes/findmatches.go @@ -12,7 +12,7 @@ import ( ) // Find the first matching user from the front on the queue, based on topics, then difficulty. -func findMatchingUsers(tx *redis.Tx, currentUsername string, ctx context.Context) (*models.MatchFound, error) { +func findMatchingUser(tx *redis.Tx, currentUsername string, ctx context.Context) (*models.MatchFound, error) { currentUser, err := databases.GetUserDetails(tx, currentUsername, ctx) if err != nil { return nil, err @@ -153,14 +153,23 @@ func doTopicMatching(tx *redis.Tx, ctx context.Context, currentUser *models.Matc // Iterate through the queue to find a match, so a user in the queue the longest is more likely to be matched. var foundUsers []string - for _, otherUser := range potentialMatches { - if otherUser == currentUser.Username { + for _, otherUsername := range potentialMatches { + if otherUsername == currentUser.Username { continue } + // Include users without any difficulty selected + otherUser, err := databases.GetUserDetails(tx, otherUsername, ctx) + if err != nil { + return nil, err + } + if len(otherUser.Topics) == 0 { + foundUsers = append(foundUsers, otherUsername) + } + // other user has matching topic - if _, ok := sameTopicUsers[otherUser]; ok { - foundUsers = append(foundUsers, otherUser) + if _, ok := sameTopicUsers[otherUsername]; ok { + foundUsers = append(foundUsers, otherUsername) break } } @@ -181,14 +190,23 @@ func doDifficultyMatching(tx *redis.Tx, ctx context.Context, currentUser *models // Iterate through the queue to find a match, so a user in the queue the longest is more likely to be matched. var foundUsers []string - for _, otherUser := range potentialMatches { - if otherUser == currentUser.Username { + for _, otherUsername := range potentialMatches { + if otherUsername == currentUser.Username { continue } - // other user has matching difficulty - if _, ok := sameDifficultyUsers[otherUser]; ok { - foundUsers = append(foundUsers, otherUser) + // Include users without any difficulty selected + otherUser, err := databases.GetUserDetails(tx, otherUsername, ctx) + if err != nil { + return nil, err + } + if len(otherUser.Topics) == 0 { + foundUsers = append(foundUsers, otherUsername) + } + + // other user has matching difficulty or has no difficulty + if _, ok := sameDifficultyUsers[otherUsername]; ok { + foundUsers = append(foundUsers, otherUsername) break } } diff --git a/apps/matching-service/processes/performmatches.go b/apps/matching-service/processes/performmatches.go index 5c125bd08c..f91c04ecdd 100644 --- a/apps/matching-service/processes/performmatches.go +++ b/apps/matching-service/processes/performmatches.go @@ -8,7 +8,8 @@ import ( "log" "matching-service/databases" "matching-service/models" - pb "matching-service/proto" + pb "proto/questionmatching" + "matching-service/servers" "github.com/redis/go-redis/v9" @@ -39,7 +40,7 @@ func PerformMatching(rdb *redis.Client, matchRequest models.MatchRequest, ctx co defer databases.PrintMatchingQueue(tx, "After Matchmaking", ctx) // Find a matching user if any - matchFound, err = findMatchingUsers(tx, currentUsername, ctx) + matchFound, err = findMatchingUser(tx, currentUsername, ctx) if err != nil { if errors.Is(err, models.NoMatchFound) { return nil @@ -119,7 +120,7 @@ func queryQuestionService(ctx context.Context, matchFound *models.MatchFound) *m User: matchFound.User, MatchedUser: matchFound.MatchedUser, MatchedTopics: matchFound.MatchedTopics, - QuestionDocRefID: question.QuestionName, + QuestionDocRefID: question.QuestionDocRefId, QuestionName: question.QuestionName, QuestionDifficulty: question.QuestionDifficulty, QuestionTopics: question.QuestionTopics, diff --git a/apps/matching-service/proto/questionmatching.pb.go b/apps/matching-service/proto/questionmatching.pb.go deleted file mode 100644 index 23341165ce..0000000000 --- a/apps/matching-service/proto/questionmatching.pb.go +++ /dev/null @@ -1,230 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.35.1 -// protoc v3.21.12 -// source: questionmatching.proto - -package proto - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type MatchQuestionRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - MatchedTopics []string `protobuf:"bytes,1,rep,name=matched_topics,json=matchedTopics,proto3" json:"matched_topics,omitempty"` - MatchedDifficulties []string `protobuf:"bytes,2,rep,name=matched_difficulties,json=matchedDifficulties,proto3" json:"matched_difficulties,omitempty"` -} - -func (x *MatchQuestionRequest) Reset() { - *x = MatchQuestionRequest{} - mi := &file_questionmatching_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *MatchQuestionRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MatchQuestionRequest) ProtoMessage() {} - -func (x *MatchQuestionRequest) ProtoReflect() protoreflect.Message { - mi := &file_questionmatching_proto_msgTypes[0] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use MatchQuestionRequest.ProtoReflect.Descriptor instead. -func (*MatchQuestionRequest) Descriptor() ([]byte, []int) { - return file_questionmatching_proto_rawDescGZIP(), []int{0} -} - -func (x *MatchQuestionRequest) GetMatchedTopics() []string { - if x != nil { - return x.MatchedTopics - } - return nil -} - -func (x *MatchQuestionRequest) GetMatchedDifficulties() []string { - if x != nil { - return x.MatchedDifficulties - } - return nil -} - -type QuestionFound struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - QuestionId int64 `protobuf:"varint,1,opt,name=question_id,json=questionId,proto3" json:"question_id,omitempty"` - QuestionName string `protobuf:"bytes,2,opt,name=question_name,json=questionName,proto3" json:"question_name,omitempty"` - QuestionDifficulty string `protobuf:"bytes,3,opt,name=question_difficulty,json=questionDifficulty,proto3" json:"question_difficulty,omitempty"` - QuestionTopics []string `protobuf:"bytes,4,rep,name=question_topics,json=questionTopics,proto3" json:"question_topics,omitempty"` -} - -func (x *QuestionFound) Reset() { - *x = QuestionFound{} - mi := &file_questionmatching_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *QuestionFound) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*QuestionFound) ProtoMessage() {} - -func (x *QuestionFound) ProtoReflect() protoreflect.Message { - mi := &file_questionmatching_proto_msgTypes[1] - if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use QuestionFound.ProtoReflect.Descriptor instead. -func (*QuestionFound) Descriptor() ([]byte, []int) { - return file_questionmatching_proto_rawDescGZIP(), []int{1} -} - -func (x *QuestionFound) GetQuestionId() int64 { - if x != nil { - return x.QuestionId - } - return 0 -} - -func (x *QuestionFound) GetQuestionName() string { - if x != nil { - return x.QuestionName - } - return "" -} - -func (x *QuestionFound) GetQuestionDifficulty() string { - if x != nil { - return x.QuestionDifficulty - } - return "" -} - -func (x *QuestionFound) GetQuestionTopics() []string { - if x != nil { - return x.QuestionTopics - } - return nil -} - -var File_questionmatching_proto protoreflect.FileDescriptor - -var file_questionmatching_proto_rawDesc = []byte{ - 0x0a, 0x16, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x69, - 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, - 0x6f, 0x6e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x22, 0x70, 0x0a, 0x14, 0x4d, 0x61, - 0x74, 0x63, 0x68, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x74, 0x6f, - 0x70, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x6d, 0x61, 0x74, 0x63, - 0x68, 0x65, 0x64, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x12, 0x31, 0x0a, 0x14, 0x6d, 0x61, 0x74, - 0x63, 0x68, 0x65, 0x64, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x69, 0x65, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, - 0x44, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x69, 0x65, 0x73, 0x22, 0xaf, 0x01, 0x0a, - 0x0d, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x1f, - 0x0a, 0x0b, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x0a, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, - 0x23, 0x0a, 0x0d, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, - 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x13, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, - 0x5f, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x12, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x69, 0x66, 0x66, 0x69, - 0x63, 0x75, 0x6c, 0x74, 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x32, 0x7a, - 0x0a, 0x17, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, - 0x6e, 0x67, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5f, 0x0a, 0x14, 0x46, 0x69, 0x6e, - 0x64, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x26, 0x2e, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x61, 0x74, 0x63, - 0x68, 0x69, 0x6e, 0x67, 0x2e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x2e, 0x51, 0x75, 0x65, - 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_questionmatching_proto_rawDescOnce sync.Once - file_questionmatching_proto_rawDescData = file_questionmatching_proto_rawDesc -) - -func file_questionmatching_proto_rawDescGZIP() []byte { - file_questionmatching_proto_rawDescOnce.Do(func() { - file_questionmatching_proto_rawDescData = protoimpl.X.CompressGZIP(file_questionmatching_proto_rawDescData) - }) - return file_questionmatching_proto_rawDescData -} - -var file_questionmatching_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_questionmatching_proto_goTypes = []any{ - (*MatchQuestionRequest)(nil), // 0: questionmatching.MatchQuestionRequest - (*QuestionFound)(nil), // 1: questionmatching.QuestionFound -} -var file_questionmatching_proto_depIdxs = []int32{ - 0, // 0: questionmatching.QuestionMatchingService.FindMatchingQuestion:input_type -> questionmatching.MatchQuestionRequest - 1, // 1: questionmatching.QuestionMatchingService.FindMatchingQuestion:output_type -> questionmatching.QuestionFound - 1, // [1:2] is the sub-list for method output_type - 0, // [0:1] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_questionmatching_proto_init() } -func file_questionmatching_proto_init() { - if File_questionmatching_proto != nil { - return - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_questionmatching_proto_rawDesc, - NumEnums: 0, - NumMessages: 2, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_questionmatching_proto_goTypes, - DependencyIndexes: file_questionmatching_proto_depIdxs, - MessageInfos: file_questionmatching_proto_msgTypes, - }.Build() - File_questionmatching_proto = out.File - file_questionmatching_proto_rawDesc = nil - file_questionmatching_proto_goTypes = nil - file_questionmatching_proto_depIdxs = nil -} diff --git a/apps/matching-service/proto/questionmatching_grpc.pb.go b/apps/matching-service/proto/questionmatching_grpc.pb.go deleted file mode 100644 index 7d65ce155e..0000000000 --- a/apps/matching-service/proto/questionmatching_grpc.pb.go +++ /dev/null @@ -1,122 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.5.1 -// - protoc v3.21.12 -// source: questionmatching.proto - -package proto - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.64.0 or later. -const _ = grpc.SupportPackageIsVersion9 - -const ( - QuestionMatchingService_FindMatchingQuestion_FullMethodName = "/questionmatching.QuestionMatchingService/FindMatchingQuestion" -) - -// QuestionMatchingServiceClient is the client API for QuestionMatchingService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type QuestionMatchingServiceClient interface { - FindMatchingQuestion(ctx context.Context, in *MatchQuestionRequest, opts ...grpc.CallOption) (*QuestionFound, error) -} - -type questionMatchingServiceClient struct { - cc grpc.ClientConnInterface -} - -func NewQuestionMatchingServiceClient(cc grpc.ClientConnInterface) QuestionMatchingServiceClient { - return &questionMatchingServiceClient{cc} -} - -func (c *questionMatchingServiceClient) FindMatchingQuestion(ctx context.Context, in *MatchQuestionRequest, opts ...grpc.CallOption) (*QuestionFound, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(QuestionFound) - err := c.cc.Invoke(ctx, QuestionMatchingService_FindMatchingQuestion_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - -// QuestionMatchingServiceServer is the server API for QuestionMatchingService service. -// All implementations must embed UnimplementedQuestionMatchingServiceServer -// for forward compatibility. -type QuestionMatchingServiceServer interface { - FindMatchingQuestion(context.Context, *MatchQuestionRequest) (*QuestionFound, error) - mustEmbedUnimplementedQuestionMatchingServiceServer() -} - -// UnimplementedQuestionMatchingServiceServer must be embedded to have -// forward compatible implementations. -// -// NOTE: this should be embedded by value instead of pointer to avoid a nil -// pointer dereference when methods are called. -type UnimplementedQuestionMatchingServiceServer struct{} - -func (UnimplementedQuestionMatchingServiceServer) FindMatchingQuestion(context.Context, *MatchQuestionRequest) (*QuestionFound, error) { - return nil, status.Errorf(codes.Unimplemented, "method FindMatchingQuestion not implemented") -} -func (UnimplementedQuestionMatchingServiceServer) mustEmbedUnimplementedQuestionMatchingServiceServer() { -} -func (UnimplementedQuestionMatchingServiceServer) testEmbeddedByValue() {} - -// UnsafeQuestionMatchingServiceServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to QuestionMatchingServiceServer will -// result in compilation errors. -type UnsafeQuestionMatchingServiceServer interface { - mustEmbedUnimplementedQuestionMatchingServiceServer() -} - -func RegisterQuestionMatchingServiceServer(s grpc.ServiceRegistrar, srv QuestionMatchingServiceServer) { - // If the following call pancis, it indicates UnimplementedQuestionMatchingServiceServer was - // embedded by pointer and is nil. This will cause panics if an - // unimplemented method is ever invoked, so we test this at initialization - // time to prevent it from happening at runtime later due to I/O. - if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { - t.testEmbeddedByValue() - } - s.RegisterService(&QuestionMatchingService_ServiceDesc, srv) -} - -func _QuestionMatchingService_FindMatchingQuestion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MatchQuestionRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QuestionMatchingServiceServer).FindMatchingQuestion(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: QuestionMatchingService_FindMatchingQuestion_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QuestionMatchingServiceServer).FindMatchingQuestion(ctx, req.(*MatchQuestionRequest)) - } - return interceptor(ctx, in, info, handler) -} - -// QuestionMatchingService_ServiceDesc is the grpc.ServiceDesc for QuestionMatchingService service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var QuestionMatchingService_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "questionmatching.QuestionMatchingService", - HandlerType: (*QuestionMatchingServiceServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "FindMatchingQuestion", - Handler: _QuestionMatchingService_FindMatchingQuestion_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "questionmatching.proto", -} diff --git a/apps/matching-service/servers/grpc.go b/apps/matching-service/servers/grpc.go index c8f82fdc6d..e6bd8f799c 100644 --- a/apps/matching-service/servers/grpc.go +++ b/apps/matching-service/servers/grpc.go @@ -2,7 +2,7 @@ package servers import ( "log" - pb "matching-service/proto" + pb "proto/questionmatching" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" From c2ad34223e0cf92d70c0036d15b939b657059d5c Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Fri, 25 Oct 2024 20:07:25 +0800 Subject: [PATCH 049/258] feat: add simulation test --- .../tests/websocket-test.html | 144 ++++++++++++++++-- 1 file changed, 135 insertions(+), 9 deletions(-) diff --git a/apps/matching-service/tests/websocket-test.html b/apps/matching-service/tests/websocket-test.html index fdc74b5379..441e4c615b 100644 --- a/apps/matching-service/tests/websocket-test.html +++ b/apps/matching-service/tests/websocket-test.html @@ -24,7 +24,7 @@ .container { width: 100%; - max-width: 800px; + max-width: 1000px; padding: 20px; background-color: #ffffff; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); @@ -174,6 +174,13 @@

Matching Service: WebSocket Test

+ +
+
+

Summary of User Match Requests

+
@@ -227,17 +234,44 @@

Matching Service: WebSocket Test

} function openWebSocket(userId) { - if (sockets[`user${userId}`]) return; - + if (sockets[`user${userId}`]) return; // Do not open if already open const socket = new WebSocket("ws://localhost:8081/match"); sockets[`user${userId}`] = socket; - clearResponse(userId); + document.getElementById(`response${userId}`).innerText = ""; - socket.onopen = () => handleSocketOpen(socket, userId); - socket.onmessage = (event) => handleSocketMessage(event, userId); - socket.onerror = (error) => - console.log(`WebSocket error for User ${userId}:`, error); - socket.onclose = () => handleSocketClose(userId); + socket.onopen = function () { + console.log(`WebSocket for User ${userId} is open now.`); + const { username, topics, difficulties } = + userSettings[`user${userId}`]; + + socket.send( + JSON.stringify({ + type: "match_request", + username: username, + topics: topics, + difficulties: difficulties, + }) + ); + + document.getElementById( + `status${userId}` + ).innerText = `Status: matching in progress...`; + updateSummary(); // Refresh summary after opening + }; + + socket.onmessage = function (event) { + handleSocketMessage(event, userId); + updateSummary(); // Refresh summary on message + }; + + socket.onerror = function (error) { + console.log(`WebSocket error for User ${userId}: ` + error); + }; + + socket.onclose = function () { + console.log(`WebSocket for User ${userId} is closed now.`); + sockets[`user${userId}`] = null; + }; } function closeConnection(userId) { @@ -358,6 +392,8 @@

Matching Service: WebSocket Test

)}`; updateStatus(userId, "Status: unexpected response", "error"); } + + updateSummary(); // Refresh summary } function handleSocketClose(userId) { @@ -383,6 +419,96 @@

Matching Service: WebSocket Test

function getRandomDifficulties() { return difficultiesList.filter(() => Math.random() < 0.4); } + + let isSimulating = false; + + async function simulateUserRequestsWithDelay() { + if (isSimulating) { + alert( + "Simulation already in progress. Please wait until it finishes." + ); + return; + } + isSimulating = true; + + const maxUserCount = parseInt( + document.getElementById("userCount").value, + 10 + ); + initializeUsers(); // Clear existing users + for (let i = 1; i <= maxUserCount; i++) { + // Initialize and open WebSocket for each user + randomizeDetails(i); + openWebSocket(i); + + updateSummary(); // Update summary after each addition + + // Wait for the delay before adding the next user + await delay(1000); // 1 second delay between each user request + } + + isSimulating = false; + } + function updateSummary() { + const summaryContainer = document.getElementById("summary"); + summaryContainer.innerHTML = ""; // Clear previous summary + + // Create table structure + const summaryTable = document.createElement("table"); + summaryTable.style.width = "100%"; + summaryTable.style.borderCollapse = "collapse"; + + // Header row + summaryTable.innerHTML = ` + + Username + Status + Topics + Difficulty + + `; + + // Add each user's details to the table + Object.keys(userSettings).forEach((userId, index) => { + const user = userSettings[userId]; + const statusElement = document.getElementById(`status${index + 1}`); + const statusText = statusElement + ? statusElement.innerText + : "unknown"; + + // Apply color coding to status + let statusColor = "black"; + if (statusText.includes("matching in progress")) { + statusColor = "blue"; + } else if (statusText.includes("match found")) { + statusColor = "green"; + } else if (statusText.includes("timed out")) { + statusColor = "red"; + } + + // Create row for each user + const row = document.createElement("tr"); + row.innerHTML = ` + ${ + user.username + } + ${statusText} + ${user.topics.join( + ", " + )} + ${user.difficulties.join( + ", " + )} + `; + summaryTable.appendChild(row); + }); + + summaryContainer.appendChild(summaryTable); // Append the summary table to the container + } + + function delay(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); + } From 8aabda68508ca8ec4f40a8a7aedf415b3abed5a7 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Fri, 25 Oct 2024 20:19:42 +0800 Subject: [PATCH 050/258] fix: remove h1 --- apps/matching-service/tests/websocket-test.html | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/matching-service/tests/websocket-test.html b/apps/matching-service/tests/websocket-test.html index 441e4c615b..8ec3c1fe3a 100644 --- a/apps/matching-service/tests/websocket-test.html +++ b/apps/matching-service/tests/websocket-test.html @@ -169,7 +169,6 @@
-

Matching Service: WebSocket Test

From 47eb5f0668e479ed8333c7973a2ff41b91d1d873 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Fri, 25 Oct 2024 20:21:09 +0800 Subject: [PATCH 051/258] fix: margin --- apps/matching-service/tests/websocket-test.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/matching-service/tests/websocket-test.html b/apps/matching-service/tests/websocket-test.html index 8ec3c1fe3a..cd0717e099 100644 --- a/apps/matching-service/tests/websocket-test.html +++ b/apps/matching-service/tests/websocket-test.html @@ -168,7 +168,7 @@ -
+
From 2ff03c3944a45ab1393efa055cd573ca2dfa1f1d Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Fri, 25 Oct 2024 23:55:11 +0800 Subject: [PATCH 052/258] chore: move proto files into individual services --- apps/matching-service/README.md | 21 +- apps/matching-service/go.mod | 3 - .../processes/performmatches.go | 2 +- .../proto}/questionmatching.pb.go | 7 +- .../proto}/questionmatching_grpc.pb.go | 2 +- apps/matching-service/servers/grpc.go | 2 +- apps/proto/README.md | 3 +- apps/proto/go.mod | 15 -- apps/proto/go.sum | 14 -- apps/proto/questionmatching.proto | 2 +- apps/question-service/go.mod | 6 +- .../handlers/findmatchingquestion.go | 2 +- apps/question-service/handlers/server.go | 2 +- apps/question-service/main.go | 2 +- .../proto/questionmatching.pb.go | 231 ++++++++++++++++++ .../proto/questionmatching_grpc.pb.go | 122 +++++++++ 16 files changed, 380 insertions(+), 56 deletions(-) rename apps/{proto/questionmatching => matching-service/proto}/questionmatching.pb.go (97%) rename apps/{proto/questionmatching => matching-service/proto}/questionmatching_grpc.pb.go (99%) delete mode 100644 apps/proto/go.mod delete mode 100644 apps/proto/go.sum create mode 100644 apps/question-service/proto/questionmatching.pb.go create mode 100644 apps/question-service/proto/questionmatching_grpc.pb.go diff --git a/apps/matching-service/README.md b/apps/matching-service/README.md index 641a890fe5..90935e71ff 100644 --- a/apps/matching-service/README.md +++ b/apps/matching-service/README.md @@ -76,7 +76,7 @@ Client sends matching parameters: "type": "match_request", "topics": ["Algorithms", "Arrays"], "difficulties": ["Easy", "Medium"], - "username": "Jane Doe" + "username": "1f0myn" } ``` @@ -84,12 +84,15 @@ Server response on successful match: ```json { - "type": "match_found", - "matchId": "1c018916a34c5bee21af0b2670bd6156", - "user": "zkb4px", - "matchedUser": "JohnDoe", - "topic": "Algorithms", - "difficulty": "Medium" + "type": "match_question_found", + "match_id": "c377f463d380a9bd1dd03242892ef32e", + "user": "1f0myn", + "matched_user": "jrsznp", + "matched_topics": ["Graphs", "Bit Manipulation", "Databases"], + "question_doc_ref_id": "5lObMfyyKPgNXSuLcGEm", + "question_name": "Repeated DNA Sequences", + "question_difficulty": "medium", + "question_topics": ["Algorithms", "Bit Manipulation"] } ``` @@ -128,21 +131,25 @@ Before running the following commands, ensure that the URL for the Redis server To run the application via Docker, run the following command: 1. Set up the Go Docker container for the matching service + ```bash docker build -f Dockerfile -t match-go-app . ``` 2. Create the Docker network for Redis and Go + ```bash docker network create redis-go-network ``` 3. Start a new Redis container in detached mode using the Redis image from Docker Hub + ```bash docker run -d --name redis-container --network redis-go-network redis ``` 4. Run the Go Docker container for the matching-service + ```bash docker run -d -p 8081:8081 --name go-app-container --network redis-go-network match-go-app ``` diff --git a/apps/matching-service/go.mod b/apps/matching-service/go.mod index 0dee610491..e4ee0c799d 100644 --- a/apps/matching-service/go.mod +++ b/apps/matching-service/go.mod @@ -2,8 +2,6 @@ module matching-service go 1.23.1 -replace proto => ../proto - require ( github.com/bsm/redislock v0.9.4 github.com/gorilla/websocket v1.5.3 @@ -11,7 +9,6 @@ require ( github.com/redis/go-redis/v9 v9.6.2 google.golang.org/grpc v1.67.1 google.golang.org/protobuf v1.35.1 - proto v0.0.0-00010101000000-000000000000 ) require ( diff --git a/apps/matching-service/processes/performmatches.go b/apps/matching-service/processes/performmatches.go index f91c04ecdd..2263ebbcf0 100644 --- a/apps/matching-service/processes/performmatches.go +++ b/apps/matching-service/processes/performmatches.go @@ -8,7 +8,7 @@ import ( "log" "matching-service/databases" "matching-service/models" - pb "proto/questionmatching" + pb "matching-service/proto" "matching-service/servers" diff --git a/apps/proto/questionmatching/questionmatching.pb.go b/apps/matching-service/proto/questionmatching.pb.go similarity index 97% rename from apps/proto/questionmatching/questionmatching.pb.go rename to apps/matching-service/proto/questionmatching.pb.go index 6cc7856274..f5081758fa 100644 --- a/apps/proto/questionmatching/questionmatching.pb.go +++ b/apps/matching-service/proto/questionmatching.pb.go @@ -4,7 +4,7 @@ // protoc v3.21.12 // source: questionmatching.proto -package questionmatching +package proto import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -174,9 +174,8 @@ var file_questionmatching_proto_rawDesc = []byte{ 0x6e, 0x67, 0x2e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x2e, 0x51, 0x75, 0x65, 0x73, 0x74, - 0x69, 0x6f, 0x6e, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x14, 0x5a, 0x12, 0x2e, 0x2f, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x6f, 0x6e, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/apps/proto/questionmatching/questionmatching_grpc.pb.go b/apps/matching-service/proto/questionmatching_grpc.pb.go similarity index 99% rename from apps/proto/questionmatching/questionmatching_grpc.pb.go rename to apps/matching-service/proto/questionmatching_grpc.pb.go index fcbd3f9204..7d65ce155e 100644 --- a/apps/proto/questionmatching/questionmatching_grpc.pb.go +++ b/apps/matching-service/proto/questionmatching_grpc.pb.go @@ -4,7 +4,7 @@ // - protoc v3.21.12 // source: questionmatching.proto -package questionmatching +package proto import ( context "context" diff --git a/apps/matching-service/servers/grpc.go b/apps/matching-service/servers/grpc.go index e6bd8f799c..c8f82fdc6d 100644 --- a/apps/matching-service/servers/grpc.go +++ b/apps/matching-service/servers/grpc.go @@ -2,7 +2,7 @@ package servers import ( "log" - pb "proto/questionmatching" + pb "matching-service/proto" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" diff --git a/apps/proto/README.md b/apps/proto/README.md index 4237db5513..ca87aca110 100644 --- a/apps/proto/README.md +++ b/apps/proto/README.md @@ -36,7 +36,8 @@ export PATH="$PATH:$(go env GOPATH)/bin" Now use the protoc compiler to generate the Go code for the service and messages. ```bash -protoc --go_out=. --go-grpc_out=. ./questionmatching.proto +protoc --go_out=../matching-service --go-grpc_out=../matching-service ./questionmatching.proto +protoc --go_out=../question-service --go-grpc_out=../question-service ./questionmatching.proto ``` This command will generate two files: diff --git a/apps/proto/go.mod b/apps/proto/go.mod deleted file mode 100644 index 2fdc33b3a7..0000000000 --- a/apps/proto/go.mod +++ /dev/null @@ -1,15 +0,0 @@ -module proto - -go 1.23.1 - -require ( - google.golang.org/grpc v1.67.1 - google.golang.org/protobuf v1.35.1 -) - -require ( - golang.org/x/net v0.28.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect -) diff --git a/apps/proto/go.sum b/apps/proto/go.sum deleted file mode 100644 index a8432dc823..0000000000 --- a/apps/proto/go.sum +++ /dev/null @@ -1,14 +0,0 @@ -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= -google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= -google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= diff --git a/apps/proto/questionmatching.proto b/apps/proto/questionmatching.proto index 803e1d9edb..46d4d24c49 100644 --- a/apps/proto/questionmatching.proto +++ b/apps/proto/questionmatching.proto @@ -2,7 +2,7 @@ syntax = "proto3"; package questionmatching; -option go_package = "./questionmatching"; +option go_package = "./proto"; message MatchQuestionRequest { repeated string matched_topics = 1; diff --git a/apps/question-service/go.mod b/apps/question-service/go.mod index 97683f31fd..481f8efbb7 100644 --- a/apps/question-service/go.mod +++ b/apps/question-service/go.mod @@ -1,9 +1,5 @@ module question-service -require proto v0.0.0 - -replace proto => ../proto - go 1.23.1 require ( @@ -53,5 +49,5 @@ require ( google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/protobuf v1.35.1 // indirect + google.golang.org/protobuf v1.35.1 ) diff --git a/apps/question-service/handlers/findmatchingquestion.go b/apps/question-service/handlers/findmatchingquestion.go index 7590282ba7..44f830add2 100644 --- a/apps/question-service/handlers/findmatchingquestion.go +++ b/apps/question-service/handlers/findmatchingquestion.go @@ -5,8 +5,8 @@ import ( "errors" "log" "math/rand" - pb "proto/questionmatching" "question-service/models" + pb "question-service/proto" "cloud.google.com/go/firestore" ) diff --git a/apps/question-service/handlers/server.go b/apps/question-service/handlers/server.go index 9c0031327c..27c1b20bfb 100644 --- a/apps/question-service/handlers/server.go +++ b/apps/question-service/handlers/server.go @@ -1,7 +1,7 @@ package handlers import ( - pb "proto/questionmatching" + pb "question-service/proto" "cloud.google.com/go/firestore" ) diff --git a/apps/question-service/main.go b/apps/question-service/main.go index b4ef33fc40..349a66402e 100644 --- a/apps/question-service/main.go +++ b/apps/question-service/main.go @@ -8,9 +8,9 @@ import ( "net" "net/http" "os" - pb "proto/questionmatching" "question-service/handlers" mymiddleware "question-service/middleware" + pb "question-service/proto" "question-service/utils" "time" diff --git a/apps/question-service/proto/questionmatching.pb.go b/apps/question-service/proto/questionmatching.pb.go new file mode 100644 index 0000000000..f5081758fa --- /dev/null +++ b/apps/question-service/proto/questionmatching.pb.go @@ -0,0 +1,231 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc v3.21.12 +// source: questionmatching.proto + +package proto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type MatchQuestionRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + MatchedTopics []string `protobuf:"bytes,1,rep,name=matched_topics,json=matchedTopics,proto3" json:"matched_topics,omitempty"` + MatchedDifficulties []string `protobuf:"bytes,2,rep,name=matched_difficulties,json=matchedDifficulties,proto3" json:"matched_difficulties,omitempty"` +} + +func (x *MatchQuestionRequest) Reset() { + *x = MatchQuestionRequest{} + mi := &file_questionmatching_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MatchQuestionRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MatchQuestionRequest) ProtoMessage() {} + +func (x *MatchQuestionRequest) ProtoReflect() protoreflect.Message { + mi := &file_questionmatching_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MatchQuestionRequest.ProtoReflect.Descriptor instead. +func (*MatchQuestionRequest) Descriptor() ([]byte, []int) { + return file_questionmatching_proto_rawDescGZIP(), []int{0} +} + +func (x *MatchQuestionRequest) GetMatchedTopics() []string { + if x != nil { + return x.MatchedTopics + } + return nil +} + +func (x *MatchQuestionRequest) GetMatchedDifficulties() []string { + if x != nil { + return x.MatchedDifficulties + } + return nil +} + +type QuestionFound struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + QuestionDocRefId string `protobuf:"bytes,1,opt,name=question_doc_ref_id,json=questionDocRefId,proto3" json:"question_doc_ref_id,omitempty"` + QuestionName string `protobuf:"bytes,2,opt,name=question_name,json=questionName,proto3" json:"question_name,omitempty"` + QuestionDifficulty string `protobuf:"bytes,3,opt,name=question_difficulty,json=questionDifficulty,proto3" json:"question_difficulty,omitempty"` + QuestionTopics []string `protobuf:"bytes,4,rep,name=question_topics,json=questionTopics,proto3" json:"question_topics,omitempty"` +} + +func (x *QuestionFound) Reset() { + *x = QuestionFound{} + mi := &file_questionmatching_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *QuestionFound) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QuestionFound) ProtoMessage() {} + +func (x *QuestionFound) ProtoReflect() protoreflect.Message { + mi := &file_questionmatching_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use QuestionFound.ProtoReflect.Descriptor instead. +func (*QuestionFound) Descriptor() ([]byte, []int) { + return file_questionmatching_proto_rawDescGZIP(), []int{1} +} + +func (x *QuestionFound) GetQuestionDocRefId() string { + if x != nil { + return x.QuestionDocRefId + } + return "" +} + +func (x *QuestionFound) GetQuestionName() string { + if x != nil { + return x.QuestionName + } + return "" +} + +func (x *QuestionFound) GetQuestionDifficulty() string { + if x != nil { + return x.QuestionDifficulty + } + return "" +} + +func (x *QuestionFound) GetQuestionTopics() []string { + if x != nil { + return x.QuestionTopics + } + return nil +} + +var File_questionmatching_proto protoreflect.FileDescriptor + +var file_questionmatching_proto_rawDesc = []byte{ + 0x0a, 0x16, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x69, + 0x6e, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, + 0x6f, 0x6e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x22, 0x70, 0x0a, 0x14, 0x4d, 0x61, + 0x74, 0x63, 0x68, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x74, 0x6f, + 0x70, 0x69, 0x63, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x6d, 0x61, 0x74, 0x63, + 0x68, 0x65, 0x64, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x12, 0x31, 0x0a, 0x14, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x65, 0x64, 0x5f, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x69, 0x65, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, + 0x44, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x69, 0x65, 0x73, 0x22, 0xbd, 0x01, 0x0a, + 0x0d, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x2d, + 0x0a, 0x13, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x6f, 0x63, 0x5f, 0x72, + 0x65, 0x66, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x6f, 0x63, 0x52, 0x65, 0x66, 0x49, 0x64, 0x12, 0x23, 0x0a, + 0x0d, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x13, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, + 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x12, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, + 0x6c, 0x74, 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x32, 0x7a, 0x0a, 0x17, + 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5f, 0x0a, 0x14, 0x46, 0x69, 0x6e, 0x64, 0x4d, + 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x26, 0x2e, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x69, + 0x6e, 0x67, 0x2e, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x51, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x71, 0x75, 0x65, 0x73, 0x74, 0x69, + 0x6f, 0x6e, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x2e, 0x51, 0x75, 0x65, 0x73, 0x74, + 0x69, 0x6f, 0x6e, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_questionmatching_proto_rawDescOnce sync.Once + file_questionmatching_proto_rawDescData = file_questionmatching_proto_rawDesc +) + +func file_questionmatching_proto_rawDescGZIP() []byte { + file_questionmatching_proto_rawDescOnce.Do(func() { + file_questionmatching_proto_rawDescData = protoimpl.X.CompressGZIP(file_questionmatching_proto_rawDescData) + }) + return file_questionmatching_proto_rawDescData +} + +var file_questionmatching_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_questionmatching_proto_goTypes = []any{ + (*MatchQuestionRequest)(nil), // 0: questionmatching.MatchQuestionRequest + (*QuestionFound)(nil), // 1: questionmatching.QuestionFound +} +var file_questionmatching_proto_depIdxs = []int32{ + 0, // 0: questionmatching.QuestionMatchingService.FindMatchingQuestion:input_type -> questionmatching.MatchQuestionRequest + 1, // 1: questionmatching.QuestionMatchingService.FindMatchingQuestion:output_type -> questionmatching.QuestionFound + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_questionmatching_proto_init() } +func file_questionmatching_proto_init() { + if File_questionmatching_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_questionmatching_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_questionmatching_proto_goTypes, + DependencyIndexes: file_questionmatching_proto_depIdxs, + MessageInfos: file_questionmatching_proto_msgTypes, + }.Build() + File_questionmatching_proto = out.File + file_questionmatching_proto_rawDesc = nil + file_questionmatching_proto_goTypes = nil + file_questionmatching_proto_depIdxs = nil +} diff --git a/apps/question-service/proto/questionmatching_grpc.pb.go b/apps/question-service/proto/questionmatching_grpc.pb.go new file mode 100644 index 0000000000..7d65ce155e --- /dev/null +++ b/apps/question-service/proto/questionmatching_grpc.pb.go @@ -0,0 +1,122 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v3.21.12 +// source: questionmatching.proto + +package proto + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + QuestionMatchingService_FindMatchingQuestion_FullMethodName = "/questionmatching.QuestionMatchingService/FindMatchingQuestion" +) + +// QuestionMatchingServiceClient is the client API for QuestionMatchingService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type QuestionMatchingServiceClient interface { + FindMatchingQuestion(ctx context.Context, in *MatchQuestionRequest, opts ...grpc.CallOption) (*QuestionFound, error) +} + +type questionMatchingServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewQuestionMatchingServiceClient(cc grpc.ClientConnInterface) QuestionMatchingServiceClient { + return &questionMatchingServiceClient{cc} +} + +func (c *questionMatchingServiceClient) FindMatchingQuestion(ctx context.Context, in *MatchQuestionRequest, opts ...grpc.CallOption) (*QuestionFound, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(QuestionFound) + err := c.cc.Invoke(ctx, QuestionMatchingService_FindMatchingQuestion_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QuestionMatchingServiceServer is the server API for QuestionMatchingService service. +// All implementations must embed UnimplementedQuestionMatchingServiceServer +// for forward compatibility. +type QuestionMatchingServiceServer interface { + FindMatchingQuestion(context.Context, *MatchQuestionRequest) (*QuestionFound, error) + mustEmbedUnimplementedQuestionMatchingServiceServer() +} + +// UnimplementedQuestionMatchingServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedQuestionMatchingServiceServer struct{} + +func (UnimplementedQuestionMatchingServiceServer) FindMatchingQuestion(context.Context, *MatchQuestionRequest) (*QuestionFound, error) { + return nil, status.Errorf(codes.Unimplemented, "method FindMatchingQuestion not implemented") +} +func (UnimplementedQuestionMatchingServiceServer) mustEmbedUnimplementedQuestionMatchingServiceServer() { +} +func (UnimplementedQuestionMatchingServiceServer) testEmbeddedByValue() {} + +// UnsafeQuestionMatchingServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to QuestionMatchingServiceServer will +// result in compilation errors. +type UnsafeQuestionMatchingServiceServer interface { + mustEmbedUnimplementedQuestionMatchingServiceServer() +} + +func RegisterQuestionMatchingServiceServer(s grpc.ServiceRegistrar, srv QuestionMatchingServiceServer) { + // If the following call pancis, it indicates UnimplementedQuestionMatchingServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&QuestionMatchingService_ServiceDesc, srv) +} + +func _QuestionMatchingService_FindMatchingQuestion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MatchQuestionRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QuestionMatchingServiceServer).FindMatchingQuestion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: QuestionMatchingService_FindMatchingQuestion_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QuestionMatchingServiceServer).FindMatchingQuestion(ctx, req.(*MatchQuestionRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// QuestionMatchingService_ServiceDesc is the grpc.ServiceDesc for QuestionMatchingService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var QuestionMatchingService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "questionmatching.QuestionMatchingService", + HandlerType: (*QuestionMatchingServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "FindMatchingQuestion", + Handler: _QuestionMatchingService_FindMatchingQuestion_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "questionmatching.proto", +} From f2683321bc17d992ff7fb3f2985c1c53fe2df43d Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Sat, 26 Oct 2024 01:14:22 +0800 Subject: [PATCH 053/258] feat: update docker and env --- .github/workflows/test.yml | 2 + apps/README.md | 2 +- apps/docker-compose.yml | 1 + .../modalContent/FindMatchContent.tsx | 4 +- .../frontend/src/app/services/use-matching.ts | 41 +++++++------------ .../src/contexts/websocketcontext.tsx | 1 - apps/matching-service/.env.example | 6 ++- apps/matching-service/README.md | 4 +- apps/matching-service/servers/grpc.go | 8 ++-- apps/question-service/Dockerfile | 2 +- apps/question-service/README.md | 2 +- 11 files changed, 34 insertions(+), 39 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0d2a1ad306..877de8eaf8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -36,6 +36,7 @@ jobs: MATCHING_SERVICE_PORT: ${{ vars.MATCHING_SERVICE_PORT }} MATCHING_SERVICE_TIMEOUT: ${{ vars.MATCHING_SERVICE_TIMEOUT }} REDIS_URL: ${{ vars.REDIS_URL }} + QUESTION_SERVICE_GRPC_URL: ${{ vars.QUESTION_SERVICE_GPRC_URL }} run: | cd ./apps/frontend echo "NEXT_PUBLIC_QUESTION_SERVICE_URL=$QUESTION_SERVICE_URL" >> .env @@ -56,6 +57,7 @@ jobs: echo "MATCH_TIMEOUT=$MATCHING_SERVICE_TIMEOUT" >> .env echo "JWT_SECRET=$JWT_SECRET" >> .env echo "REDIS_URL=$REDIS_URL" >> .env + echo "QUESTION_SERVICE_GRPC_URL=$QUESTION_SERVICE_GRPC_URL" >> .env - name: Create Database Credential Files env: diff --git a/apps/README.md b/apps/README.md index 18525dd4f6..ae12a36fc1 100644 --- a/apps/README.md +++ b/apps/README.md @@ -56,7 +56,7 @@ Once running, you can access: - The **frontend** at http://localhost:3000 - The **user service** at http://localhost:3001 -- The **question service** at http://localhost:8080 +- The **question service** at http://localhost:8080 (REST) and http://localhost:50051 (gRPC) - The **matching service** at http://localhost:8081 - The **redis service** at http://localhost:6379 diff --git a/apps/docker-compose.yml b/apps/docker-compose.yml index e69e2bcc65..a8ee1986f9 100644 --- a/apps/docker-compose.yml +++ b/apps/docker-compose.yml @@ -31,6 +31,7 @@ services: dockerfile: Dockerfile ports: - 8080:8080 + - 50051:50051 env_file: - ./question-service/.env networks: diff --git a/apps/frontend/src/app/matching/modalContent/FindMatchContent.tsx b/apps/frontend/src/app/matching/modalContent/FindMatchContent.tsx index ac65cbe033..383f049385 100644 --- a/apps/frontend/src/app/matching/modalContent/FindMatchContent.tsx +++ b/apps/frontend/src/app/matching/modalContent/FindMatchContent.tsx @@ -94,8 +94,8 @@ const DifficultySelector: React.FC = ({ selectedDifficu handleChange(difficultyOption.label)} + checked={selectedDifficulties.includes(difficultyOption.value)} + onChange={() => handleChange(difficultyOption.value)} > {difficultyOption.label} diff --git a/apps/frontend/src/app/services/use-matching.ts b/apps/frontend/src/app/services/use-matching.ts index ce9d463b53..4a37c9f153 100644 --- a/apps/frontend/src/app/services/use-matching.ts +++ b/apps/frontend/src/app/services/use-matching.ts @@ -17,17 +17,15 @@ export type MatchRequestParams = { } export type MatchFoundResponse = { - type: "match_found", - matchId: number, - partnerId: number, - partnerName: string, -} | { - type: "match_found", - matchId: string, + type: "match_question_found", + match_id: string, user: string, - matchedUser: string, - topic: string | string[], - difficulty: string + matched_user: string, + matched_topics: string[], + question_doc_ref_id: string, + question_name: string, + question_difficulty: string, + question_topics: string[], } export type MatchTimeoutResponse = { @@ -61,7 +59,7 @@ export default function useMatching(): MatchState { return; } - if (responseJson.type == "match_found") { + if (responseJson.type == "match_question_found") { setIsSocket(false); const info: MatchInfo = parseInfoFromResponse(responseJson); @@ -136,20 +134,9 @@ export default function useMatching(): MatchState { } function parseInfoFromResponse(responseJson: MatchFoundResponse): MatchInfo { - // test whether old or new - if ("partnerId" in responseJson) { - return { - matchId: responseJson.matchId?.toString() ?? "unknown", - partnerId: responseJson.partnerId?.toString() ?? "unknown", - partnerName: responseJson.partnerName ?? "unknown", - myName: "unknown", - }; - } else { - return { - matchId: responseJson.matchId?.toString() ?? "unknown", - partnerId: "unknown", - partnerName: responseJson.matchedUser ?? "unknown", - myName: responseJson.user ?? "unknown", - }; - } + return { + matchId: responseJson.match_id?.toString() ?? "unknown", + partnerName: responseJson.matched_user ?? "unknown", + myName: responseJson.user ?? "unknown", + }; } diff --git a/apps/frontend/src/contexts/websocketcontext.tsx b/apps/frontend/src/contexts/websocketcontext.tsx index fe0c95624d..84893c15ed 100644 --- a/apps/frontend/src/contexts/websocketcontext.tsx +++ b/apps/frontend/src/contexts/websocketcontext.tsx @@ -15,7 +15,6 @@ export type SocketState = { }; export type MatchInfo = { matchId: string; - partnerId: string; myName: string; partnerName: string; } diff --git a/apps/matching-service/.env.example b/apps/matching-service/.env.example index 8fc9a4032a..50dc113f63 100644 --- a/apps/matching-service/.env.example +++ b/apps/matching-service/.env.example @@ -2,8 +2,10 @@ PORT=8081 MATCH_TIMEOUT=30 JWT_SECRET=you-can-replace-this-with-your-own-secret -# if you are NOT USING docker, use the below url +# If you are NOT USING docker, use the below variables REDIS_URL=localhost:6379 +QUESTION_SERVICE_GRPC_URL=localhost:50051 -# if you are USING docker, use the below url +# If you are USING docker, use the below variables # REDIS_URL=redis-container:6379 +# QUESTION_SERVICE_GRPC_URL=question-service:50051 diff --git a/apps/matching-service/README.md b/apps/matching-service/README.md index 90935e71ff..92b957c7b0 100644 --- a/apps/matching-service/README.md +++ b/apps/matching-service/README.md @@ -75,7 +75,7 @@ Client sends matching parameters: { "type": "match_request", "topics": ["Algorithms", "Arrays"], - "difficulties": ["Easy", "Medium"], + "difficulties": ["easy", "medium"], "username": "1f0myn" } ``` @@ -153,3 +153,5 @@ docker run -d --name redis-container --network redis-go-network redis ```bash docker run -d -p 8081:8081 --name go-app-container --network redis-go-network match-go-app ``` + +**NOTE:** As there is a dependency on the question-service to return the found questions, the matching-service does not work fully unless the question-service is present. diff --git a/apps/matching-service/servers/grpc.go b/apps/matching-service/servers/grpc.go index c8f82fdc6d..a6a2aac507 100644 --- a/apps/matching-service/servers/grpc.go +++ b/apps/matching-service/servers/grpc.go @@ -3,6 +3,7 @@ package servers import ( "log" pb "matching-service/proto" + "os" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -13,12 +14,13 @@ var ( ) func InitGrpcServer() *grpc.ClientConn { + questionServiceAddr := os.Getenv("QUESTION_SERVICE_GRPC_URL") // Dial the server - conn, err := grpc.NewClient("localhost:50051", grpc.WithTransportCredentials(insecure.NewCredentials())) + conn, err := grpc.NewClient(questionServiceAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { - log.Fatalf("Did not connect: %v", err) + log.Fatalf("Did not connect to %v: %v", questionServiceAddr, err) } else { - log.Println("Connected to Grpc server at :50051") + log.Println("Connected to Grpc server at %v", questionServiceAddr) } // Create a new client for the ExampleService diff --git a/apps/question-service/Dockerfile b/apps/question-service/Dockerfile index c2a9e0836b..0f7b9b698a 100644 --- a/apps/question-service/Dockerfile +++ b/apps/question-service/Dockerfile @@ -11,6 +11,6 @@ COPY . . RUN go build -v -o /usr/local/bin/app ./main.go -EXPOSE 8080 +EXPOSE 8080 50051 CMD ["app"] diff --git a/apps/question-service/README.md b/apps/question-service/README.md index 99ed749159..3045231030 100644 --- a/apps/question-service/README.md +++ b/apps/question-service/README.md @@ -58,7 +58,7 @@ docker build -t question-service . ``` ```bash -docker run -p 8080:8080 --env-file .env -d question-service +docker run -p 8080:8080 -p 50051:50051 --env-file .env -d question-service ``` The server will be available at http://localhost:8080. From e58e4afd7c84a621d21f93e2da82bab9b4f54877 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Sat, 26 Oct 2024 14:34:44 +0800 Subject: [PATCH 054/258] fix: return error if unable to lock --- apps/matching-service/handlers/responses.go | 11 ++++++++++- apps/matching-service/handlers/websocket.go | 4 +++- apps/matching-service/processes/performmatches.go | 1 + 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/matching-service/handlers/responses.go b/apps/matching-service/handlers/responses.go index 4c38a982c2..1baa208473 100644 --- a/apps/matching-service/handlers/responses.go +++ b/apps/matching-service/handlers/responses.go @@ -18,7 +18,7 @@ func sendTimeoutResponse(ws *websocket.Conn) { } } -func sendRejectionResponse(ws *websocket.Conn) { +func sendDuplicateUserRejectionResponse(ws *websocket.Conn) { if err := ws.WriteJSON(models.MatchRejected{ Type: "match_rejected", Message: "You are already in a matchmaking queue. Please disconnect before reconnecting.", @@ -27,6 +27,15 @@ func sendRejectionResponse(ws *websocket.Conn) { } } +func sendDefaultRejectionResponse(ws *websocket.Conn) { + if err := ws.WriteJSON(models.MatchRejected{ + Type: "match_rejected", + Message: "An unexpected error occurred. Please try again later.", + }); err != nil { + log.Printf("write error: %v", err) + } +} + // Send message to matched user func sendMatchFoundResponse(ws *websocket.Conn, username string, result models.MatchQuestionFound) { if err := ws.WriteJSON(result); err != nil { diff --git a/apps/matching-service/handlers/websocket.go b/apps/matching-service/handlers/websocket.go index f7ea976c29..6b28340c1d 100644 --- a/apps/matching-service/handlers/websocket.go +++ b/apps/matching-service/handlers/websocket.go @@ -124,9 +124,11 @@ func waitForResult(ws *websocket.Conn, userCtx, timeoutCtx context.Context, matc if !ok { return } + log.Printf("Error occured performing matching: %v", err) if errors.Is(err, models.ExistingUserError) { - sendRejectionResponse(ws) + sendDuplicateUserRejectionResponse(ws) } else { + sendDefaultRejectionResponse(ws) cleanUpUser(username) } return diff --git a/apps/matching-service/processes/performmatches.go b/apps/matching-service/processes/performmatches.go index 2263ebbcf0..0c9740338b 100644 --- a/apps/matching-service/processes/performmatches.go +++ b/apps/matching-service/processes/performmatches.go @@ -24,6 +24,7 @@ func PerformMatching(rdb *redis.Client, matchRequest models.MatchRequest, ctx co // Obtain lock with retry lock, err := servers.ObtainRedisLock(ctx) if err != nil { + errorChan <- err return } defer lock.Release(ctx) From 8f5318f672e5ce6abfae787c2aa4de2f93fbbba9 Mon Sep 17 00:00:00 2001 From: solomonng2001 Date: Sat, 26 Oct 2024 20:06:43 +0800 Subject: [PATCH 055/258] Add collaboration fetch question --- apps/frontend/pnpm-lock.yaml | 4345 +++++++++-------- .../src/app/matching/MatchingModal.tsx | 3 +- .../frontend/src/app/services/use-matching.ts | 1 + .../src/contexts/websocketcontext.tsx | 1 + 4 files changed, 2391 insertions(+), 1959 deletions(-) diff --git a/apps/frontend/pnpm-lock.yaml b/apps/frontend/pnpm-lock.yaml index 23a3402952..c114790857 100644 --- a/apps/frontend/pnpm-lock.yaml +++ b/apps/frontend/pnpm-lock.yaml @@ -1,120 +1,1976 @@ -lockfileVersion: '6.0' +lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -dependencies: - '@ant-design/icons': - specifier: ^5.5.1 - version: 5.5.1(react-dom@18.2.0)(react@18.2.0) - '@ant-design/nextjs-registry': - specifier: ^1.0.1 - version: 1.0.1(@ant-design/cssinjs@1.21.1)(antd@5.20.6)(next@14.2.13)(react-dom@18.2.0)(react@18.2.0) - '@codemirror/lang-cpp': - specifier: ^6.0.2 - version: 6.0.2 - '@codemirror/lang-go': - specifier: ^6.0.1 - version: 6.0.1(@codemirror/view@6.34.1) - '@codemirror/lang-java': - specifier: ^6.0.1 - version: 6.0.1 - '@codemirror/lang-javascript': - specifier: ^6.2.2 - version: 6.2.2 - '@codemirror/lang-python': - specifier: ^6.1.6 - version: 6.1.6(@codemirror/view@6.34.1) - '@codemirror/language': - specifier: ^6.10.3 - version: 6.10.3 - '@codemirror/state': - specifier: ^6.4.1 - version: 6.4.1 - antd: - specifier: ^5.20.6 - version: 5.20.6(react-dom@18.2.0)(react@18.2.0) - codemirror: - specifier: ^6.0.1 - version: 6.0.1(@lezer/common@1.2.3) - next: - specifier: 14.2.13 - version: 14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2) - react: - specifier: ^18.2.0 - version: 18.2.0 - react-dom: - specifier: ^18.2.0 - version: 18.2.0(react@18.2.0) - react-timer-hook: - specifier: ^3.0.7 - version: 3.0.7(react@18.2.0) - react-use-websocket: - specifier: ^4.9.0 - version: 4.9.0 - sass: - specifier: ^1.79.2 - version: 1.79.2 - typeface-montserrat: - specifier: ^1.1.13 - version: 1.1.13 - y-codemirror.next: - specifier: ^0.3.5 - version: 0.3.5(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(yjs@13.6.20) - y-webrtc: - specifier: ^10.3.0 - version: 10.3.0(yjs@13.6.20) - yjs: - specifier: ^13.6.20 - version: 13.6.20 - -devDependencies: - '@types/node': - specifier: ^20 - version: 20.0.0 - '@types/react': - specifier: ^18.3.8 - version: 18.3.8 - '@types/react-dom': - specifier: ^18.3.0 - version: 18.3.0 - eslint: - specifier: ^8 - version: 8.0.0 - eslint-config-next: - specifier: 14.2.13 - version: 14.2.13(eslint@8.0.0)(typescript@5.0.2) - typescript: - specifier: ^5 - version: 5.0.2 +importers: + + .: + dependencies: + '@ant-design/icons': + specifier: ^5.5.1 + version: 5.5.1(react-dom@18.2.0)(react@18.2.0) + '@ant-design/nextjs-registry': + specifier: ^1.0.1 + version: 1.0.1(@ant-design/cssinjs@1.21.1)(antd@5.20.6)(next@14.2.13)(react-dom@18.2.0)(react@18.2.0) + '@codemirror/lang-cpp': + specifier: ^6.0.2 + version: 6.0.2 + '@codemirror/lang-go': + specifier: ^6.0.1 + version: 6.0.1(@codemirror/view@6.34.1) + '@codemirror/lang-java': + specifier: ^6.0.1 + version: 6.0.1 + '@codemirror/lang-javascript': + specifier: ^6.2.2 + version: 6.2.2 + '@codemirror/lang-python': + specifier: ^6.1.6 + version: 6.1.6(@codemirror/view@6.34.1) + '@codemirror/language': + specifier: ^6.10.3 + version: 6.10.3 + '@codemirror/state': + specifier: ^6.4.1 + version: 6.4.1 + antd: + specifier: ^5.20.6 + version: 5.20.6(react-dom@18.2.0)(react@18.2.0) + codemirror: + specifier: ^6.0.1 + version: 6.0.1(@lezer/common@1.2.3) + next: + specifier: 14.2.13 + version: 14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2) + react: + specifier: ^18.2.0 + version: 18.2.0 + react-dom: + specifier: ^18.2.0 + version: 18.2.0(react@18.2.0) + react-timer-hook: + specifier: ^3.0.7 + version: 3.0.7(react@18.2.0) + react-use-websocket: + specifier: ^4.9.0 + version: 4.9.0 + sass: + specifier: ^1.79.2 + version: 1.79.2 + typeface-montserrat: + specifier: ^1.1.13 + version: 1.1.13 + y-codemirror.next: + specifier: ^0.3.5 + version: 0.3.5(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(yjs@13.6.20) + y-webrtc: + specifier: ^10.3.0 + version: 10.3.0(yjs@13.6.20) + yjs: + specifier: ^13.6.20 + version: 13.6.20 + devDependencies: + '@types/node': + specifier: ^20 + version: 20.0.0 + '@types/react': + specifier: ^18.3.8 + version: 18.3.8 + '@types/react-dom': + specifier: ^18.3.0 + version: 18.3.0 + eslint: + specifier: ^8 + version: 8.0.0 + eslint-config-next: + specifier: 14.2.13 + version: 14.2.13(eslint@8.0.0)(typescript@5.0.2) + typescript: + specifier: ^5 + version: 5.0.2 + +packages: + + '@ant-design/colors@7.1.0': + resolution: {integrity: sha512-MMoDGWn1y9LdQJQSHiCC20x3uZ3CwQnv9QMz6pCmJOrqdgM9YxsoVVY0wtrdXbmfSgnV0KNk6zi09NAhMR2jvg==} + + '@ant-design/cssinjs-utils@1.1.0': + resolution: {integrity: sha512-E9nOWObXx7Dy7hdyuYlOFaer/LtPO7oyZVxZphh0CYEslr5EmhJPM3WI0Q2RBHRtYg6dSNqeSK73kvZjPN3IMQ==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@ant-design/cssinjs@1.21.1': + resolution: {integrity: sha512-tyWnlK+XH7Bumd0byfbCiZNK43HEubMoCcu9VxwsAwiHdHTgWa+tMN0/yvxa+e8EzuFP1WdUNNPclRpVtD33lg==} + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' + + '@ant-design/fast-color@2.0.6': + resolution: {integrity: sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==} + engines: {node: '>=8.x'} + + '@ant-design/icons-svg@4.4.2': + resolution: {integrity: sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==} + + '@ant-design/icons@5.5.1': + resolution: {integrity: sha512-0UrM02MA2iDIgvLatWrj6YTCYe0F/cwXvVE0E2SqGrL7PZireQwgEKTKBisWpZyal5eXZLvuM98kju6YtYne8w==} + engines: {node: '>=8'} + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' + + '@ant-design/nextjs-registry@1.0.1': + resolution: {integrity: sha512-DaMJ1nClR1a4UfG7vXkDj89z1eARhSDgqvHoxfM0Yco1MZEbaqRj4o+bQToHb3gMb6gbFlrZ51nOBGh5xSJ7EQ==} + peerDependencies: + '@ant-design/cssinjs': ^1.18.2 + antd: ^5.0.0 + next: ^14.0.0 + react: '>=16.0.0' + react-dom: '>=16.0.0' + + '@ant-design/react-slick@1.1.2': + resolution: {integrity: sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA==} + peerDependencies: + react: '>=16.9.0' + + '@babel/runtime@7.25.7': + resolution: {integrity: sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==} + engines: {node: '>=6.9.0'} + + '@codemirror/autocomplete@6.18.1': + resolution: {integrity: sha512-iWHdj/B1ethnHRTwZj+C1obmmuCzquH29EbcKr0qIjA9NfDeBDJ7vs+WOHsFeLeflE4o+dHfYndJloMKHUkWUA==} + peerDependencies: + '@codemirror/language': ^6.0.0 + '@codemirror/state': ^6.0.0 + '@codemirror/view': ^6.0.0 + '@lezer/common': ^1.0.0 + + '@codemirror/commands@6.7.1': + resolution: {integrity: sha512-llTrboQYw5H4THfhN4U3qCnSZ1SOJ60ohhz+SzU0ADGtwlc533DtklQP0vSFaQuCPDn3BPpOd1GbbnUtwNjsrw==} + + '@codemirror/lang-cpp@6.0.2': + resolution: {integrity: sha512-6oYEYUKHvrnacXxWxYa6t4puTlbN3dgV662BDfSH8+MfjQjVmP697/KYTDOqpxgerkvoNm7q5wlFMBeX8ZMocg==} + + '@codemirror/lang-go@6.0.1': + resolution: {integrity: sha512-7fNvbyNylvqCphW9HD6WFnRpcDjr+KXX/FgqXy5H5ZS0eC5edDljukm/yNgYkwTsgp2busdod50AOTIy6Jikfg==} + + '@codemirror/lang-java@6.0.1': + resolution: {integrity: sha512-OOnmhH67h97jHzCuFaIEspbmsT98fNdhVhmA3zCxW0cn7l8rChDhZtwiwJ/JOKXgfm4J+ELxQihxaI7bj7mJRg==} + + '@codemirror/lang-javascript@6.2.2': + resolution: {integrity: sha512-VGQfY+FCc285AhWuwjYxQyUQcYurWlxdKYT4bqwr3Twnd5wP5WSeu52t4tvvuWmljT4EmgEgZCqSieokhtY8hg==} + + '@codemirror/lang-python@6.1.6': + resolution: {integrity: sha512-ai+01WfZhWqM92UqjnvorkxosZ2aq2u28kHvr+N3gu012XqY2CThD67JPMHnGceRfXPDBmn1HnyqowdpF57bNg==} + + '@codemirror/language@6.10.3': + resolution: {integrity: sha512-kDqEU5sCP55Oabl6E7m5N+vZRoc0iWqgDVhEKifcHzPzjqCegcO4amfrYVL9PmPZpl4G0yjkpTpUO/Ui8CzO8A==} + + '@codemirror/lint@6.8.2': + resolution: {integrity: sha512-PDFG5DjHxSEjOXk9TQYYVjZDqlZTFaDBfhQixHnQOEVDDNHUbEh/hstAjcQJaA6FQdZTD1hquXTK0rVBLADR1g==} + + '@codemirror/search@6.5.6': + resolution: {integrity: sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==} + + '@codemirror/state@6.4.1': + resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==} + + '@codemirror/view@6.34.1': + resolution: {integrity: sha512-t1zK/l9UiRqwUNPm+pdIT0qzJlzuVckbTEMVNFhfWkGiBQClstzg+78vedCvLSX0xJEZ6lwZbPpnljL7L6iwMQ==} + + '@ctrl/tinycolor@3.6.1': + resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} + engines: {node: '>=10'} + + '@emotion/hash@0.8.0': + resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} + + '@emotion/unitless@0.7.5': + resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==} + + '@eslint-community/eslint-utils@4.4.0': + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.11.1': + resolution: {integrity: sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/eslintrc@1.4.1': + resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@humanwhocodes/config-array@0.6.0': + resolution: {integrity: sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + + '@humanwhocodes/object-schema@1.2.1': + resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + deprecated: Use @eslint/object-schema instead + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@lezer/common@1.2.3': + resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==} + + '@lezer/cpp@1.1.2': + resolution: {integrity: sha512-macwKtyeUO0EW86r3xWQCzOV9/CF8imJLpJlPv3sDY57cPGeUZ8gXWOWNlJr52TVByMV3PayFQCA5SHEERDmVQ==} + + '@lezer/go@1.0.0': + resolution: {integrity: sha512-co9JfT3QqX1YkrMmourYw2Z8meGC50Ko4d54QEcQbEYpvdUvN4yb0NBZdn/9ertgvjsySxHsKzH3lbm3vqJ4Jw==} + + '@lezer/highlight@1.2.1': + resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==} + + '@lezer/java@1.1.3': + resolution: {integrity: sha512-yHquUfujwg6Yu4Fd1GNHCvidIvJwi/1Xu2DaKl/pfWIA2c1oXkVvawH3NyXhCaFx4OdlYBVX5wvz2f7Aoa/4Xw==} + + '@lezer/javascript@1.4.19': + resolution: {integrity: sha512-j44kbR1QL26l6dMunZ1uhKBFteVGLVCBGNUD2sUaMnic+rbTviVuoK0CD1l9FTW31EueWvFFswCKMH7Z+M3JRA==} + + '@lezer/lr@1.4.2': + resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==} + + '@lezer/python@1.1.14': + resolution: {integrity: sha512-ykDOb2Ti24n76PJsSa4ZoDF0zH12BSw1LGfQXCYJhJyOGiFTfGaX0Du66Ze72R+u/P35U+O6I9m8TFXov1JzsA==} + + '@next/env@14.2.13': + resolution: {integrity: sha512-s3lh6K8cbW1h5Nga7NNeXrbe0+2jIIYK9YaA9T7IufDWnZpozdFUp6Hf0d5rNWUKu4fEuSX2rCKlGjCrtylfDw==} + + '@next/eslint-plugin-next@14.2.13': + resolution: {integrity: sha512-z8Mk0VljxhIzsSiZUSdt3wp+t2lKd+jk5a9Jsvh3zDGkItgDMfjv/ZbET6HsxEl/fSihVoHGsXV6VLyDH0lfTQ==} + + '@next/swc-darwin-arm64@14.2.13': + resolution: {integrity: sha512-IkAmQEa2Htq+wHACBxOsslt+jMoV3msvxCn0WFSfJSkv/scy+i/EukBKNad36grRxywaXUYJc9mxEGkeIs8Bzg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@14.2.13': + resolution: {integrity: sha512-Dv1RBGs2TTjkwEnFMVL5XIfJEavnLqqwYSD6LXgTPdEy/u6FlSrLBSSfe1pcfqhFEXRAgVL3Wpjibe5wXJzWog==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@14.2.13': + resolution: {integrity: sha512-yB1tYEFFqo4ZNWkwrJultbsw7NPAAxlPXURXioRl9SdW6aIefOLS+0TEsKrWBtbJ9moTDgU3HRILL6QBQnMevg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-arm64-musl@14.2.13': + resolution: {integrity: sha512-v5jZ/FV/eHGoWhMKYrsAweQ7CWb8xsWGM/8m1mwwZQ/sutJjoFaXchwK4pX8NqwImILEvQmZWyb8pPTcP7htWg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-x64-gnu@14.2.13': + resolution: {integrity: sha512-aVc7m4YL7ViiRv7SOXK3RplXzOEe/qQzRA5R2vpXboHABs3w8vtFslGTz+5tKiQzWUmTmBNVW0UQdhkKRORmGA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-linux-x64-musl@14.2.13': + resolution: {integrity: sha512-4wWY7/OsSaJOOKvMsu1Teylku7vKyTuocvDLTZQq0TYv9OjiYYWt63PiE1nTuZnqQ4RPvME7Xai+9enoiN0Wrg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-win32-arm64-msvc@14.2.13': + resolution: {integrity: sha512-uP1XkqCqV2NVH9+g2sC7qIw+w2tRbcMiXFEbMihkQ8B1+V6m28sshBwAB0SDmOe0u44ne1vFU66+gx/28RsBVQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-ia32-msvc@14.2.13': + resolution: {integrity: sha512-V26ezyjPqQpDBV4lcWIh8B/QICQ4v+M5Bo9ykLN+sqeKKBxJVDpEc6biDVyluTXTC40f5IqCU0ttth7Es2ZuMw==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@next/swc-win32-x64-msvc@14.2.13': + resolution: {integrity: sha512-WwzOEAFBGhlDHE5Z73mNU8CO8mqMNLqaG+AO9ETmzdCQlJhVtWZnOl2+rqgVQS+YHunjOWptdFmNfbpwcUuEsw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nolyfill/is-core-module@1.0.39': + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} + engines: {node: '>=12.4.0'} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@rc-component/async-validator@5.0.4': + resolution: {integrity: sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==} + engines: {node: '>=14.x'} + + '@rc-component/color-picker@2.0.1': + resolution: {integrity: sha512-WcZYwAThV/b2GISQ8F+7650r5ZZJ043E57aVBFkQ+kSY4C6wdofXgB0hBx+GPGpIU0Z81eETNoDUJMr7oy/P8Q==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/context@1.4.0': + resolution: {integrity: sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/mini-decimal@1.1.0': + resolution: {integrity: sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==} + engines: {node: '>=8.x'} + + '@rc-component/mutate-observer@1.1.0': + resolution: {integrity: sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/portal@1.1.2': + resolution: {integrity: sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/qrcode@1.0.0': + resolution: {integrity: sha512-L+rZ4HXP2sJ1gHMGHjsg9jlYBX/SLN2D6OxP9Zn3qgtpMWtO2vUfxVFwiogHpAIqs54FnALxraUy/BCO1yRIgg==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/tour@1.15.1': + resolution: {integrity: sha512-Tr2t7J1DKZUpfJuDZWHxyxWpfmj8EZrqSgyMZ+BCdvKZ6r1UDsfU46M/iWAAFBy961Ssfom2kv5f3UcjIL2CmQ==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rc-component/trigger@2.2.3': + resolution: {integrity: sha512-X1oFIpKoXAMXNDYCviOmTfuNuYxE4h5laBsyCqVAVMjNHxoF3/uiyA7XdegK1XbCvBbCZ6P6byWrEoDRpKL8+A==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + + '@rushstack/eslint-patch@1.10.4': + resolution: {integrity: sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==} + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/helpers@0.5.5': + resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/node@20.0.0': + resolution: {integrity: sha512-cD2uPTDnQQCVpmRefonO98/PPijuOnnEy5oytWJFPY1N9aJCz2wJ5kSGWO+zJoed2cY2JxQh6yBuUq4vIn61hw==} + + '@types/prop-types@15.7.13': + resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==} + + '@types/react-dom@18.3.0': + resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} + + '@types/react@18.3.8': + resolution: {integrity: sha512-syBUrW3/XpnW4WJ41Pft+I+aPoDVbrBVQGEnbD7NijDGlVC+8gV/XKRY+7vMDlfPpbwYt0l1vd/Sj8bJGMbs9Q==} + + '@typescript-eslint/eslint-plugin@8.8.0': + resolution: {integrity: sha512-wORFWjU30B2WJ/aXBfOm1LX9v9nyt9D3jsSOxC3cCaTQGCW5k4jNpmjFv3U7p/7s4yvdjHzwtv2Sd2dOyhjS0A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/parser@8.8.0': + resolution: {integrity: sha512-uEFUsgR+tl8GmzmLjRqz+VrDv4eoaMqMXW7ruXfgThaAShO9JTciKpEsB+TvnfFfbg5IpujgMXVV36gOJRLtZg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/scope-manager@8.8.0': + resolution: {integrity: sha512-EL8eaGC6gx3jDd8GwEFEV091210U97J0jeEHrAYvIYosmEGet4wJ+g0SYmLu+oRiAwbSA5AVrt6DxLHfdd+bUg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/type-utils@8.8.0': + resolution: {integrity: sha512-IKwJSS7bCqyCeG4NVGxnOP6lLT9Okc3Zj8hLO96bpMkJab+10HIfJbMouLrlpyOr3yrQ1cA413YPFiGd1mW9/Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/types@8.8.0': + resolution: {integrity: sha512-QJwc50hRCgBd/k12sTykOJbESe1RrzmX6COk8Y525C9l7oweZ+1lw9JiU56im7Amm8swlz00DRIlxMYLizr2Vw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.8.0': + resolution: {integrity: sha512-ZaMJwc/0ckLz5DaAZ+pNLmHv8AMVGtfWxZe/x2JVEkD5LnmhWiQMMcYT7IY7gkdJuzJ9P14fRy28lUrlDSWYdw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/utils@8.8.0': + resolution: {integrity: sha512-QE2MgfOTem00qrlPgyByaCHay9yb1+9BjnMFnSFkUKQfu7adBXDTnCAivURnuPPAG/qiB+kzKkZKmKfaMT0zVg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + + '@typescript-eslint/visitor-keys@8.8.0': + resolution: {integrity: sha512-8mq51Lx6Hpmd7HnA2fcHQo3YgfX1qbccxQOgZcb4tvasu//zXRaA1j5ZRFeCw/VRAdFi4mRM9DnZw0Nu0Q2d1g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.12.1: + resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + antd@5.20.6: + resolution: {integrity: sha512-TZFmNenHlh26DelHCJbkB+x1OVulIKsN1f/CnAd2NxZLysXqRvSuLUeHcgccqAnxTy7B03GZ6i1tocGxPCNjgA==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.1.3: + resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} + + array-buffer-byte-length@1.0.1: + resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + engines: {node: '>= 0.4'} + + array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + engines: {node: '>= 0.4'} + + array-tree-filter@2.1.0: + resolution: {integrity: sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==} + + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.5: + resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.3: + resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + engines: {node: '>= 0.4'} + + ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axe-core@4.10.0: + resolution: {integrity: sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==} + engines: {node: '>=4'} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + + call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001666: + resolution: {integrity: sha512-gD14ICmoV5ZZM1OdzPWmpx+q4GyefaK06zi8hmfHV5xe4/2nOQX3+Dw5o+fSqOws2xVwL9j+anOPFwHzdEdV4g==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chokidar@4.0.1: + resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} + engines: {node: '>= 14.16.0'} + + classnames@2.5.1: + resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + codemirror@6.0.1: + resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + compute-scroll-into-view@3.1.0: + resolution: {integrity: sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + copy-to-clipboard@3.3.3: + resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + + crelt@1.0.6: + resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + + data-view-buffer@1.0.1: + resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.1: + resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.0: + resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + engines: {node: '>= 0.4'} + + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-equal@2.2.3: + resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==} + engines: {node: '>= 0.4'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + enhanced-resolve@5.17.1: + resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} + engines: {node: '>=10.13.0'} + + enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + + err-code@3.0.1: + resolution: {integrity: sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==} + + es-abstract@1.23.3: + resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-get-iterator@1.1.3: + resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} + + es-iterator-helpers@1.0.19: + resolution: {integrity: sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.0.3: + resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + + es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-config-next@14.2.13: + resolution: {integrity: sha512-aro1EKAoyYchnO/3Tlo91hnNBO7QO7qnv/79MAFC+4Jq8TdUVKQlht5d2F+YjrePjdpOvfL+mV9JPfyYNwkk1g==} + peerDependencies: + eslint: ^7.23.0 || ^8.0.0 + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true + + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + + eslint-import-resolver-typescript@3.6.3: + resolution: {integrity: sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + + eslint-module-utils@2.12.0: + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import@2.30.0: + resolution: {integrity: sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-jsx-a11y@6.10.0: + resolution: {integrity: sha512-ySOHvXX8eSN6zz8Bywacm7CvGNhUtdjvqfQDVe6020TUK34Cywkw7m0KsCCk1Qtm9G1FayfTN1/7mMYnYO2Bhg==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + + eslint-plugin-react-hooks@4.6.2: + resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + + eslint-plugin-react@7.37.1: + resolution: {integrity: sha512-xwTnwDqzbDRA8uJ7BMxPs/EXRB3i8ZfnOIp8BsxEQkT0nHPp+WWceqGgo6rKb9ctNi8GJLDT4Go5HAWELa/WMg==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + + eslint-scope@6.0.0: + resolution: {integrity: sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-utils@3.0.0: + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' + + eslint-visitor-keys@2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} + engines: {node: '>=10'} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint@8.0.0: + resolution: {integrity: sha512-03spzPzMAO4pElm44m60Nj08nYonPGQXmw6Ceai/S4QK82IgwWO1EXx1s9namKzVlbVu3Jf81hb+N+8+v21/HQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + + flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + + for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + + foreground-child@3.3.0: + resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} + engines: {node: '>=14'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + + functional-red-black-tree@1.0.1: + resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + get-browser-rtc@1.1.0: + resolution: {integrity: sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ==} + + get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + + get-symbol-description@1.0.2: + resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.8.1: + resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@10.3.10: + resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + + has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@4.0.6: + resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} + engines: {node: '>= 4'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + immutable@4.3.7: + resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + internal-slot@1.0.7: + resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} + engines: {node: '>= 0.4'} + + is-arguments@1.1.1: + resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + engines: {node: '>= 0.4'} + + is-array-buffer@3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + engines: {node: '>= 0.4'} + + is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} + + is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + + is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + + is-bun-module@1.2.1: + resolution: {integrity: sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.1: + resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + engines: {node: '>= 0.4'} + + is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.0.2: + resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.3: + resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + engines: {node: '>= 0.4'} + + is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + + is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + + is-weakset@2.0.3: + resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} + engines: {node: '>= 0.4'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isomorphic.js@0.2.5: + resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} + + iterator.prototype@1.1.2: + resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} + + jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json2mq@0.2.0: + resolution: {integrity: sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + language-subtag-registry@0.3.23: + resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} + + language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lib0@0.2.98: + resolution: {integrity: sha512-XteTiNO0qEXqqweWx+b21p/fBnNHUA1NwAtJNJek1oPrewEZs2uiT4gWivHKr9GqCjDPAhchz0UQO8NwU3bBNA==} + engines: {node: '>=16'} + hasBin: true + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + next@14.2.13: + resolution: {integrity: sha512-BseY9YNw8QJSwLYD7hlZzl6QVDoSFHL/URN5K64kVEVpCsSOWeyjbIGK+dZUaRViHTaMQX8aqmnn0PHBbGZezg==} + engines: {node: '>=18.17.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.41.2 + react: ^18.2.0 + react-dom: ^18.2.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + sass: + optional: true + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.2: + resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} + engines: {node: '>= 0.4'} + + object-is@1.1.6: + resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + engines: {node: '>= 0.4'} + + object.entries@1.1.8: + resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.0: + resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + engines: {node: '>= 0.4'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + picocolors@1.1.0: + resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + rc-cascader@3.28.1: + resolution: {integrity: sha512-9+8oHIMWVLHxuaapDiqFNmD9KSyKN/P4bo9x/MBuDbyTqP8f2/POmmZxdXWBO3yq/uE3pKyQCXYNUxrNfHRv2A==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-checkbox@3.3.0: + resolution: {integrity: sha512-Ih3ZaAcoAiFKJjifzwsGiT/f/quIkxJoklW4yKGho14Olulwn8gN7hOBve0/WGDg5o/l/5mL0w7ff7/YGvefVw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-collapse@3.7.3: + resolution: {integrity: sha512-60FJcdTRn0X5sELF18TANwtVi7FtModq649H11mYF1jh83DniMoM4MqY627sEKRCTm4+WXfGDcB7hY5oW6xhyw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-dialog@9.5.2: + resolution: {integrity: sha512-qVUjc8JukG+j/pNaHVSRa2GO2/KbV2thm7yO4hepQ902eGdYK913sGkwg/fh9yhKYV1ql3BKIN2xnud3rEXAPw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-drawer@7.2.0: + resolution: {integrity: sha512-9lOQ7kBekEJRdEpScHvtmEtXnAsy+NGDXiRWc2ZVC7QXAazNVbeT4EraQKYwCME8BJLa8Bxqxvs5swwyOepRwg==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-dropdown@4.2.0: + resolution: {integrity: sha512-odM8Ove+gSh0zU27DUj5cG1gNKg7mLWBYzB5E4nNLrLwBmYEgYP43vHKDGOVZcJSVElQBI0+jTQgjnq0NfLjng==} + peerDependencies: + react: '>=16.11.0' + react-dom: '>=16.11.0' + + rc-field-form@2.4.0: + resolution: {integrity: sha512-XZ/lF9iqf9HXApIHQHqzJK5v2w4mkUMsVqAzOyWVzoiwwXEavY6Tpuw7HavgzIoD+huVff4JghSGcgEfX6eycg==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-image@7.9.0: + resolution: {integrity: sha512-l4zqO5E0quuLMCtdKfBgj4Suv8tIS011F5k1zBBlK25iMjjiNHxA0VeTzGFtUZERSA45gvpXDg8/P6qNLjR25g==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-input-number@9.2.0: + resolution: {integrity: sha512-5XZFhBCV5f9UQ62AZ2hFbEY8iZT/dm23Q1kAg0H8EvOgD3UDbYYJAayoVIkM3lQaCqYAW5gV0yV3vjw1XtzWHg==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-input@1.6.3: + resolution: {integrity: sha512-wI4NzuqBS8vvKr8cljsvnTUqItMfG1QbJoxovCgL+DX4eVUcHIjVwharwevIxyy7H/jbLryh+K7ysnJr23aWIA==} + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' + + rc-mentions@2.15.0: + resolution: {integrity: sha512-f5v5i7VdqvBDXbphoqcQWmXDif2Msd2arritVoWybrVDuHE6nQ7XCYsybHbV//WylooK52BFDouFvyaRDtXZEw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-menu@9.14.1: + resolution: {integrity: sha512-5wlRb3M8S4yGlWhSoEYJ7ZVRElyScdcpUHxgiLxkeig1tEdyKrnED3B2fhpN0Rrpdp9jyhnmZR/Lwq2fH5VvDQ==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-motion@2.9.3: + resolution: {integrity: sha512-rkW47ABVkic7WEB0EKJqzySpvDqwl60/tdkY7hWP7dYnh5pm0SzJpo54oW3TDUGXV5wfxXFmMkxrzRRbotQ0+w==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-notification@5.6.2: + resolution: {integrity: sha512-Id4IYMoii3zzrG0lB0gD6dPgJx4Iu95Xu0BQrhHIbp7ZnAZbLqdqQ73aIWH0d0UFcElxwaKjnzNovTjo7kXz7g==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-overflow@1.3.2: + resolution: {integrity: sha512-nsUm78jkYAoPygDAcGZeC2VwIg/IBGSodtOY3pMof4W3M9qRJgqaDYm03ZayHlde3I6ipliAxbN0RUcGf5KOzw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-pagination@4.2.0: + resolution: {integrity: sha512-V6qeANJsT6tmOcZ4XiUmj8JXjRLbkusuufpuoBw2GiAn94fIixYjFLmbruD1Sbhn8fPLDnWawPp4CN37zQorvw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-picker@4.6.15: + resolution: {integrity: sha512-OWZ1yrMie+KN2uEUfYCfS4b2Vu6RC1FWwNI0s+qypsc3wRt7g+peuZKVIzXCTaJwyyZruo80+akPg2+GmyiJjw==} + engines: {node: '>=8.x'} + peerDependencies: + date-fns: '>= 2.x' + dayjs: '>= 1.x' + luxon: '>= 3.x' + moment: '>= 2.x' + react: '>=16.9.0' + react-dom: '>=16.9.0' + peerDependenciesMeta: + date-fns: + optional: true + dayjs: + optional: true + luxon: + optional: true + moment: + optional: true + + rc-progress@4.0.0: + resolution: {integrity: sha512-oofVMMafOCokIUIBnZLNcOZFsABaUw8PPrf1/y0ZBvKZNpOiu5h4AO9vv11Sw0p4Hb3D0yGWuEattcQGtNJ/aw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-rate@2.13.0: + resolution: {integrity: sha512-oxvx1Q5k5wD30sjN5tqAyWTvJfLNNJn7Oq3IeS4HxWfAiC4BOXMITNAsw7u/fzdtO4MS8Ki8uRLOzcnEuoQiAw==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-resize-observer@1.4.0: + resolution: {integrity: sha512-PnMVyRid9JLxFavTjeDXEXo65HCRqbmLBw9xX9gfC4BZiSzbLXKzW3jPz+J0P71pLbD5tBMTT+mkstV5gD0c9Q==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-segmented@2.3.0: + resolution: {integrity: sha512-I3FtM5Smua/ESXutFfb8gJ8ZPcvFR+qUgeeGFQHBOvRiRKyAk4aBE5nfqrxXx+h8/vn60DQjOt6i4RNtrbOobg==} + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' + + rc-select@14.15.2: + resolution: {integrity: sha512-oNoXlaFmpqXYcQDzcPVLrEqS2J9c+/+oJuGrlXeVVX/gVgrbHa5YcyiRUXRydFjyuA7GP3elRuLF7Y3Tfwltlw==} + engines: {node: '>=8.x'} + peerDependencies: + react: '*' + react-dom: '*' + + rc-slider@11.1.6: + resolution: {integrity: sha512-LACAaXM0hi+4x4ErDGZLy7weIQwmBIVbIgPE+eDHiHkyzMvKjWHraCG8/B22Y/tCQUPAsP02wBhKhth7mH2PIw==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-steps@6.0.1: + resolution: {integrity: sha512-lKHL+Sny0SeHkQKKDJlAjV5oZ8DwCdS2hFhAkIjuQt1/pB81M0cA0ErVFdHq9+jmPmFw1vJB2F5NBzFXLJxV+g==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-switch@4.1.0: + resolution: {integrity: sha512-TI8ufP2Az9oEbvyCeVE4+90PDSljGyuwix3fV58p7HV2o4wBnVToEyomJRVyTaZeqNPAp+vqeo4Wnj5u0ZZQBg==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-table@7.45.7: + resolution: {integrity: sha512-wi9LetBL1t1csxyGkMB2p3mCiMt+NDexMlPbXHvQFmBBAsMxrgNSAPwUci2zDLUq9m8QdWc1Nh8suvrpy9mXrg==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-tabs@15.1.1: + resolution: {integrity: sha512-Tc7bJvpEdkWIVCUL7yQrMNBJY3j44NcyWS48jF/UKMXuUlzaXK+Z/pEL5LjGcTadtPvVmNqA40yv7hmr+tCOAw==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-textarea@1.8.2: + resolution: {integrity: sha512-UFAezAqltyR00a8Lf0IPAyTd29Jj9ee8wt8DqXyDMal7r/Cg/nDt3e1OOv3Th4W6mKaZijjgwuPXhAfVNTN8sw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-tooltip@6.2.1: + resolution: {integrity: sha512-rws0duD/3sHHsD905Nex7FvoUGy2UBQRhTkKxeEvr2FB+r21HsOxcDJI0TzyO8NHhnAA8ILr8pfbSBg5Jj5KBg==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-tree-select@5.23.0: + resolution: {integrity: sha512-aQGi2tFSRw1WbXv0UVXPzHm09E0cSvUVZMLxQtMv3rnZZpNmdRXWrnd9QkLNlVH31F+X5rgghmdSFF3yZW0N9A==} + peerDependencies: + react: '*' + react-dom: '*' + + rc-tree@5.9.0: + resolution: {integrity: sha512-CPrgOvm9d/9E+izTONKSngNzQdIEjMox2PBufWjS1wf7vxtvmCWzK1SlpHbRY6IaBfJIeZ+88RkcIevf729cRg==} + engines: {node: '>=10.x'} + peerDependencies: + react: '*' + react-dom: '*' + + rc-upload@4.7.0: + resolution: {integrity: sha512-eUwxYNHlsYe5vYhKFAUGrQG95JrnPzY+BmPi1Daq39fWNl/eOc7v4UODuWrVp2LFkQBuV3cMCG/I68iub6oBrg==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-util@5.43.0: + resolution: {integrity: sha512-AzC7KKOXFqAdIBqdGWepL9Xn7cm3vnAmjlHqUnoQaTMZYhM4VlXGLkkHHxj/BZ7Td0+SOPKB4RGPboBVKT9htw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + rc-virtual-list@3.14.8: + resolution: {integrity: sha512-8D0KfzpRYi6YZvlOWIxiOm9BGt4Wf2hQyEaM6RXlDDiY2NhLheuYI+RA+7ZaZj1lq+XQqy3KHlaeeXQfzI5fGg==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + react-dom@18.2.0: + resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} + peerDependencies: + react: ^18.2.0 + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react-timer-hook@3.0.7: + resolution: {integrity: sha512-ATpNcU+PQRxxfNBPVqce2+REtjGAlwmfoNQfcEBMZFxPj0r3GYdKhyPHdStvqrejejEi0QvqaJZjy2lBlFvAsA==} + peerDependencies: + react: '>=16.8.0' + + react-use-websocket@4.9.0: + resolution: {integrity: sha512-/6OaCMggQCTnryCAsw/N+/wfH7bBfIXk5WXTMPdyf0x9HWJXLGUVttAT5hqAimRytD1dkHEJCUrFHAGzOAg1eg==} + + react@18.2.0: + resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} + engines: {node: '>=0.10.0'} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdirp@4.0.1: + resolution: {integrity: sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw==} + engines: {node: '>= 14.16.0'} + + reflect.getprototypeof@1.0.6: + resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} + engines: {node: '>= 0.4'} + + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + + regexp.prototype.flags@1.5.3: + resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} + engines: {node: '>= 0.4'} + + regexpp@3.2.0: + resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} + engines: {node: '>=8'} + + resize-observer-polyfill@1.5.1: + resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + + resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} + engines: {node: '>=0.4'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-regex-test@1.0.3: + resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + engines: {node: '>= 0.4'} + + sass@1.79.2: + resolution: {integrity: sha512-YmT1aoF1MwHsZEu/eXhbAJNsPGAhNP4UixW9ckEwWCvPcVdVF0/C104OGDVEqtoctKq0N+wM20O/rj+sSPsWeg==} + engines: {node: '>=14.0.0'} + hasBin: true + + scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + + scroll-into-view-if-needed@3.1.0: + resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + simple-peer@9.11.1: + resolution: {integrity: sha512-D1SaWpOW8afq1CZGWB8xTfrT3FekjQmPValrqncJMX7QFl8YwhrPTZvMCANLtgBwwdS+7zURyqxDDEmY558tTw==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + stop-iteration-iterator@1.0.0: + resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} + engines: {node: '>= 0.4'} + + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + + string-convert@0.2.1: + resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string.prototype.includes@2.0.0: + resolution: {integrity: sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==} + + string.prototype.matchall@4.0.11: + resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} + engines: {node: '>= 0.4'} + + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + + string.prototype.trim@1.2.9: + resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.8: + resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + style-mod@4.1.2: + resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} + + styled-jsx@5.1.1: + resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + stylis@4.3.4: + resolution: {integrity: sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + throttle-debounce@5.0.2: + resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} + engines: {node: '>=12.22'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toggle-selection@1.0.6: + resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} + + ts-api-utils@1.3.0: + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@2.7.0: + resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.2: + resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.6: + resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} + engines: {node: '>= 0.4'} + + typeface-montserrat@1.1.13: + resolution: {integrity: sha512-Pklkyj0e+K+6I/t0M6JBDBphpfJkF1k+3qd8qDnp9aVtCC7oGBQWTAcL6+5eArfGe7h73uPwyal73hEkf9YCUA==} + + typescript@5.0.2: + resolution: {integrity: sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==} + engines: {node: '>=12.20'} + hasBin: true + + unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + v8-compile-cache@2.4.0: + resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==} + + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + + which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + + which-builtin-type@1.1.4: + resolution: {integrity: sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + y-codemirror.next@0.3.5: + resolution: {integrity: sha512-VluNu3e5HfEXybnypnsGwKAj+fKLd4iAnR7JuX1Sfyydmn1jCBS5wwEL/uS04Ch2ib0DnMAOF6ZRR/8kK3wyGw==} + peerDependencies: + '@codemirror/state': ^6.0.0 + '@codemirror/view': ^6.0.0 + yjs: ^13.5.6 -packages: + y-protocols@1.0.6: + resolution: {integrity: sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + peerDependencies: + yjs: ^13.0.0 - /@ant-design/colors@7.1.0: - resolution: {integrity: sha512-MMoDGWn1y9LdQJQSHiCC20x3uZ3CwQnv9QMz6pCmJOrqdgM9YxsoVVY0wtrdXbmfSgnV0KNk6zi09NAhMR2jvg==} + y-webrtc@10.3.0: + resolution: {integrity: sha512-KalJr7dCgUgyVFxoG3CQYbpS0O2qybegD0vI4bYnYHI0MOwoVbucED3RZ5f2o1a5HZb1qEssUKS0H/Upc6p1lA==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + yjs: ^13.6.8 + + yjs@13.6.20: + resolution: {integrity: sha512-Z2YZI+SYqK7XdWlloI3lhMiKnCdFCVC4PchpdO+mCYwtiTwncjUbnRK9R1JmkNfdmHyDXuWN3ibJAt0wsqTbLQ==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + +snapshots: + + '@ant-design/colors@7.1.0': dependencies: '@ctrl/tinycolor': 3.6.1 - dev: false - /@ant-design/cssinjs-utils@1.1.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-E9nOWObXx7Dy7hdyuYlOFaer/LtPO7oyZVxZphh0CYEslr5EmhJPM3WI0Q2RBHRtYg6dSNqeSK73kvZjPN3IMQ==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + '@ant-design/cssinjs-utils@1.1.0(react-dom@18.2.0)(react@18.2.0)': dependencies: '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0)(react@18.2.0) '@babel/runtime': 7.25.7 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /@ant-design/cssinjs@1.21.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-tyWnlK+XH7Bumd0byfbCiZNK43HEubMoCcu9VxwsAwiHdHTgWa+tMN0/yvxa+e8EzuFP1WdUNNPclRpVtD33lg==} - peerDependencies: - react: '>=16.0.0' - react-dom: '>=16.0.0' + '@ant-design/cssinjs@1.21.1(react-dom@18.2.0)(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 '@emotion/hash': 0.8.0 @@ -125,25 +1981,14 @@ packages: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) stylis: 4.3.4 - dev: false - /@ant-design/fast-color@2.0.6: - resolution: {integrity: sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==} - engines: {node: '>=8.x'} + '@ant-design/fast-color@2.0.6': dependencies: '@babel/runtime': 7.25.7 - dev: false - /@ant-design/icons-svg@4.4.2: - resolution: {integrity: sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==} - dev: false + '@ant-design/icons-svg@4.4.2': {} - /@ant-design/icons@5.5.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-0UrM02MA2iDIgvLatWrj6YTCYe0F/cwXvVE0E2SqGrL7PZireQwgEKTKBisWpZyal5eXZLvuM98kju6YtYne8w==} - engines: {node: '>=8'} - peerDependencies: - react: '>=16.0.0' - react-dom: '>=16.0.0' + '@ant-design/icons@5.5.1(react-dom@18.2.0)(react@18.2.0)': dependencies: '@ant-design/colors': 7.1.0 '@ant-design/icons-svg': 4.4.2 @@ -152,28 +1997,16 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /@ant-design/nextjs-registry@1.0.1(@ant-design/cssinjs@1.21.1)(antd@5.20.6)(next@14.2.13)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-DaMJ1nClR1a4UfG7vXkDj89z1eARhSDgqvHoxfM0Yco1MZEbaqRj4o+bQToHb3gMb6gbFlrZ51nOBGh5xSJ7EQ==} - peerDependencies: - '@ant-design/cssinjs': ^1.18.2 - antd: ^5.0.0 - next: ^14.0.0 - react: '>=16.0.0' - react-dom: '>=16.0.0' + '@ant-design/nextjs-registry@1.0.1(@ant-design/cssinjs@1.21.1)(antd@5.20.6)(next@14.2.13)(react-dom@18.2.0)(react@18.2.0)': dependencies: '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0)(react@18.2.0) antd: 5.20.6(react-dom@18.2.0)(react@18.2.0) next: 14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /@ant-design/react-slick@1.1.2(react@18.2.0): - resolution: {integrity: sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA==} - peerDependencies: - react: '>=16.9.0' + '@ant-design/react-slick@1.1.2(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -181,47 +2014,31 @@ packages: react: 18.2.0 resize-observer-polyfill: 1.5.1 throttle-debounce: 5.0.2 - dev: false - /@babel/runtime@7.25.7: - resolution: {integrity: sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==} - engines: {node: '>=6.9.0'} + '@babel/runtime@7.25.7': dependencies: regenerator-runtime: 0.14.1 - dev: false - /@codemirror/autocomplete@6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3): - resolution: {integrity: sha512-iWHdj/B1ethnHRTwZj+C1obmmuCzquH29EbcKr0qIjA9NfDeBDJ7vs+WOHsFeLeflE4o+dHfYndJloMKHUkWUA==} - peerDependencies: - '@codemirror/language': ^6.0.0 - '@codemirror/state': ^6.0.0 - '@codemirror/view': ^6.0.0 - '@lezer/common': ^1.0.0 + '@codemirror/autocomplete@6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3)': dependencies: '@codemirror/language': 6.10.3 '@codemirror/state': 6.4.1 '@codemirror/view': 6.34.1 '@lezer/common': 1.2.3 - dev: false - /@codemirror/commands@6.7.1: - resolution: {integrity: sha512-llTrboQYw5H4THfhN4U3qCnSZ1SOJ60ohhz+SzU0ADGtwlc533DtklQP0vSFaQuCPDn3BPpOd1GbbnUtwNjsrw==} + '@codemirror/commands@6.7.1': dependencies: '@codemirror/language': 6.10.3 '@codemirror/state': 6.4.1 '@codemirror/view': 6.34.1 '@lezer/common': 1.2.3 - dev: false - /@codemirror/lang-cpp@6.0.2: - resolution: {integrity: sha512-6oYEYUKHvrnacXxWxYa6t4puTlbN3dgV662BDfSH8+MfjQjVmP697/KYTDOqpxgerkvoNm7q5wlFMBeX8ZMocg==} + '@codemirror/lang-cpp@6.0.2': dependencies: '@codemirror/language': 6.10.3 '@lezer/cpp': 1.1.2 - dev: false - /@codemirror/lang-go@6.0.1(@codemirror/view@6.34.1): - resolution: {integrity: sha512-7fNvbyNylvqCphW9HD6WFnRpcDjr+KXX/FgqXy5H5ZS0eC5edDljukm/yNgYkwTsgp2busdod50AOTIy6Jikfg==} + '@codemirror/lang-go@6.0.1(@codemirror/view@6.34.1)': dependencies: '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3) '@codemirror/language': 6.10.3 @@ -230,17 +2047,13 @@ packages: '@lezer/go': 1.0.0 transitivePeerDependencies: - '@codemirror/view' - dev: false - /@codemirror/lang-java@6.0.1: - resolution: {integrity: sha512-OOnmhH67h97jHzCuFaIEspbmsT98fNdhVhmA3zCxW0cn7l8rChDhZtwiwJ/JOKXgfm4J+ELxQihxaI7bj7mJRg==} + '@codemirror/lang-java@6.0.1': dependencies: '@codemirror/language': 6.10.3 '@lezer/java': 1.1.3 - dev: false - /@codemirror/lang-javascript@6.2.2: - resolution: {integrity: sha512-VGQfY+FCc285AhWuwjYxQyUQcYurWlxdKYT4bqwr3Twnd5wP5WSeu52t4tvvuWmljT4EmgEgZCqSieokhtY8hg==} + '@codemirror/lang-javascript@6.2.2': dependencies: '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3) '@codemirror/language': 6.10.3 @@ -249,10 +2062,8 @@ packages: '@codemirror/view': 6.34.1 '@lezer/common': 1.2.3 '@lezer/javascript': 1.4.19 - dev: false - /@codemirror/lang-python@6.1.6(@codemirror/view@6.34.1): - resolution: {integrity: sha512-ai+01WfZhWqM92UqjnvorkxosZ2aq2u28kHvr+N3gu012XqY2CThD67JPMHnGceRfXPDBmn1HnyqowdpF57bNg==} + '@codemirror/lang-python@6.1.6(@codemirror/view@6.34.1)': dependencies: '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3) '@codemirror/language': 6.10.3 @@ -261,10 +2072,8 @@ packages: '@lezer/python': 1.1.14 transitivePeerDependencies: - '@codemirror/view' - dev: false - /@codemirror/language@6.10.3: - resolution: {integrity: sha512-kDqEU5sCP55Oabl6E7m5N+vZRoc0iWqgDVhEKifcHzPzjqCegcO4amfrYVL9PmPZpl4G0yjkpTpUO/Ui8CzO8A==} + '@codemirror/language@6.10.3': dependencies: '@codemirror/state': 6.4.1 '@codemirror/view': 6.34.1 @@ -272,67 +2081,41 @@ packages: '@lezer/highlight': 1.2.1 '@lezer/lr': 1.4.2 style-mod: 4.1.2 - dev: false - /@codemirror/lint@6.8.2: - resolution: {integrity: sha512-PDFG5DjHxSEjOXk9TQYYVjZDqlZTFaDBfhQixHnQOEVDDNHUbEh/hstAjcQJaA6FQdZTD1hquXTK0rVBLADR1g==} + '@codemirror/lint@6.8.2': dependencies: '@codemirror/state': 6.4.1 '@codemirror/view': 6.34.1 crelt: 1.0.6 - dev: false - /@codemirror/search@6.5.6: - resolution: {integrity: sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==} + '@codemirror/search@6.5.6': dependencies: '@codemirror/state': 6.4.1 '@codemirror/view': 6.34.1 crelt: 1.0.6 - dev: false - /@codemirror/state@6.4.1: - resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==} - dev: false + '@codemirror/state@6.4.1': {} - /@codemirror/view@6.34.1: - resolution: {integrity: sha512-t1zK/l9UiRqwUNPm+pdIT0qzJlzuVckbTEMVNFhfWkGiBQClstzg+78vedCvLSX0xJEZ6lwZbPpnljL7L6iwMQ==} + '@codemirror/view@6.34.1': dependencies: '@codemirror/state': 6.4.1 style-mod: 4.1.2 w3c-keyname: 2.2.8 - dev: false - /@ctrl/tinycolor@3.6.1: - resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} - engines: {node: '>=10'} - dev: false + '@ctrl/tinycolor@3.6.1': {} - /@emotion/hash@0.8.0: - resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} - dev: false + '@emotion/hash@0.8.0': {} - /@emotion/unitless@0.7.5: - resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==} - dev: false + '@emotion/unitless@0.7.5': {} - /@eslint-community/eslint-utils@4.4.0(eslint@8.0.0): - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/eslint-utils@4.4.0(eslint@8.0.0)': dependencies: eslint: 8.0.0 eslint-visitor-keys: 3.4.3 - dev: true - /@eslint-community/regexpp@4.11.1: - resolution: {integrity: sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - dev: true + '@eslint-community/regexpp@4.11.1': {} - /@eslint/eslintrc@1.4.1: - resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/eslintrc@1.4.1': dependencies: ajv: 6.12.6 debug: 4.3.7 @@ -345,229 +2128,121 @@ packages: strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - dev: true - /@humanwhocodes/config-array@0.6.0: - resolution: {integrity: sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead + '@humanwhocodes/config-array@0.6.0': dependencies: '@humanwhocodes/object-schema': 1.2.1 debug: 4.3.7 minimatch: 3.1.2 transitivePeerDependencies: - supports-color - dev: true - /@humanwhocodes/object-schema@1.2.1: - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} - deprecated: Use @eslint/object-schema instead - dev: true + '@humanwhocodes/object-schema@1.2.1': {} - /@isaacs/cliui@8.0.2: - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 - string-width-cjs: /string-width@4.2.3 + string-width-cjs: string-width@4.2.3 strip-ansi: 7.1.0 - strip-ansi-cjs: /strip-ansi@6.0.1 + strip-ansi-cjs: strip-ansi@6.0.1 wrap-ansi: 8.1.0 - wrap-ansi-cjs: /wrap-ansi@7.0.0 - dev: true + wrap-ansi-cjs: wrap-ansi@7.0.0 - /@lezer/common@1.2.3: - resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==} - dev: false + '@lezer/common@1.2.3': {} - /@lezer/cpp@1.1.2: - resolution: {integrity: sha512-macwKtyeUO0EW86r3xWQCzOV9/CF8imJLpJlPv3sDY57cPGeUZ8gXWOWNlJr52TVByMV3PayFQCA5SHEERDmVQ==} + '@lezer/cpp@1.1.2': dependencies: '@lezer/common': 1.2.3 '@lezer/highlight': 1.2.1 '@lezer/lr': 1.4.2 - dev: false - /@lezer/go@1.0.0: - resolution: {integrity: sha512-co9JfT3QqX1YkrMmourYw2Z8meGC50Ko4d54QEcQbEYpvdUvN4yb0NBZdn/9ertgvjsySxHsKzH3lbm3vqJ4Jw==} + '@lezer/go@1.0.0': dependencies: '@lezer/common': 1.2.3 '@lezer/highlight': 1.2.1 '@lezer/lr': 1.4.2 - dev: false - /@lezer/highlight@1.2.1: - resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==} + '@lezer/highlight@1.2.1': dependencies: '@lezer/common': 1.2.3 - dev: false - /@lezer/java@1.1.3: - resolution: {integrity: sha512-yHquUfujwg6Yu4Fd1GNHCvidIvJwi/1Xu2DaKl/pfWIA2c1oXkVvawH3NyXhCaFx4OdlYBVX5wvz2f7Aoa/4Xw==} + '@lezer/java@1.1.3': dependencies: '@lezer/common': 1.2.3 '@lezer/highlight': 1.2.1 '@lezer/lr': 1.4.2 - dev: false - /@lezer/javascript@1.4.19: - resolution: {integrity: sha512-j44kbR1QL26l6dMunZ1uhKBFteVGLVCBGNUD2sUaMnic+rbTviVuoK0CD1l9FTW31EueWvFFswCKMH7Z+M3JRA==} + '@lezer/javascript@1.4.19': dependencies: '@lezer/common': 1.2.3 '@lezer/highlight': 1.2.1 '@lezer/lr': 1.4.2 - dev: false - /@lezer/lr@1.4.2: - resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==} + '@lezer/lr@1.4.2': dependencies: '@lezer/common': 1.2.3 - dev: false - /@lezer/python@1.1.14: - resolution: {integrity: sha512-ykDOb2Ti24n76PJsSa4ZoDF0zH12BSw1LGfQXCYJhJyOGiFTfGaX0Du66Ze72R+u/P35U+O6I9m8TFXov1JzsA==} + '@lezer/python@1.1.14': dependencies: '@lezer/common': 1.2.3 '@lezer/highlight': 1.2.1 '@lezer/lr': 1.4.2 - dev: false - /@next/env@14.2.13: - resolution: {integrity: sha512-s3lh6K8cbW1h5Nga7NNeXrbe0+2jIIYK9YaA9T7IufDWnZpozdFUp6Hf0d5rNWUKu4fEuSX2rCKlGjCrtylfDw==} - dev: false + '@next/env@14.2.13': {} - /@next/eslint-plugin-next@14.2.13: - resolution: {integrity: sha512-z8Mk0VljxhIzsSiZUSdt3wp+t2lKd+jk5a9Jsvh3zDGkItgDMfjv/ZbET6HsxEl/fSihVoHGsXV6VLyDH0lfTQ==} + '@next/eslint-plugin-next@14.2.13': dependencies: glob: 10.3.10 - dev: true - /@next/swc-darwin-arm64@14.2.13: - resolution: {integrity: sha512-IkAmQEa2Htq+wHACBxOsslt+jMoV3msvxCn0WFSfJSkv/scy+i/EukBKNad36grRxywaXUYJc9mxEGkeIs8Bzg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: false + '@next/swc-darwin-arm64@14.2.13': optional: true - /@next/swc-darwin-x64@14.2.13: - resolution: {integrity: sha512-Dv1RBGs2TTjkwEnFMVL5XIfJEavnLqqwYSD6LXgTPdEy/u6FlSrLBSSfe1pcfqhFEXRAgVL3Wpjibe5wXJzWog==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: false + '@next/swc-darwin-x64@14.2.13': optional: true - /@next/swc-linux-arm64-gnu@14.2.13: - resolution: {integrity: sha512-yB1tYEFFqo4ZNWkwrJultbsw7NPAAxlPXURXioRl9SdW6aIefOLS+0TEsKrWBtbJ9moTDgU3HRILL6QBQnMevg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: false + '@next/swc-linux-arm64-gnu@14.2.13': optional: true - /@next/swc-linux-arm64-musl@14.2.13: - resolution: {integrity: sha512-v5jZ/FV/eHGoWhMKYrsAweQ7CWb8xsWGM/8m1mwwZQ/sutJjoFaXchwK4pX8NqwImILEvQmZWyb8pPTcP7htWg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: false + '@next/swc-linux-arm64-musl@14.2.13': optional: true - /@next/swc-linux-x64-gnu@14.2.13: - resolution: {integrity: sha512-aVc7m4YL7ViiRv7SOXK3RplXzOEe/qQzRA5R2vpXboHABs3w8vtFslGTz+5tKiQzWUmTmBNVW0UQdhkKRORmGA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: false + '@next/swc-linux-x64-gnu@14.2.13': optional: true - /@next/swc-linux-x64-musl@14.2.13: - resolution: {integrity: sha512-4wWY7/OsSaJOOKvMsu1Teylku7vKyTuocvDLTZQq0TYv9OjiYYWt63PiE1nTuZnqQ4RPvME7Xai+9enoiN0Wrg==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: false + '@next/swc-linux-x64-musl@14.2.13': optional: true - /@next/swc-win32-arm64-msvc@14.2.13: - resolution: {integrity: sha512-uP1XkqCqV2NVH9+g2sC7qIw+w2tRbcMiXFEbMihkQ8B1+V6m28sshBwAB0SDmOe0u44ne1vFU66+gx/28RsBVQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: false + '@next/swc-win32-arm64-msvc@14.2.13': optional: true - /@next/swc-win32-ia32-msvc@14.2.13: - resolution: {integrity: sha512-V26ezyjPqQpDBV4lcWIh8B/QICQ4v+M5Bo9ykLN+sqeKKBxJVDpEc6biDVyluTXTC40f5IqCU0ttth7Es2ZuMw==} - engines: {node: '>= 10'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: false + '@next/swc-win32-ia32-msvc@14.2.13': optional: true - /@next/swc-win32-x64-msvc@14.2.13: - resolution: {integrity: sha512-WwzOEAFBGhlDHE5Z73mNU8CO8mqMNLqaG+AO9ETmzdCQlJhVtWZnOl2+rqgVQS+YHunjOWptdFmNfbpwcUuEsw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: false + '@next/swc-win32-x64-msvc@14.2.13': optional: true - /@nodelib/fs.scandir@2.1.5: - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 run-parallel: 1.2.0 - dev: true - /@nodelib/fs.stat@2.0.5: - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - dev: true + '@nodelib/fs.stat@2.0.5': {} - /@nodelib/fs.walk@1.2.8: - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} + '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 - dev: true - /@nolyfill/is-core-module@1.0.39: - resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} - engines: {node: '>=12.4.0'} - dev: true + '@nolyfill/is-core-module@1.0.39': {} - /@pkgjs/parseargs@0.11.0: - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - requiresBuild: true - dev: true + '@pkgjs/parseargs@0.11.0': optional: true - /@rc-component/async-validator@5.0.4: - resolution: {integrity: sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==} - engines: {node: '>=14.x'} + '@rc-component/async-validator@5.0.4': dependencies: '@babel/runtime': 7.25.7 - dev: false - /@rc-component/color-picker@2.0.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-WcZYwAThV/b2GISQ8F+7650r5ZZJ043E57aVBFkQ+kSY4C6wdofXgB0hBx+GPGpIU0Z81eETNoDUJMr7oy/P8Q==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + '@rc-component/color-picker@2.0.1(react-dom@18.2.0)(react@18.2.0)': dependencies: '@ant-design/fast-color': 2.0.6 '@babel/runtime': 7.25.7 @@ -575,75 +2250,43 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /@rc-component/context@1.4.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + '@rc-component/context@1.4.0(react-dom@18.2.0)(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /@rc-component/mini-decimal@1.1.0: - resolution: {integrity: sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==} - engines: {node: '>=8.x'} + '@rc-component/mini-decimal@1.1.0': dependencies: '@babel/runtime': 7.25.7 - dev: false - /@rc-component/mutate-observer@1.1.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + '@rc-component/mutate-observer@1.1.0(react-dom@18.2.0)(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /@rc-component/portal@1.1.2(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + '@rc-component/portal@1.1.2(react-dom@18.2.0)(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /@rc-component/qrcode@1.0.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-L+rZ4HXP2sJ1gHMGHjsg9jlYBX/SLN2D6OxP9Zn3qgtpMWtO2vUfxVFwiogHpAIqs54FnALxraUy/BCO1yRIgg==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + '@rc-component/qrcode@1.0.0(react-dom@18.2.0)(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /@rc-component/tour@1.15.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Tr2t7J1DKZUpfJuDZWHxyxWpfmj8EZrqSgyMZ+BCdvKZ6r1UDsfU46M/iWAAFBy961Ssfom2kv5f3UcjIL2CmQ==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + '@rc-component/tour@1.15.1(react-dom@18.2.0)(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) @@ -652,14 +2295,8 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /@rc-component/trigger@2.2.3(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-X1oFIpKoXAMXNDYCviOmTfuNuYxE4h5laBsyCqVAVMjNHxoF3/uiyA7XdegK1XbCvBbCZ6P6byWrEoDRpKL8+A==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + '@rc-component/trigger@2.2.3(react-dom@18.2.0)(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) @@ -669,62 +2306,34 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /@rtsao/scc@1.1.0: - resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - dev: true + '@rtsao/scc@1.1.0': {} - /@rushstack/eslint-patch@1.10.4: - resolution: {integrity: sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==} - dev: true + '@rushstack/eslint-patch@1.10.4': {} - /@swc/counter@0.1.3: - resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - dev: false + '@swc/counter@0.1.3': {} - /@swc/helpers@0.5.5: - resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} + '@swc/helpers@0.5.5': dependencies: '@swc/counter': 0.1.3 tslib: 2.7.0 - dev: false - /@types/json5@0.0.29: - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - dev: true + '@types/json5@0.0.29': {} - /@types/node@20.0.0: - resolution: {integrity: sha512-cD2uPTDnQQCVpmRefonO98/PPijuOnnEy5oytWJFPY1N9aJCz2wJ5kSGWO+zJoed2cY2JxQh6yBuUq4vIn61hw==} - dev: true + '@types/node@20.0.0': {} - /@types/prop-types@15.7.13: - resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==} - dev: true + '@types/prop-types@15.7.13': {} - /@types/react-dom@18.3.0: - resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} + '@types/react-dom@18.3.0': dependencies: '@types/react': 18.3.8 - dev: true - /@types/react@18.3.8: - resolution: {integrity: sha512-syBUrW3/XpnW4WJ41Pft+I+aPoDVbrBVQGEnbD7NijDGlVC+8gV/XKRY+7vMDlfPpbwYt0l1vd/Sj8bJGMbs9Q==} + '@types/react@18.3.8': dependencies: '@types/prop-types': 15.7.13 csstype: 3.1.3 - dev: true - /@typescript-eslint/eslint-plugin@8.8.0(@typescript-eslint/parser@8.8.0)(eslint@8.0.0)(typescript@5.0.2): - resolution: {integrity: sha512-wORFWjU30B2WJ/aXBfOm1LX9v9nyt9D3jsSOxC3cCaTQGCW5k4jNpmjFv3U7p/7s4yvdjHzwtv2Sd2dOyhjS0A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/eslint-plugin@8.8.0(@typescript-eslint/parser@8.8.0)(eslint@8.0.0)(typescript@5.0.2)': dependencies: '@eslint-community/regexpp': 4.11.1 '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) @@ -740,17 +2349,8 @@ packages: typescript: 5.0.2 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2): - resolution: {integrity: sha512-uEFUsgR+tl8GmzmLjRqz+VrDv4eoaMqMXW7ruXfgThaAShO9JTciKpEsB+TvnfFfbg5IpujgMXVV36gOJRLtZg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2)': dependencies: '@typescript-eslint/scope-manager': 8.8.0 '@typescript-eslint/types': 8.8.0 @@ -761,24 +2361,13 @@ packages: typescript: 5.0.2 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/scope-manager@8.8.0: - resolution: {integrity: sha512-EL8eaGC6gx3jDd8GwEFEV091210U97J0jeEHrAYvIYosmEGet4wJ+g0SYmLu+oRiAwbSA5AVrt6DxLHfdd+bUg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.8.0': dependencies: '@typescript-eslint/types': 8.8.0 '@typescript-eslint/visitor-keys': 8.8.0 - dev: true - /@typescript-eslint/type-utils@8.8.0(eslint@8.0.0)(typescript@5.0.2): - resolution: {integrity: sha512-IKwJSS7bCqyCeG4NVGxnOP6lLT9Okc3Zj8hLO96bpMkJab+10HIfJbMouLrlpyOr3yrQ1cA413YPFiGd1mW9/Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/type-utils@8.8.0(eslint@8.0.0)(typescript@5.0.2)': dependencies: '@typescript-eslint/typescript-estree': 8.8.0(typescript@5.0.2) '@typescript-eslint/utils': 8.8.0(eslint@8.0.0)(typescript@5.0.2) @@ -788,21 +2377,10 @@ packages: transitivePeerDependencies: - eslint - supports-color - dev: true - /@typescript-eslint/types@8.8.0: - resolution: {integrity: sha512-QJwc50hRCgBd/k12sTykOJbESe1RrzmX6COk8Y525C9l7oweZ+1lw9JiU56im7Amm8swlz00DRIlxMYLizr2Vw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dev: true + '@typescript-eslint/types@8.8.0': {} - /@typescript-eslint/typescript-estree@8.8.0(typescript@5.0.2): - resolution: {integrity: sha512-ZaMJwc/0ckLz5DaAZ+pNLmHv8AMVGtfWxZe/x2JVEkD5LnmhWiQMMcYT7IY7gkdJuzJ9P14fRy28lUrlDSWYdw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/typescript-estree@8.8.0(typescript@5.0.2)': dependencies: '@typescript-eslint/types': 8.8.0 '@typescript-eslint/visitor-keys': 8.8.0 @@ -815,13 +2393,8 @@ packages: typescript: 5.0.2 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/utils@8.8.0(eslint@8.0.0)(typescript@5.0.2): - resolution: {integrity: sha512-QE2MgfOTem00qrlPgyByaCHay9yb1+9BjnMFnSFkUKQfu7adBXDTnCAivURnuPPAG/qiB+kzKkZKmKfaMT0zVg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + '@typescript-eslint/utils@8.8.0(eslint@8.0.0)(typescript@5.0.2)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.0.0) '@typescript-eslint/scope-manager': 8.8.0 @@ -831,71 +2404,38 @@ packages: transitivePeerDependencies: - supports-color - typescript - dev: true - /@typescript-eslint/visitor-keys@8.8.0: - resolution: {integrity: sha512-8mq51Lx6Hpmd7HnA2fcHQo3YgfX1qbccxQOgZcb4tvasu//zXRaA1j5ZRFeCw/VRAdFi4mRM9DnZw0Nu0Q2d1g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.8.0': dependencies: '@typescript-eslint/types': 8.8.0 eslint-visitor-keys: 3.4.3 - dev: true - /acorn-jsx@5.3.2(acorn@8.12.1): - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn-jsx@5.3.2(acorn@8.12.1): dependencies: acorn: 8.12.1 - dev: true - /acorn@8.12.1: - resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true + acorn@8.12.1: {} - /ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 - dev: true - /ansi-colors@4.1.3: - resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} - engines: {node: '>=6'} - dev: true + ansi-colors@4.1.3: {} - /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - dev: true + ansi-regex@5.0.1: {} - /ansi-regex@6.1.0: - resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} - engines: {node: '>=12'} - dev: true + ansi-regex@6.1.0: {} - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 - dev: true - /ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} - dev: true + ansi-styles@6.2.1: {} - /antd@5.20.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-TZFmNenHlh26DelHCJbkB+x1OVulIKsN1f/CnAd2NxZLysXqRvSuLUeHcgccqAnxTy7B03GZ6i1tocGxPCNjgA==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + antd@5.20.6(react-dom@18.2.0)(react@18.2.0): dependencies: '@ant-design/colors': 7.1.0 '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0)(react@18.2.0) @@ -952,29 +2492,19 @@ packages: - date-fns - luxon - moment - dev: false - /argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true + argparse@2.0.1: {} - /aria-query@5.1.3: - resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} + aria-query@5.1.3: dependencies: deep-equal: 2.2.3 - dev: true - /array-buffer-byte-length@1.0.1: - resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} - engines: {node: '>= 0.4'} + array-buffer-byte-length@1.0.1: dependencies: call-bind: 1.0.7 is-array-buffer: 3.0.4 - dev: true - /array-includes@3.1.8: - resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} - engines: {node: '>= 0.4'} + array-includes@3.1.8: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 @@ -982,15 +2512,10 @@ packages: es-object-atoms: 1.0.0 get-intrinsic: 1.2.4 is-string: 1.0.7 - dev: true - /array-tree-filter@2.1.0: - resolution: {integrity: sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==} - dev: false - - /array.prototype.findlast@1.2.5: - resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} - engines: {node: '>= 0.4'} + array-tree-filter@2.1.0: {} + + array.prototype.findlast@1.2.5: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 @@ -998,11 +2523,8 @@ packages: es-errors: 1.3.0 es-object-atoms: 1.0.0 es-shim-unscopables: 1.0.2 - dev: true - /array.prototype.findlastindex@1.2.5: - resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} - engines: {node: '>= 0.4'} + array.prototype.findlastindex@1.2.5: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 @@ -1010,42 +2532,30 @@ packages: es-errors: 1.3.0 es-object-atoms: 1.0.0 es-shim-unscopables: 1.0.2 - dev: true - /array.prototype.flat@1.3.2: - resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} - engines: {node: '>= 0.4'} + array.prototype.flat@1.3.2: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-shim-unscopables: 1.0.2 - dev: true - /array.prototype.flatmap@1.3.2: - resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} - engines: {node: '>= 0.4'} + array.prototype.flatmap@1.3.2: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-shim-unscopables: 1.0.2 - dev: true - /array.prototype.tosorted@1.1.4: - resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} - engines: {node: '>= 0.4'} + array.prototype.tosorted@1.1.4: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-errors: 1.3.0 es-shim-unscopables: 1.0.2 - dev: true - /arraybuffer.prototype.slice@1.0.3: - resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} - engines: {node: '>= 0.4'} + arraybuffer.prototype.slice@1.0.3: dependencies: array-buffer-byte-length: 1.0.1 call-bind: 1.0.7 @@ -1055,116 +2565,69 @@ packages: get-intrinsic: 1.2.4 is-array-buffer: 3.0.4 is-shared-array-buffer: 1.0.3 - dev: true - /ast-types-flow@0.0.8: - resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} - dev: true + ast-types-flow@0.0.8: {} - /available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.0.0 - dev: true - /axe-core@4.10.0: - resolution: {integrity: sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==} - engines: {node: '>=4'} - dev: true + axe-core@4.10.0: {} - /axobject-query@4.1.0: - resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} - engines: {node: '>= 0.4'} - dev: true + axobject-query@4.1.0: {} - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true + balanced-match@1.0.2: {} - /base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - dev: false + base64-js@1.5.1: {} - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - dev: true - /brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + brace-expansion@2.0.1: dependencies: balanced-match: 1.0.2 - dev: true - /braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} + braces@3.0.3: dependencies: fill-range: 7.1.1 - dev: true - /buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + buffer@6.0.3: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 - dev: false - /busboy@1.6.0: - resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} - engines: {node: '>=10.16.0'} + busboy@1.6.0: dependencies: streamsearch: 1.1.0 - dev: false - /call-bind@1.0.7: - resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} - engines: {node: '>= 0.4'} + call-bind@1.0.7: dependencies: es-define-property: 1.0.0 es-errors: 1.3.0 function-bind: 1.1.2 get-intrinsic: 1.2.4 set-function-length: 1.2.2 - dev: true - /callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - dev: true + callsites@3.1.0: {} - /caniuse-lite@1.0.30001666: - resolution: {integrity: sha512-gD14ICmoV5ZZM1OdzPWmpx+q4GyefaK06zi8hmfHV5xe4/2nOQX3+Dw5o+fSqOws2xVwL9j+anOPFwHzdEdV4g==} - dev: false + caniuse-lite@1.0.30001666: {} - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - dev: true - /chokidar@4.0.1: - resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} - engines: {node: '>= 14.16.0'} + chokidar@4.0.1: dependencies: readdirp: 4.0.1 - dev: false - /classnames@2.5.1: - resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} - dev: false + classnames@2.5.1: {} - /client-only@0.0.1: - resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - dev: false + client-only@0.0.1: {} - /codemirror@6.0.1(@lezer/common@1.2.3): - resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==} + codemirror@6.0.1(@lezer/common@1.2.3): dependencies: '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3) '@codemirror/commands': 6.7.1 @@ -1175,109 +2638,62 @@ packages: '@codemirror/view': 6.34.1 transitivePeerDependencies: - '@lezer/common' - dev: false - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} + color-convert@2.0.1: dependencies: color-name: 1.1.4 - dev: true - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true + color-name@1.1.4: {} - /compute-scroll-into-view@3.1.0: - resolution: {integrity: sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==} - dev: false + compute-scroll-into-view@3.1.0: {} - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true + concat-map@0.0.1: {} - /copy-to-clipboard@3.3.3: - resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + copy-to-clipboard@3.3.3: dependencies: toggle-selection: 1.0.6 - dev: false - /crelt@1.0.6: - resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} - dev: false + crelt@1.0.6: {} - /cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} + cross-spawn@7.0.3: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - dev: true - /csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + csstype@3.1.3: {} - /damerau-levenshtein@1.0.8: - resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} - dev: true + damerau-levenshtein@1.0.8: {} - /data-view-buffer@1.0.1: - resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} - engines: {node: '>= 0.4'} + data-view-buffer@1.0.1: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-data-view: 1.0.1 - dev: true - /data-view-byte-length@1.0.1: - resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} - engines: {node: '>= 0.4'} + data-view-byte-length@1.0.1: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-data-view: 1.0.1 - dev: true - /data-view-byte-offset@1.0.0: - resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} - engines: {node: '>= 0.4'} + data-view-byte-offset@1.0.0: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-data-view: 1.0.1 - dev: true - /dayjs@1.11.13: - resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} - dev: false + dayjs@1.11.13: {} - /debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true + debug@3.2.7: dependencies: ms: 2.1.3 - dev: true - /debug@4.3.7: - resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true + debug@4.3.7: dependencies: ms: 2.1.3 - /deep-equal@2.2.3: - resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==} - engines: {node: '>= 0.4'} + deep-equal@2.2.3: dependencies: array-buffer-byte-length: 1.0.1 call-bind: 1.0.7 @@ -1297,79 +2713,48 @@ packages: which-boxed-primitive: 1.0.2 which-collection: 1.0.2 which-typed-array: 1.1.15 - dev: true - /deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dev: true + deep-is@0.1.4: {} - /define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} + define-data-property@1.1.4: dependencies: es-define-property: 1.0.0 es-errors: 1.3.0 gopd: 1.0.1 - dev: true - /define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} + define-properties@1.2.1: dependencies: define-data-property: 1.1.4 has-property-descriptors: 1.0.2 object-keys: 1.1.1 - dev: true - /doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} + doctrine@2.1.0: dependencies: esutils: 2.0.3 - dev: true - /doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} + doctrine@3.0.0: dependencies: esutils: 2.0.3 - dev: true - /eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - dev: true + eastasianwidth@0.2.0: {} - /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true + emoji-regex@8.0.0: {} - /emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - dev: true + emoji-regex@9.2.2: {} - /enhanced-resolve@5.17.1: - resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} - engines: {node: '>=10.13.0'} + enhanced-resolve@5.17.1: dependencies: graceful-fs: 4.2.11 tapable: 2.2.1 - dev: true - /enquirer@2.4.1: - resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} - engines: {node: '>=8.6'} + enquirer@2.4.1: dependencies: ansi-colors: 4.1.3 strip-ansi: 6.0.1 - dev: true - /err-code@3.0.1: - resolution: {integrity: sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==} - dev: false + err-code@3.0.1: {} - /es-abstract@1.23.3: - resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} - engines: {node: '>= 0.4'} + es-abstract@1.23.3: dependencies: array-buffer-byte-length: 1.0.1 arraybuffer.prototype.slice: 1.0.3 @@ -1417,22 +2802,14 @@ packages: typed-array-length: 1.0.6 unbox-primitive: 1.0.2 which-typed-array: 1.1.15 - dev: true - /es-define-property@1.0.0: - resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} - engines: {node: '>= 0.4'} + es-define-property@1.0.0: dependencies: get-intrinsic: 1.2.4 - dev: true - /es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - dev: true + es-errors@1.3.0: {} - /es-get-iterator@1.1.3: - resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} + es-get-iterator@1.1.3: dependencies: call-bind: 1.0.7 get-intrinsic: 1.2.4 @@ -1443,11 +2820,8 @@ packages: is-string: 1.0.7 isarray: 2.0.5 stop-iteration-iterator: 1.0.0 - dev: true - /es-iterator-helpers@1.0.19: - resolution: {integrity: sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==} - engines: {node: '>= 0.4'} + es-iterator-helpers@1.0.19: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 @@ -1463,52 +2837,30 @@ packages: internal-slot: 1.0.7 iterator.prototype: 1.1.2 safe-array-concat: 1.1.2 - dev: true - /es-object-atoms@1.0.0: - resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} - engines: {node: '>= 0.4'} + es-object-atoms@1.0.0: dependencies: es-errors: 1.3.0 - dev: true - /es-set-tostringtag@2.0.3: - resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} - engines: {node: '>= 0.4'} + es-set-tostringtag@2.0.3: dependencies: get-intrinsic: 1.2.4 has-tostringtag: 1.0.2 hasown: 2.0.2 - dev: true - /es-shim-unscopables@1.0.2: - resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + es-shim-unscopables@1.0.2: dependencies: hasown: 2.0.2 - dev: true - /es-to-primitive@1.2.1: - resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} - engines: {node: '>= 0.4'} + es-to-primitive@1.2.1: dependencies: is-callable: 1.2.7 is-date-object: 1.0.5 is-symbol: 1.0.4 - dev: true - /escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - dev: true + escape-string-regexp@4.0.0: {} - /eslint-config-next@14.2.13(eslint@8.0.0)(typescript@5.0.2): - resolution: {integrity: sha512-aro1EKAoyYchnO/3Tlo91hnNBO7QO7qnv/79MAFC+4Jq8TdUVKQlht5d2F+YjrePjdpOvfL+mV9JPfyYNwkk1g==} - peerDependencies: - eslint: ^7.23.0 || ^8.0.0 - typescript: '>=3.3.1' - peerDependenciesMeta: - typescript: - optional: true + eslint-config-next@14.2.13(eslint@8.0.0)(typescript@5.0.2): dependencies: '@next/eslint-plugin-next': 14.2.13 '@rushstack/eslint-patch': 1.10.4 @@ -1526,30 +2878,16 @@ packages: - eslint-import-resolver-webpack - eslint-plugin-import-x - supports-color - dev: true - /eslint-import-resolver-node@0.3.9: - resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + eslint-import-resolver-node@0.3.9: dependencies: debug: 3.2.7 is-core-module: 2.15.1 resolve: 1.22.8 transitivePeerDependencies: - supports-color - dev: true - /eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0): - resolution: {integrity: sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - eslint: '*' - eslint-plugin-import: '*' - eslint-plugin-import-x: '*' - peerDependenciesMeta: - eslint-plugin-import: - optional: true - eslint-plugin-import-x: - optional: true + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.3.7 @@ -1566,28 +2904,8 @@ packages: - eslint-import-resolver-node - eslint-import-resolver-webpack - supports-color - dev: true - /eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): - resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): dependencies: '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) debug: 3.2.7 @@ -1596,17 +2914,8 @@ packages: eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0) transitivePeerDependencies: - supports-color - dev: true - /eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): - resolution: {integrity: sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true + eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): dependencies: '@rtsao/scc': 1.1.0 '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) @@ -1632,13 +2941,8 @@ packages: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - dev: true - /eslint-plugin-jsx-a11y@6.10.0(eslint@8.0.0): - resolution: {integrity: sha512-ySOHvXX8eSN6zz8Bywacm7CvGNhUtdjvqfQDVe6020TUK34Cywkw7m0KsCCk1Qtm9G1FayfTN1/7mMYnYO2Bhg==} - engines: {node: '>=4.0'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + eslint-plugin-jsx-a11y@6.10.0(eslint@8.0.0): dependencies: aria-query: 5.1.3 array-includes: 3.1.8 @@ -1657,22 +2961,12 @@ packages: object.fromentries: 2.0.8 safe-regex-test: 1.0.3 string.prototype.includes: 2.0.0 - dev: true - /eslint-plugin-react-hooks@4.6.2(eslint@8.0.0): - resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==} - engines: {node: '>=10'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + eslint-plugin-react-hooks@4.6.2(eslint@8.0.0): dependencies: eslint: 8.0.0 - dev: true - /eslint-plugin-react@7.37.1(eslint@8.0.0): - resolution: {integrity: sha512-xwTnwDqzbDRA8uJ7BMxPs/EXRB3i8ZfnOIp8BsxEQkT0nHPp+WWceqGgo6rKb9ctNi8GJLDT4Go5HAWELa/WMg==} - engines: {node: '>=4'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + eslint-plugin-react@7.37.1(eslint@8.0.0): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 @@ -1693,40 +2987,22 @@ packages: semver: 6.3.1 string.prototype.matchall: 4.0.11 string.prototype.repeat: 1.0.0 - dev: true - /eslint-scope@6.0.0: - resolution: {integrity: sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-scope@6.0.0: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 - dev: true - /eslint-utils@3.0.0(eslint@8.0.0): - resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} - engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} - peerDependencies: - eslint: '>=5' + eslint-utils@3.0.0(eslint@8.0.0): dependencies: eslint: 8.0.0 eslint-visitor-keys: 2.1.0 - dev: true - /eslint-visitor-keys@2.1.0: - resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} - engines: {node: '>=10'} - dev: true + eslint-visitor-keys@2.1.0: {} - /eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true + eslint-visitor-keys@3.4.3: {} - /eslint@8.0.0: - resolution: {integrity: sha512-03spzPzMAO4pElm44m60Nj08nYonPGQXmw6Ceai/S4QK82IgwWO1EXx1s9namKzVlbVu3Jf81hb+N+8+v21/HQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true + eslint@8.0.0: dependencies: '@eslint/eslintrc': 1.4.1 '@humanwhocodes/config-array': 0.6.0 @@ -1768,196 +3044,120 @@ packages: v8-compile-cache: 2.4.0 transitivePeerDependencies: - supports-color - dev: true - /espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + espree@9.6.1: dependencies: acorn: 8.12.1 acorn-jsx: 5.3.2(acorn@8.12.1) eslint-visitor-keys: 3.4.3 - dev: true - /esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} - engines: {node: '>=0.10'} + esquery@1.6.0: dependencies: estraverse: 5.3.0 - dev: true - /esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} + esrecurse@4.3.0: dependencies: estraverse: 5.3.0 - dev: true - /estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - dev: true + estraverse@5.3.0: {} - /esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - dev: true + esutils@2.0.3: {} - /fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true + fast-deep-equal@3.1.3: {} - /fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} - engines: {node: '>=8.6.0'} + fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.8 - dev: true - /fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true + fast-json-stable-stringify@2.1.0: {} - /fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - dev: true + fast-levenshtein@2.0.6: {} - /fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + fastq@1.17.1: dependencies: reusify: 1.0.4 - dev: true - /file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} + file-entry-cache@6.0.1: dependencies: flat-cache: 3.2.0 - dev: true - /fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 - dev: true - /flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} + flat-cache@3.2.0: dependencies: flatted: 3.3.1 keyv: 4.5.4 rimraf: 3.0.2 - dev: true - /flatted@3.3.1: - resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} - dev: true + flatted@3.3.1: {} - /for-each@0.3.3: - resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + for-each@0.3.3: dependencies: is-callable: 1.2.7 - dev: true - /foreground-child@3.3.0: - resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} - engines: {node: '>=14'} + foreground-child@3.3.0: dependencies: cross-spawn: 7.0.3 signal-exit: 4.1.0 - dev: true - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true + fs.realpath@1.0.0: {} - /function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - dev: true + function-bind@1.1.2: {} - /function.prototype.name@1.1.6: - resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} - engines: {node: '>= 0.4'} + function.prototype.name@1.1.6: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 functions-have-names: 1.2.3 - dev: true - /functional-red-black-tree@1.0.1: - resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} - dev: true + functional-red-black-tree@1.0.1: {} - /functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - dev: true + functions-have-names@1.2.3: {} - /get-browser-rtc@1.1.0: - resolution: {integrity: sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ==} - dev: false + get-browser-rtc@1.1.0: {} - /get-intrinsic@1.2.4: - resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} - engines: {node: '>= 0.4'} + get-intrinsic@1.2.4: dependencies: es-errors: 1.3.0 function-bind: 1.1.2 has-proto: 1.0.3 has-symbols: 1.0.3 hasown: 2.0.2 - dev: true - /get-symbol-description@1.0.2: - resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} - engines: {node: '>= 0.4'} + get-symbol-description@1.0.2: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 get-intrinsic: 1.2.4 - dev: true - /get-tsconfig@4.8.1: - resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + get-tsconfig@4.8.1: dependencies: resolve-pkg-maps: 1.0.0 - dev: true - /glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 - dev: true - /glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} + glob-parent@6.0.2: dependencies: is-glob: 4.0.3 - dev: true - /glob@10.3.10: - resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} - engines: {node: '>=16 || 14 >=14.17'} - hasBin: true + glob@10.3.10: dependencies: foreground-child: 3.3.0 jackspeak: 2.3.6 minimatch: 9.0.5 minipass: 7.1.2 path-scurry: 1.11.1 - dev: true - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + glob@7.2.3: dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -1965,495 +3165,273 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true - /globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} + globals@13.24.0: dependencies: type-fest: 0.20.2 - dev: true - /globalthis@1.0.4: - resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} - engines: {node: '>= 0.4'} + globalthis@1.0.4: dependencies: define-properties: 1.2.1 gopd: 1.0.1 - dev: true - /gopd@1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + gopd@1.0.1: dependencies: get-intrinsic: 1.2.4 - dev: true - /graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + graceful-fs@4.2.11: {} - /graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - dev: true + graphemer@1.4.0: {} - /has-bigints@1.0.2: - resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} - dev: true + has-bigints@1.0.2: {} - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true + has-flag@4.0.0: {} - /has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.0 - dev: true - /has-proto@1.0.3: - resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} - engines: {node: '>= 0.4'} - dev: true + has-proto@1.0.3: {} - /has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} - engines: {node: '>= 0.4'} - dev: true + has-symbols@1.0.3: {} - /has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} + has-tostringtag@1.0.2: dependencies: has-symbols: 1.0.3 - dev: true - /hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} + hasown@2.0.2: dependencies: function-bind: 1.1.2 - dev: true - /ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - dev: false + ieee754@1.2.1: {} - /ignore@4.0.6: - resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} - engines: {node: '>= 4'} - dev: true + ignore@4.0.6: {} - /ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - dev: true + ignore@5.3.2: {} - /immutable@4.3.7: - resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} - dev: false + immutable@4.3.7: {} - /import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} + import-fresh@3.3.0: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - dev: true - /imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - dev: true + imurmurhash@0.1.4: {} - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + inflight@1.0.6: dependencies: once: 1.4.0 wrappy: 1.0.2 - dev: true - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + inherits@2.0.4: {} - /internal-slot@1.0.7: - resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} - engines: {node: '>= 0.4'} + internal-slot@1.0.7: dependencies: es-errors: 1.3.0 hasown: 2.0.2 side-channel: 1.0.6 - dev: true - /is-arguments@1.1.1: - resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} - engines: {node: '>= 0.4'} + is-arguments@1.1.1: dependencies: call-bind: 1.0.7 has-tostringtag: 1.0.2 - dev: true - /is-array-buffer@3.0.4: - resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} - engines: {node: '>= 0.4'} + is-array-buffer@3.0.4: dependencies: call-bind: 1.0.7 get-intrinsic: 1.2.4 - dev: true - /is-async-function@2.0.0: - resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} - engines: {node: '>= 0.4'} + is-async-function@2.0.0: dependencies: has-tostringtag: 1.0.2 - dev: true - /is-bigint@1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + is-bigint@1.0.4: dependencies: has-bigints: 1.0.2 - dev: true - /is-boolean-object@1.1.2: - resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} - engines: {node: '>= 0.4'} + is-boolean-object@1.1.2: dependencies: call-bind: 1.0.7 has-tostringtag: 1.0.2 - dev: true - /is-bun-module@1.2.1: - resolution: {integrity: sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==} + is-bun-module@1.2.1: dependencies: semver: 7.6.3 - dev: true - /is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - dev: true + is-callable@1.2.7: {} - /is-core-module@2.15.1: - resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} - engines: {node: '>= 0.4'} + is-core-module@2.15.1: dependencies: hasown: 2.0.2 - dev: true - /is-data-view@1.0.1: - resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} - engines: {node: '>= 0.4'} + is-data-view@1.0.1: dependencies: is-typed-array: 1.1.13 - dev: true - /is-date-object@1.0.5: - resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} - engines: {node: '>= 0.4'} + is-date-object@1.0.5: dependencies: has-tostringtag: 1.0.2 - dev: true - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - dev: true + is-extglob@2.1.1: {} - /is-finalizationregistry@1.0.2: - resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + is-finalizationregistry@1.0.2: dependencies: call-bind: 1.0.7 - dev: true - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - dev: true + is-fullwidth-code-point@3.0.0: {} - /is-generator-function@1.0.10: - resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} - engines: {node: '>= 0.4'} + is-generator-function@1.0.10: dependencies: has-tostringtag: 1.0.2 - dev: true - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 - dev: true - /is-map@2.0.3: - resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} - engines: {node: '>= 0.4'} - dev: true + is-map@2.0.3: {} - /is-negative-zero@2.0.3: - resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} - engines: {node: '>= 0.4'} - dev: true + is-negative-zero@2.0.3: {} - /is-number-object@1.0.7: - resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} - engines: {node: '>= 0.4'} + is-number-object@1.0.7: dependencies: has-tostringtag: 1.0.2 - dev: true - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - dev: true + is-number@7.0.0: {} - /is-regex@1.1.4: - resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} - engines: {node: '>= 0.4'} + is-regex@1.1.4: dependencies: call-bind: 1.0.7 has-tostringtag: 1.0.2 - dev: true - /is-set@2.0.3: - resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} - engines: {node: '>= 0.4'} - dev: true + is-set@2.0.3: {} - /is-shared-array-buffer@1.0.3: - resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} - engines: {node: '>= 0.4'} + is-shared-array-buffer@1.0.3: dependencies: call-bind: 1.0.7 - dev: true - /is-string@1.0.7: - resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} - engines: {node: '>= 0.4'} + is-string@1.0.7: dependencies: has-tostringtag: 1.0.2 - dev: true - /is-symbol@1.0.4: - resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} - engines: {node: '>= 0.4'} + is-symbol@1.0.4: dependencies: has-symbols: 1.0.3 - dev: true - /is-typed-array@1.1.13: - resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} - engines: {node: '>= 0.4'} + is-typed-array@1.1.13: dependencies: which-typed-array: 1.1.15 - dev: true - /is-weakmap@2.0.2: - resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} - engines: {node: '>= 0.4'} - dev: true + is-weakmap@2.0.2: {} - /is-weakref@1.0.2: - resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + is-weakref@1.0.2: dependencies: call-bind: 1.0.7 - dev: true - /is-weakset@2.0.3: - resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} - engines: {node: '>= 0.4'} + is-weakset@2.0.3: dependencies: call-bind: 1.0.7 get-intrinsic: 1.2.4 - dev: true - /isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - dev: true + isarray@2.0.5: {} - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true + isexe@2.0.0: {} - /isomorphic.js@0.2.5: - resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} - dev: false + isomorphic.js@0.2.5: {} - /iterator.prototype@1.1.2: - resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} + iterator.prototype@1.1.2: dependencies: define-properties: 1.2.1 get-intrinsic: 1.2.4 has-symbols: 1.0.3 reflect.getprototypeof: 1.0.6 set-function-name: 2.0.2 - dev: true - /jackspeak@2.3.6: - resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} - engines: {node: '>=14'} + jackspeak@2.3.6: dependencies: '@isaacs/cliui': 8.0.2 optionalDependencies: '@pkgjs/parseargs': 0.11.0 - dev: true - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-tokens@4.0.0: {} - /js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true + js-yaml@4.1.0: dependencies: argparse: 2.0.1 - dev: true - /json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - dev: true + json-buffer@3.0.1: {} - /json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true + json-schema-traverse@0.4.1: {} - /json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - dev: true + json-stable-stringify-without-jsonify@1.0.1: {} - /json2mq@0.2.0: - resolution: {integrity: sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==} + json2mq@0.2.0: dependencies: string-convert: 0.2.1 - dev: false - /json5@1.0.2: - resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} - hasBin: true + json5@1.0.2: dependencies: minimist: 1.2.8 - dev: true - /jsx-ast-utils@3.3.5: - resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} - engines: {node: '>=4.0'} + jsx-ast-utils@3.3.5: dependencies: array-includes: 3.1.8 array.prototype.flat: 1.3.2 object.assign: 4.1.5 object.values: 1.2.0 - dev: true - /keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + keyv@4.5.4: dependencies: json-buffer: 3.0.1 - dev: true - /language-subtag-registry@0.3.23: - resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} - dev: true + language-subtag-registry@0.3.23: {} - /language-tags@1.0.9: - resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} - engines: {node: '>=0.10'} + language-tags@1.0.9: dependencies: language-subtag-registry: 0.3.23 - dev: true - /levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 - dev: true - /lib0@0.2.98: - resolution: {integrity: sha512-XteTiNO0qEXqqweWx+b21p/fBnNHUA1NwAtJNJek1oPrewEZs2uiT4gWivHKr9GqCjDPAhchz0UQO8NwU3bBNA==} - engines: {node: '>=16'} - hasBin: true + lib0@0.2.98: dependencies: isomorphic.js: 0.2.5 - dev: false - /lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: true + lodash.merge@4.6.2: {} - /loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 - /lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - dev: true + lru-cache@10.4.3: {} - /merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - dev: true + merge2@1.4.1: {} - /micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} + micromatch@4.0.8: dependencies: braces: 3.0.3 picomatch: 2.3.1 - dev: true - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 - dev: true - /minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} + minimatch@9.0.5: dependencies: brace-expansion: 2.0.1 - dev: true - /minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true + minimist@1.2.8: {} - /minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} - engines: {node: '>=16 || 14 >=14.17'} - dev: true + minipass@7.1.2: {} - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + ms@2.1.3: {} - /nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - dev: false + nanoid@3.3.7: {} - /natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true + natural-compare@1.4.0: {} - /next@14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2): - resolution: {integrity: sha512-BseY9YNw8QJSwLYD7hlZzl6QVDoSFHL/URN5K64kVEVpCsSOWeyjbIGK+dZUaRViHTaMQX8aqmnn0PHBbGZezg==} - engines: {node: '>=18.17.0'} - hasBin: true - peerDependencies: - '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.41.2 - react: ^18.2.0 - react-dom: ^18.2.0 - sass: ^1.3.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@playwright/test': - optional: true - sass: - optional: true + next@14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2): dependencies: '@next/env': 14.2.13 '@swc/helpers': 0.5.5 @@ -2478,87 +3456,55 @@ packages: transitivePeerDependencies: - '@babel/core' - babel-plugin-macros - dev: false - /object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - dev: true + object-assign@4.1.1: {} - /object-inspect@1.13.2: - resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} - engines: {node: '>= 0.4'} - dev: true + object-inspect@1.13.2: {} - /object-is@1.1.6: - resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} - engines: {node: '>= 0.4'} + object-is@1.1.6: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - dev: true - /object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - dev: true + object-keys@1.1.1: {} - /object.assign@4.1.5: - resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} - engines: {node: '>= 0.4'} + object.assign@4.1.5: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 has-symbols: 1.0.3 object-keys: 1.1.1 - dev: true - /object.entries@1.1.8: - resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} - engines: {node: '>= 0.4'} + object.entries@1.1.8: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-object-atoms: 1.0.0 - dev: true - /object.fromentries@2.0.8: - resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} - engines: {node: '>= 0.4'} + object.fromentries@2.0.8: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-object-atoms: 1.0.0 - dev: true - /object.groupby@1.0.3: - resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} - engines: {node: '>= 0.4'} + object.groupby@1.0.3: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 - dev: true - /object.values@1.2.0: - resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} - engines: {node: '>= 0.4'} + object.values@1.2.0: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-object-atoms: 1.0.0 - dev: true - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + once@1.4.0: dependencies: wrappy: 1.0.2 - dev: true - /optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} + optionator@0.9.4: dependencies: deep-is: 0.1.4 fast-levenshtein: 2.0.6 @@ -2566,97 +3512,53 @@ packages: prelude-ls: 1.2.1 type-check: 0.4.0 word-wrap: 1.2.5 - dev: true - /parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} + parent-module@1.0.1: dependencies: callsites: 3.1.0 - dev: true - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: true + path-is-absolute@1.0.1: {} - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: true + path-key@3.1.1: {} - /path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - dev: true + path-parse@1.0.7: {} - /path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} + path-scurry@1.11.1: dependencies: lru-cache: 10.4.3 minipass: 7.1.2 - dev: true - /picocolors@1.1.0: - resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} - dev: false + picocolors@1.1.0: {} - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - dev: true + picomatch@2.3.1: {} - /possible-typed-array-names@1.0.0: - resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} - engines: {node: '>= 0.4'} - dev: true + possible-typed-array-names@1.0.0: {} - /postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} - engines: {node: ^10 || ^12 || >=14} + postcss@8.4.31: dependencies: nanoid: 3.3.7 picocolors: 1.1.0 source-map-js: 1.2.1 - dev: false - /prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - dev: true + prelude-ls@1.2.1: {} - /progress@2.0.3: - resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} - engines: {node: '>=0.4.0'} - dev: true + progress@2.0.3: {} - /prop-types@15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 - dev: true - /punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - dev: true + punycode@2.3.1: {} - /queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + queue-microtask@1.2.3: {} - /randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 - dev: false - /rc-cascader@3.28.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-9+8oHIMWVLHxuaapDiqFNmD9KSyKN/P4bo9x/MBuDbyTqP8f2/POmmZxdXWBO3yq/uE3pKyQCXYNUxrNfHRv2A==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-cascader@3.28.1(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 array-tree-filter: 2.1.0 @@ -2666,26 +3568,16 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-checkbox@3.3.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Ih3ZaAcoAiFKJjifzwsGiT/f/quIkxJoklW4yKGho14Olulwn8gN7hOBve0/WGDg5o/l/5mL0w7ff7/YGvefVw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-checkbox@3.3.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-collapse@3.7.3(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-60FJcdTRn0X5sELF18TANwtVi7FtModq649H11mYF1jh83DniMoM4MqY627sEKRCTm4+WXfGDcB7hY5oW6xhyw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-collapse@3.7.3(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -2693,13 +3585,8 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-dialog@9.5.2(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-qVUjc8JukG+j/pNaHVSRa2GO2/KbV2thm7yO4hepQ902eGdYK913sGkwg/fh9yhKYV1ql3BKIN2xnud3rEXAPw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-dialog@9.5.2(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) @@ -2708,13 +3595,8 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-drawer@7.2.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-9lOQ7kBekEJRdEpScHvtmEtXnAsy+NGDXiRWc2ZVC7QXAazNVbeT4EraQKYwCME8BJLa8Bxqxvs5swwyOepRwg==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-drawer@7.2.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) @@ -2723,13 +3605,8 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-dropdown@4.2.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-odM8Ove+gSh0zU27DUj5cG1gNKg7mLWBYzB5E4nNLrLwBmYEgYP43vHKDGOVZcJSVElQBI0+jTQgjnq0NfLjng==} - peerDependencies: - react: '>=16.11.0' - react-dom: '>=16.11.0' + rc-dropdown@4.2.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) @@ -2737,27 +3614,16 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-field-form@2.4.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-XZ/lF9iqf9HXApIHQHqzJK5v2w4mkUMsVqAzOyWVzoiwwXEavY6Tpuw7HavgzIoD+huVff4JghSGcgEfX6eycg==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-field-form@2.4.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/async-validator': 5.0.4 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-image@7.9.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-l4zqO5E0quuLMCtdKfBgj4Suv8tIS011F5k1zBBlK25iMjjiNHxA0VeTzGFtUZERSA45gvpXDg8/P6qNLjR25g==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-image@7.9.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) @@ -2767,13 +3633,8 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-input-number@9.2.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-5XZFhBCV5f9UQ62AZ2hFbEY8iZT/dm23Q1kAg0H8EvOgD3UDbYYJAayoVIkM3lQaCqYAW5gV0yV3vjw1XtzWHg==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-input-number@9.2.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/mini-decimal': 1.1.0 @@ -2782,26 +3643,16 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-input@1.6.3(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-wI4NzuqBS8vvKr8cljsvnTUqItMfG1QbJoxovCgL+DX4eVUcHIjVwharwevIxyy7H/jbLryh+K7ysnJr23aWIA==} - peerDependencies: - react: '>=16.0.0' - react-dom: '>=16.0.0' + rc-input@1.6.3(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-mentions@2.15.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-f5v5i7VdqvBDXbphoqcQWmXDif2Msd2arritVoWybrVDuHE6nQ7XCYsybHbV//WylooK52BFDouFvyaRDtXZEw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-mentions@2.15.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) @@ -2812,13 +3663,8 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-menu@9.14.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-5wlRb3M8S4yGlWhSoEYJ7ZVRElyScdcpUHxgiLxkeig1tEdyKrnED3B2fhpN0Rrpdp9jyhnmZR/Lwq2fH5VvDQ==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-menu@9.14.1(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) @@ -2828,27 +3674,16 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-motion@2.9.3(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-rkW47ABVkic7WEB0EKJqzySpvDqwl60/tdkY7hWP7dYnh5pm0SzJpo54oW3TDUGXV5wfxXFmMkxrzRRbotQ0+w==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-motion@2.9.3(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-notification@5.6.2(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Id4IYMoii3zzrG0lB0gD6dPgJx4Iu95Xu0BQrhHIbp7ZnAZbLqdqQ73aIWH0d0UFcElxwaKjnzNovTjo7kXz7g==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-notification@5.6.2(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -2856,13 +3691,8 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-overflow@1.3.2(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-nsUm78jkYAoPygDAcGZeC2VwIg/IBGSodtOY3pMof4W3M9qRJgqaDYm03ZayHlde3I6ipliAxbN0RUcGf5KOzw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-overflow@1.3.2(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -2870,40 +3700,16 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-pagination@4.2.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-V6qeANJsT6tmOcZ4XiUmj8JXjRLbkusuufpuoBw2GiAn94fIixYjFLmbruD1Sbhn8fPLDnWawPp4CN37zQorvw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-pagination@4.2.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-picker@4.6.15(dayjs@1.11.13)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-OWZ1yrMie+KN2uEUfYCfS4b2Vu6RC1FWwNI0s+qypsc3wRt7g+peuZKVIzXCTaJwyyZruo80+akPg2+GmyiJjw==} - engines: {node: '>=8.x'} - peerDependencies: - date-fns: '>= 2.x' - dayjs: '>= 1.x' - luxon: '>= 3.x' - moment: '>= 2.x' - react: '>=16.9.0' - react-dom: '>=16.9.0' - peerDependenciesMeta: - date-fns: - optional: true - dayjs: - optional: true - luxon: - optional: true - moment: - optional: true + rc-picker@4.6.15(dayjs@1.11.13)(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) @@ -2914,40 +3720,24 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-progress@4.0.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-oofVMMafOCokIUIBnZLNcOZFsABaUw8PPrf1/y0ZBvKZNpOiu5h4AO9vv11Sw0p4Hb3D0yGWuEattcQGtNJ/aw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-progress@4.0.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - - /rc-rate@2.13.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-oxvx1Q5k5wD30sjN5tqAyWTvJfLNNJn7Oq3IeS4HxWfAiC4BOXMITNAsw7u/fzdtO4MS8Ki8uRLOzcnEuoQiAw==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + + rc-rate@2.13.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-resize-observer@1.4.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-PnMVyRid9JLxFavTjeDXEXo65HCRqbmLBw9xX9gfC4BZiSzbLXKzW3jPz+J0P71pLbD5tBMTT+mkstV5gD0c9Q==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-resize-observer@1.4.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -2955,13 +3745,8 @@ packages: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) resize-observer-polyfill: 1.5.1 - dev: false - /rc-segmented@2.3.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-I3FtM5Smua/ESXutFfb8gJ8ZPcvFR+qUgeeGFQHBOvRiRKyAk4aBE5nfqrxXx+h8/vn60DQjOt6i4RNtrbOobg==} - peerDependencies: - react: '>=16.0.0' - react-dom: '>=16.0.0' + rc-segmented@2.3.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -2969,14 +3754,8 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-select@14.15.2(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-oNoXlaFmpqXYcQDzcPVLrEqS2J9c+/+oJuGrlXeVVX/gVgrbHa5YcyiRUXRydFjyuA7GP3elRuLF7Y3Tfwltlw==} - engines: {node: '>=8.x'} - peerDependencies: - react: '*' - react-dom: '*' + rc-select@14.15.2(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) @@ -2987,55 +3766,32 @@ packages: rc-virtual-list: 3.14.8(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-slider@11.1.6(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-LACAaXM0hi+4x4ErDGZLy7weIQwmBIVbIgPE+eDHiHkyzMvKjWHraCG8/B22Y/tCQUPAsP02wBhKhth7mH2PIw==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-slider@11.1.6(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-steps@6.0.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-lKHL+Sny0SeHkQKKDJlAjV5oZ8DwCdS2hFhAkIjuQt1/pB81M0cA0ErVFdHq9+jmPmFw1vJB2F5NBzFXLJxV+g==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-steps@6.0.1(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-switch@4.1.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-TI8ufP2Az9oEbvyCeVE4+90PDSljGyuwix3fV58p7HV2o4wBnVToEyomJRVyTaZeqNPAp+vqeo4Wnj5u0ZZQBg==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-switch@4.1.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-table@7.45.7(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-wi9LetBL1t1csxyGkMB2p3mCiMt+NDexMlPbXHvQFmBBAsMxrgNSAPwUci2zDLUq9m8QdWc1Nh8suvrpy9mXrg==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-table@7.45.7(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/context': 1.4.0(react-dom@18.2.0)(react@18.2.0) @@ -3045,14 +3801,8 @@ packages: rc-virtual-list: 3.14.8(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-tabs@15.1.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-Tc7bJvpEdkWIVCUL7yQrMNBJY3j44NcyWS48jF/UKMXuUlzaXK+Z/pEL5LjGcTadtPvVmNqA40yv7hmr+tCOAw==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-tabs@15.1.1(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -3063,13 +3813,8 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-textarea@1.8.2(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-UFAezAqltyR00a8Lf0IPAyTd29Jj9ee8wt8DqXyDMal7r/Cg/nDt3e1OOv3Th4W6mKaZijjgwuPXhAfVNTN8sw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-textarea@1.8.2(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -3078,26 +3823,16 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-tooltip@6.2.1(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-rws0duD/3sHHsD905Nex7FvoUGy2UBQRhTkKxeEvr2FB+r21HsOxcDJI0TzyO8NHhnAA8ILr8pfbSBg5Jj5KBg==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-tooltip@6.2.1(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-tree-select@5.23.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-aQGi2tFSRw1WbXv0UVXPzHm09E0cSvUVZMLxQtMv3rnZZpNmdRXWrnd9QkLNlVH31F+X5rgghmdSFF3yZW0N9A==} - peerDependencies: - react: '*' - react-dom: '*' + rc-tree-select@5.23.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -3106,14 +3841,8 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-tree@5.9.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-CPrgOvm9d/9E+izTONKSngNzQdIEjMox2PBufWjS1wf7vxtvmCWzK1SlpHbRY6IaBfJIeZ+88RkcIevf729cRg==} - engines: {node: '>=10.x'} - peerDependencies: - react: '*' - react-dom: '*' + rc-tree@5.9.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -3122,39 +3851,23 @@ packages: rc-virtual-list: 3.14.8(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-upload@4.7.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-eUwxYNHlsYe5vYhKFAUGrQG95JrnPzY+BmPi1Daq39fWNl/eOc7v4UODuWrVp2LFkQBuV3cMCG/I68iub6oBrg==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-upload@4.7.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /rc-util@5.43.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-AzC7KKOXFqAdIBqdGWepL9Xn7cm3vnAmjlHqUnoQaTMZYhM4VlXGLkkHHxj/BZ7Td0+SOPKB4RGPboBVKT9htw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-util@5.43.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-is: 18.3.1 - dev: false - /rc-virtual-list@3.14.8(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-8D0KfzpRYi6YZvlOWIxiOm9BGt4Wf2hQyEaM6RXlDDiY2NhLheuYI+RA+7ZaZj1lq+XQqy3KHlaeeXQfzI5fGg==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + rc-virtual-list@3.14.8(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -3162,62 +3875,36 @@ packages: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - dev: false - /react-dom@18.2.0(react@18.2.0): - resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} - peerDependencies: - react: ^18.2.0 + react-dom@18.2.0(react@18.2.0): dependencies: loose-envify: 1.4.0 react: 18.2.0 scheduler: 0.23.2 - dev: false - /react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - dev: true + react-is@16.13.1: {} - /react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - dev: false + react-is@18.3.1: {} - /react-timer-hook@3.0.7(react@18.2.0): - resolution: {integrity: sha512-ATpNcU+PQRxxfNBPVqce2+REtjGAlwmfoNQfcEBMZFxPj0r3GYdKhyPHdStvqrejejEi0QvqaJZjy2lBlFvAsA==} - peerDependencies: - react: '>=16.8.0' + react-timer-hook@3.0.7(react@18.2.0): dependencies: react: 18.2.0 - dev: false - /react-use-websocket@4.9.0: - resolution: {integrity: sha512-/6OaCMggQCTnryCAsw/N+/wfH7bBfIXk5WXTMPdyf0x9HWJXLGUVttAT5hqAimRytD1dkHEJCUrFHAGzOAg1eg==} - dev: false + react-use-websocket@4.9.0: {} - /react@18.2.0: - resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} - engines: {node: '>=0.10.0'} + react@18.2.0: dependencies: loose-envify: 1.4.0 - dev: false - /readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} + readable-stream@3.6.2: dependencies: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 - dev: false - /readdirp@4.0.1: - resolution: {integrity: sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw==} - engines: {node: '>= 14.16.0'} - dev: false + readdirp@4.0.1: {} - /reflect.getprototypeof@1.0.6: - resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} - engines: {node: '>= 0.4'} + reflect.getprototypeof@1.0.6: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 @@ -3226,136 +3913,80 @@ packages: get-intrinsic: 1.2.4 globalthis: 1.0.4 which-builtin-type: 1.1.4 - dev: true - /regenerator-runtime@0.14.1: - resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - dev: false + regenerator-runtime@0.14.1: {} - /regexp.prototype.flags@1.5.3: - resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} - engines: {node: '>= 0.4'} + regexp.prototype.flags@1.5.3: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-errors: 1.3.0 set-function-name: 2.0.2 - dev: true - /regexpp@3.2.0: - resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} - engines: {node: '>=8'} - dev: true + regexpp@3.2.0: {} - /resize-observer-polyfill@1.5.1: - resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} - dev: false + resize-observer-polyfill@1.5.1: {} - /resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - dev: true + resolve-from@4.0.0: {} - /resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - dev: true + resolve-pkg-maps@1.0.0: {} - /resolve@1.22.8: - resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} - hasBin: true + resolve@1.22.8: dependencies: is-core-module: 2.15.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - dev: true - /resolve@2.0.0-next.5: - resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} - hasBin: true + resolve@2.0.0-next.5: dependencies: is-core-module: 2.15.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - dev: true - /reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: true + reusify@1.0.4: {} - /rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true + rimraf@3.0.2: dependencies: glob: 7.2.3 - dev: true - /run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 - dev: true - /safe-array-concat@1.1.2: - resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} - engines: {node: '>=0.4'} + safe-array-concat@1.1.2: dependencies: call-bind: 1.0.7 get-intrinsic: 1.2.4 has-symbols: 1.0.3 isarray: 2.0.5 - dev: true - /safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: false + safe-buffer@5.2.1: {} - /safe-regex-test@1.0.3: - resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} - engines: {node: '>= 0.4'} + safe-regex-test@1.0.3: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-regex: 1.1.4 - dev: true - /sass@1.79.2: - resolution: {integrity: sha512-YmT1aoF1MwHsZEu/eXhbAJNsPGAhNP4UixW9ckEwWCvPcVdVF0/C104OGDVEqtoctKq0N+wM20O/rj+sSPsWeg==} - engines: {node: '>=14.0.0'} - hasBin: true + sass@1.79.2: dependencies: chokidar: 4.0.1 immutable: 4.3.7 source-map-js: 1.2.1 - dev: false - /scheduler@0.23.2: - resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + scheduler@0.23.2: dependencies: loose-envify: 1.4.0 - dev: false - /scroll-into-view-if-needed@3.1.0: - resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==} + scroll-into-view-if-needed@3.1.0: dependencies: compute-scroll-into-view: 3.1.0 - dev: false - /semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - dev: true + semver@6.3.1: {} - /semver@7.6.3: - resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} - engines: {node: '>=10'} - hasBin: true - dev: true + semver@7.6.3: {} - /set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 es-errors: 1.3.0 @@ -3363,47 +3994,30 @@ packages: get-intrinsic: 1.2.4 gopd: 1.0.1 has-property-descriptors: 1.0.2 - dev: true - /set-function-name@2.0.2: - resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} - engines: {node: '>= 0.4'} + set-function-name@2.0.2: dependencies: define-data-property: 1.1.4 es-errors: 1.3.0 functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 - dev: true - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 - dev: true - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: true + shebang-regex@3.0.0: {} - /side-channel@1.0.6: - resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} - engines: {node: '>= 0.4'} + side-channel@1.0.6: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 get-intrinsic: 1.2.4 object-inspect: 1.13.2 - dev: true - /signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - dev: true + signal-exit@4.1.0: {} - /simple-peer@9.11.1: - resolution: {integrity: sha512-D1SaWpOW8afq1CZGWB8xTfrT3FekjQmPValrqncJMX7QFl8YwhrPTZvMCANLtgBwwdS+7zURyqxDDEmY558tTw==} + simple-peer@9.11.1: dependencies: buffer: 6.0.3 debug: 4.3.7 @@ -3414,57 +4028,35 @@ packages: readable-stream: 3.6.2 transitivePeerDependencies: - supports-color - dev: false - /source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - dev: false + source-map-js@1.2.1: {} - /stop-iteration-iterator@1.0.0: - resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} - engines: {node: '>= 0.4'} + stop-iteration-iterator@1.0.0: dependencies: internal-slot: 1.0.7 - dev: true - /streamsearch@1.1.0: - resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} - engines: {node: '>=10.0.0'} - dev: false + streamsearch@1.1.0: {} - /string-convert@0.2.1: - resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==} - dev: false + string-convert@0.2.1: {} - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: true - /string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} + string-width@5.1.2: dependencies: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 strip-ansi: 7.1.0 - dev: true - /string.prototype.includes@2.0.0: - resolution: {integrity: sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==} + string.prototype.includes@2.0.0: dependencies: define-properties: 1.2.1 es-abstract: 1.23.3 - dev: true - /string.prototype.matchall@4.0.11: - resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} - engines: {node: '>= 0.4'} + string.prototype.matchall@4.0.11: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 @@ -3478,191 +4070,108 @@ packages: regexp.prototype.flags: 1.5.3 set-function-name: 2.0.2 side-channel: 1.0.6 - dev: true - /string.prototype.repeat@1.0.0: - resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + string.prototype.repeat@1.0.0: dependencies: define-properties: 1.2.1 es-abstract: 1.23.3 - dev: true - /string.prototype.trim@1.2.9: - resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} - engines: {node: '>= 0.4'} + string.prototype.trim@1.2.9: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-object-atoms: 1.0.0 - dev: true - /string.prototype.trimend@1.0.8: - resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + string.prototype.trimend@1.0.8: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-object-atoms: 1.0.0 - dev: true - /string.prototype.trimstart@1.0.8: - resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} - engines: {node: '>= 0.4'} + string.prototype.trimstart@1.0.8: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-object-atoms: 1.0.0 - dev: true - /string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 - dev: false - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 - dev: true - /strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: '>=12'} + strip-ansi@7.1.0: dependencies: ansi-regex: 6.1.0 - dev: true - /strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - dev: true + strip-bom@3.0.0: {} - /strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - dev: true + strip-json-comments@3.1.1: {} - /style-mod@4.1.2: - resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} - dev: false + style-mod@4.1.2: {} - /styled-jsx@5.1.1(react@18.2.0): - resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} - engines: {node: '>= 12.0.0'} - peerDependencies: - '@babel/core': '*' - babel-plugin-macros: '*' - react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' - peerDependenciesMeta: - '@babel/core': - optional: true - babel-plugin-macros: - optional: true + styled-jsx@5.1.1(react@18.2.0): dependencies: client-only: 0.0.1 react: 18.2.0 - dev: false - /stylis@4.3.4: - resolution: {integrity: sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==} - dev: false + stylis@4.3.4: {} - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 - dev: true - /supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - dev: true + supports-preserve-symlinks-flag@1.0.0: {} - /tapable@2.2.1: - resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} - engines: {node: '>=6'} - dev: true + tapable@2.2.1: {} - /text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - dev: true + text-table@0.2.0: {} - /throttle-debounce@5.0.2: - resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} - engines: {node: '>=12.22'} - dev: false + throttle-debounce@5.0.2: {} - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - dev: true - /toggle-selection@1.0.6: - resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} - dev: false + toggle-selection@1.0.6: {} - /ts-api-utils@1.3.0(typescript@5.0.2): - resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} - engines: {node: '>=16'} - peerDependencies: - typescript: '>=4.2.0' + ts-api-utils@1.3.0(typescript@5.0.2): dependencies: typescript: 5.0.2 - dev: true - /tsconfig-paths@3.15.0: - resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 json5: 1.0.2 minimist: 1.2.8 strip-bom: 3.0.0 - dev: true - /tslib@2.7.0: - resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} - dev: false + tslib@2.7.0: {} - /type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 - dev: true - /type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - dev: true + type-fest@0.20.2: {} - /typed-array-buffer@1.0.2: - resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} - engines: {node: '>= 0.4'} + typed-array-buffer@1.0.2: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-typed-array: 1.1.13 - dev: true - /typed-array-byte-length@1.0.1: - resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} - engines: {node: '>= 0.4'} + typed-array-byte-length@1.0.1: dependencies: call-bind: 1.0.7 for-each: 0.3.3 gopd: 1.0.1 has-proto: 1.0.3 is-typed-array: 1.1.13 - dev: true - /typed-array-byte-offset@1.0.2: - resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} - engines: {node: '>= 0.4'} + typed-array-byte-offset@1.0.2: dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.7 @@ -3670,11 +4179,8 @@ packages: gopd: 1.0.1 has-proto: 1.0.3 is-typed-array: 1.1.13 - dev: true - /typed-array-length@1.0.6: - resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} - engines: {node: '>= 0.4'} + typed-array-length@1.0.6: dependencies: call-bind: 1.0.7 for-each: 0.3.3 @@ -3682,58 +4188,37 @@ packages: has-proto: 1.0.3 is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 - dev: true - /typeface-montserrat@1.1.13: - resolution: {integrity: sha512-Pklkyj0e+K+6I/t0M6JBDBphpfJkF1k+3qd8qDnp9aVtCC7oGBQWTAcL6+5eArfGe7h73uPwyal73hEkf9YCUA==} - dev: false + typeface-montserrat@1.1.13: {} - /typescript@5.0.2: - resolution: {integrity: sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==} - engines: {node: '>=12.20'} - hasBin: true - dev: true + typescript@5.0.2: {} - /unbox-primitive@1.0.2: - resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + unbox-primitive@1.0.2: dependencies: call-bind: 1.0.7 has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 - dev: true - /uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + uri-js@4.4.1: dependencies: punycode: 2.3.1 - dev: true - /util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - dev: false + util-deprecate@1.0.2: {} - /v8-compile-cache@2.4.0: - resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==} - dev: true + v8-compile-cache@2.4.0: {} - /w3c-keyname@2.2.8: - resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} - dev: false + w3c-keyname@2.2.8: {} - /which-boxed-primitive@1.0.2: - resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + which-boxed-primitive@1.0.2: dependencies: is-bigint: 1.0.4 is-boolean-object: 1.1.2 is-number-object: 1.0.7 is-string: 1.0.7 is-symbol: 1.0.4 - dev: true - /which-builtin-type@1.1.4: - resolution: {integrity: sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==} - engines: {node: '>= 0.4'} + which-builtin-type@1.1.4: dependencies: function.prototype.name: 1.1.6 has-tostringtag: 1.0.2 @@ -3747,108 +4232,58 @@ packages: which-boxed-primitive: 1.0.2 which-collection: 1.0.2 which-typed-array: 1.1.15 - dev: true - /which-collection@1.0.2: - resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} - engines: {node: '>= 0.4'} + which-collection@1.0.2: dependencies: is-map: 2.0.3 is-set: 2.0.3 is-weakmap: 2.0.2 is-weakset: 2.0.3 - dev: true - /which-typed-array@1.1.15: - resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} - engines: {node: '>= 0.4'} + which-typed-array@1.1.15: dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.7 for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.2 - dev: true - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true + which@2.0.2: dependencies: isexe: 2.0.0 - dev: true - /word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - dev: true + word-wrap@1.2.5: {} - /wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true - /wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} + wrap-ansi@8.1.0: dependencies: ansi-styles: 6.2.1 string-width: 5.1.2 strip-ansi: 7.1.0 - dev: true - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true + wrappy@1.0.2: {} - /ws@8.18.0: - resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} - engines: {node: '>=10.0.0'} - requiresBuild: true - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: false + ws@8.18.0: optional: true - /y-codemirror.next@0.3.5(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(yjs@13.6.20): - resolution: {integrity: sha512-VluNu3e5HfEXybnypnsGwKAj+fKLd4iAnR7JuX1Sfyydmn1jCBS5wwEL/uS04Ch2ib0DnMAOF6ZRR/8kK3wyGw==} - peerDependencies: - '@codemirror/state': ^6.0.0 - '@codemirror/view': ^6.0.0 - yjs: ^13.5.6 + y-codemirror.next@0.3.5(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(yjs@13.6.20): dependencies: '@codemirror/state': 6.4.1 '@codemirror/view': 6.34.1 lib0: 0.2.98 yjs: 13.6.20 - dev: false - /y-protocols@1.0.6(yjs@13.6.20): - resolution: {integrity: sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==} - engines: {node: '>=16.0.0', npm: '>=8.0.0'} - peerDependencies: - yjs: ^13.0.0 + y-protocols@1.0.6(yjs@13.6.20): dependencies: lib0: 0.2.98 yjs: 13.6.20 - dev: false - /y-webrtc@10.3.0(yjs@13.6.20): - resolution: {integrity: sha512-KalJr7dCgUgyVFxoG3CQYbpS0O2qybegD0vI4bYnYHI0MOwoVbucED3RZ5f2o1a5HZb1qEssUKS0H/Upc6p1lA==} - engines: {node: '>=12'} - hasBin: true - peerDependencies: - yjs: ^13.6.8 + y-webrtc@10.3.0(yjs@13.6.20): dependencies: lib0: 0.2.98 simple-peer: 9.11.1 @@ -3860,11 +4295,7 @@ packages: - bufferutil - supports-color - utf-8-validate - dev: false - /yjs@13.6.20: - resolution: {integrity: sha512-Z2YZI+SYqK7XdWlloI3lhMiKnCdFCVC4PchpdO+mCYwtiTwncjUbnRK9R1JmkNfdmHyDXuWN3ibJAt0wsqTbLQ==} - engines: {node: '>=16.0.0', npm: '>=8.0.0'} + yjs@13.6.20: dependencies: lib0: 0.2.98 - dev: false diff --git a/apps/frontend/src/app/matching/MatchingModal.tsx b/apps/frontend/src/app/matching/MatchingModal.tsx index d5b37b7fc5..16288bd78d 100644 --- a/apps/frontend/src/app/matching/MatchingModal.tsx +++ b/apps/frontend/src/app/matching/MatchingModal.tsx @@ -103,8 +103,7 @@ const MatchingModal: React.FC = ({ matchingState.info.partnerName ); localStorage.setItem("collabId", matchingState.info.matchId); - localStorage.setItem("docRefId", "CV480GUbjk15eWOrWrA0"); // TODO: remove temporary placeholder for quesiton testing - // localStorage.setItem("docRefId", matchingState.info.docRefId); // TODO: Update the response from backend when match_found + localStorage.setItem("docRefId", matchingState.info.docRefId); // TODO: Update the response from backend when match_found // Redirect to collaboration page router.push(`/collaboration/${matchingState.info.matchId}`); diff --git a/apps/frontend/src/app/services/use-matching.ts b/apps/frontend/src/app/services/use-matching.ts index 4a37c9f153..21fac18be6 100644 --- a/apps/frontend/src/app/services/use-matching.ts +++ b/apps/frontend/src/app/services/use-matching.ts @@ -138,5 +138,6 @@ function parseInfoFromResponse(responseJson: MatchFoundResponse): MatchInfo { matchId: responseJson.match_id?.toString() ?? "unknown", partnerName: responseJson.matched_user ?? "unknown", myName: responseJson.user ?? "unknown", + docRefId: responseJson.question_doc_ref_id ?? "unknown", }; } diff --git a/apps/frontend/src/contexts/websocketcontext.tsx b/apps/frontend/src/contexts/websocketcontext.tsx index 84893c15ed..b4946ec225 100644 --- a/apps/frontend/src/contexts/websocketcontext.tsx +++ b/apps/frontend/src/contexts/websocketcontext.tsx @@ -17,6 +17,7 @@ export type MatchInfo = { matchId: string; myName: string; partnerName: string; + docRefId: string; } export type MatchState = SocketState | { state: "found"; From 290094b7df764f9146a34b715e227e975ef0a2d5 Mon Sep 17 00:00:00 2001 From: solomonng2001 Date: Sat, 26 Oct 2024 20:17:07 +0800 Subject: [PATCH 056/258] Remove comments --- .../src/app/matching/MatchingModal.tsx | 2 +- apps/signalling-service/pnpm-lock.yaml | 40 +++++++++++-------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/apps/frontend/src/app/matching/MatchingModal.tsx b/apps/frontend/src/app/matching/MatchingModal.tsx index 16288bd78d..9fa9334b5f 100644 --- a/apps/frontend/src/app/matching/MatchingModal.tsx +++ b/apps/frontend/src/app/matching/MatchingModal.tsx @@ -103,7 +103,7 @@ const MatchingModal: React.FC = ({ matchingState.info.partnerName ); localStorage.setItem("collabId", matchingState.info.matchId); - localStorage.setItem("docRefId", matchingState.info.docRefId); // TODO: Update the response from backend when match_found + localStorage.setItem("docRefId", matchingState.info.docRefId); // Redirect to collaboration page router.push(`/collaboration/${matchingState.info.matchId}`); diff --git a/apps/signalling-service/pnpm-lock.yaml b/apps/signalling-service/pnpm-lock.yaml index cd6e4916a0..04ce15c614 100644 --- a/apps/signalling-service/pnpm-lock.yaml +++ b/apps/signalling-service/pnpm-lock.yaml @@ -1,32 +1,31 @@ -lockfileVersion: '6.0' +lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -dependencies: - lib0: - specifier: ^0.2.98 - version: 0.2.98 - ws: - specifier: ^8.18.0 - version: 8.18.0 +importers: + + .: + dependencies: + lib0: + specifier: ^0.2.98 + version: 0.2.98 + ws: + specifier: ^8.18.0 + version: 8.18.0 packages: - /isomorphic.js@0.2.5: + isomorphic.js@0.2.5: resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} - dev: false - /lib0@0.2.98: + lib0@0.2.98: resolution: {integrity: sha512-XteTiNO0qEXqqweWx+b21p/fBnNHUA1NwAtJNJek1oPrewEZs2uiT4gWivHKr9GqCjDPAhchz0UQO8NwU3bBNA==} engines: {node: '>=16'} hasBin: true - dependencies: - isomorphic.js: 0.2.5 - dev: false - /ws@8.18.0: + ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} peerDependencies: @@ -37,4 +36,13 @@ packages: optional: true utf-8-validate: optional: true - dev: false + +snapshots: + + isomorphic.js@0.2.5: {} + + lib0@0.2.98: + dependencies: + isomorphic.js: 0.2.5 + + ws@8.18.0: {} From 68023da7dd9dfc49de8e04dfd2179db267ac4e8d Mon Sep 17 00:00:00 2001 From: bensohh Date: Sun, 27 Oct 2024 15:01:04 +0800 Subject: [PATCH 057/258] Implement session timer using localstorage --- .../src/app/collaboration/[id]/page.tsx | 93 ++++++++++++++++--- .../src/app/collaboration/[id]/styles.scss | 6 ++ 2 files changed, 84 insertions(+), 15 deletions(-) diff --git a/apps/frontend/src/app/collaboration/[id]/page.tsx b/apps/frontend/src/app/collaboration/[id]/page.tsx index fbca214fb4..7e671a69a1 100644 --- a/apps/frontend/src/app/collaboration/[id]/page.tsx +++ b/apps/frontend/src/app/collaboration/[id]/page.tsx @@ -15,7 +15,7 @@ import { import { Content } from "antd/es/layout/layout"; import "./styles.scss"; import { useRouter, useSearchParams } from "next/navigation"; -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { GetSingleQuestion, Question } from "@/app/services/question"; import { ClockCircleOutlined, @@ -50,6 +50,11 @@ export default function CollaborationPage(props: CollaborationProps) { ); const [currentUser, setCurrentUser] = useState(undefined); const [matchedUser, setMatchedUser] = useState(undefined); + const [sessionDuration, setSessionDuration] = useState(() => { + const storedTime = localStorage.getItem("session-duration"); + return storedTime ? parseInt(storedTime) : 0; + }); // State for count-up timer (TODO: currently using localstorage to store time, change to db stored time in the future) + const stopwatchRef = useRef(null); // Chat states const [messageToSend, setMessageToSend] = useState( @@ -61,8 +66,42 @@ export default function CollaborationPage(props: CollaborationProps) { undefined ); - // Retrieve the docRefId from query params during page navigation - // const searchParams = useSearchParams(); + // Stops the session duration stopwatch + const stopStopwatch = () => { + if (stopwatchRef.current) { + clearInterval(stopwatchRef.current); + } + }; + + // Starts the session duration stopwatch + const startStopwatch = () => { + if (stopwatchRef.current) { + clearInterval(stopwatchRef.current); + } + + stopwatchRef.current = setInterval(() => { + setSessionDuration((prevTime) => { + const newTime = prevTime + 1; + localStorage.setItem("session-duration", newTime.toString()); + return newTime; + }); + }, 1000); + }; + + // Convert seconds into time of format "hh:mm:ss" + const formatTime = (seconds: number) => { + const hours = Math.floor(seconds / 3600); + const minutes = Math.floor((seconds % 3600) / 60); + const secs = seconds % 60; + + return ( + (hours > 9 ? hours : "0" + hours) + + ":" + + (minutes > 9 ? minutes : "0" + minutes) + + ":" + + (secs > 9 ? secs : "0" + secs) + ); + }; // Fetch the question on initialisation useEffect(() => { @@ -81,14 +120,19 @@ export default function CollaborationPage(props: CollaborationProps) { setMatchedUser(matchedUser); setCurrentUser(currentUser); + // Fetch question and set question states GetSingleQuestion(docRefId).then((data: Question) => { setQuestionTitle(`${data.id}. ${data.title}`); setComplexity(data.complexity); setCategories(data.categories); setDescription(data.description); }); + + // Start stopwatch + startStopwatch(); }, []); + // Tabs component items for testcases const items: TabsProps["items"] = [ { key: "1", @@ -117,15 +161,21 @@ export default function CollaborationPage(props: CollaborationProps) { }, ]; + // Handles the cleaning of localstorage variables, stopping the timer & signalling collab user on webrtc const handleCloseCollaboration = () => { - // Remove localstorage variables for collaboration - localStorage.removeItem("user"); - localStorage.removeItem("matchedUser"); - localStorage.removeItem("collaId"); - localStorage.removeItem("docRefId"); + // Stop stopwatch + stopStopwatch(); + // Remove localstorage variable for stored session duration + localStorage.removeItem("session-duration"); // TODO: Remove this after collaboration backend data stored - // Redirect back to matching page - router.push("/matching"); + // // Remove localstorage variables for collaboration + // localStorage.removeItem("user"); + // localStorage.removeItem("matchedUser"); + // localStorage.removeItem("collaId"); + // localStorage.removeItem("docRefId"); + + // // Redirect back to matching page + // router.push("/matching"); }; return ( @@ -170,7 +220,11 @@ export default function CollaborationPage(props: CollaborationProps) { Test Cases
{/* TODO: Link to execution service for running code against test-cases */} -
@@ -189,7 +243,11 @@ export default function CollaborationPage(props: CollaborationProps) { Code
{/* TODO: Link to execution service for code submission */} -
@@ -221,15 +279,20 @@ export default function CollaborationPage(props: CollaborationProps) { Session Details
{/* TODO: End the collaboration session, cleanup the localstorage variables */} -
Duration: - {/* TODO: Implement a count-up timer for session duration */} - 00:00:00 + + {formatTime(sessionDuration)} +
Matched User: diff --git a/apps/frontend/src/app/collaboration/[id]/styles.scss b/apps/frontend/src/app/collaboration/[id]/styles.scss index 35f2ea7a79..7fee13a64d 100644 --- a/apps/frontend/src/app/collaboration/[id]/styles.scss +++ b/apps/frontend/src/app/collaboration/[id]/styles.scss @@ -168,3 +168,9 @@ .title-icons { margin-right: 4px; } + +.code-submit-button, +.session-end-button, +.test-case-button { + width: fit-content; +} From 77ff847a112567c529fb6430d4ceb8821a82c777 Mon Sep 17 00:00:00 2001 From: bensohh Date: Sun, 27 Oct 2024 15:44:10 +0800 Subject: [PATCH 058/258] Add modal component on top of end session --- .../src/app/collaboration/[id]/page.tsx | 45 +++++++++++-------- .../src/app/collaboration/[id]/styles.scss | 4 ++ 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/apps/frontend/src/app/collaboration/[id]/page.tsx b/apps/frontend/src/app/collaboration/[id]/page.tsx index 7e671a69a1..2a69d08491 100644 --- a/apps/frontend/src/app/collaboration/[id]/page.tsx +++ b/apps/frontend/src/app/collaboration/[id]/page.tsx @@ -5,6 +5,7 @@ import { Col, Input, Layout, + Modal, Row, Select, Tabs, @@ -66,6 +67,9 @@ export default function CollaborationPage(props: CollaborationProps) { undefined ); + // Modal state + const [isModalOpen, setIsModalOpen] = useState(false); + // Stops the session duration stopwatch const stopStopwatch = () => { if (stopwatchRef.current) { @@ -168,14 +172,14 @@ export default function CollaborationPage(props: CollaborationProps) { // Remove localstorage variable for stored session duration localStorage.removeItem("session-duration"); // TODO: Remove this after collaboration backend data stored - // // Remove localstorage variables for collaboration - // localStorage.removeItem("user"); - // localStorage.removeItem("matchedUser"); - // localStorage.removeItem("collaId"); - // localStorage.removeItem("docRefId"); + // Remove localstorage variables for collaboration + localStorage.removeItem("user"); + localStorage.removeItem("matchedUser"); + localStorage.removeItem("collaId"); + localStorage.removeItem("docRefId"); - // // Redirect back to matching page - // router.push("/matching"); + // Redirect back to matching page + router.push("/matching"); }; return ( @@ -251,15 +255,6 @@ export default function CollaborationPage(props: CollaborationProps) { Submit
- {/*
-
Select Language:
-
- Start Time: + Start Time: 01:23:45
- + Session Duration:{" "} - + 01:23:45
- Matched with: + Matched with: John Doe
diff --git a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx index 5328da6cdf..dda8403650 100644 --- a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx +++ b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx @@ -1,8 +1,12 @@ // Referenced from example in https://www.npmjs.com/package/y-codemirror.next import React, { Dispatch, + ForwardedRef, + forwardRef, + RefObject, SetStateAction, useEffect, + useImperativeHandle, useRef, useState, } from "react"; @@ -26,6 +30,11 @@ interface CollaborativeEditorProps { collaborationId: string; language: string; setMatchedUser: Dispatch>; + handleCloseCollaboration: (type: string) => void; +} + +export interface CollaborativeEditorHandle { + endSession: () => void; } export const usercolors = [ @@ -43,196 +52,215 @@ export const usercolors = [ export const userColor = usercolors[Math.floor(Math.random() * (usercolors.length - 1))]; -const CollaborativeEditor = (props: CollaborativeEditorProps) => { - const editorRef = useRef(null); - // const viewRef = useRef(null); - const [selectedLanguage, setSelectedLanguage] = useState("JavaScript"); - const [trigger, setTrigger] = useState(false); - - const languageConf = new Compartment(); - - // Referenced: https://codemirror.net/examples/config/#dynamic-configuration - const autoLanguage = EditorState.transactionExtender.of((tr) => { - if (!tr.docChanged) return null; - - const snippet = tr.newDoc.sliceString(0, 100); - // Test for various language - const docIsPython = /^\s*(def|class)\s/.test(snippet); - const docIsJava = /^\s*(class|public\s+static\s+void\s+main)\s/.test( - snippet - ); // Java has some problems - const docIsCpp = /^\s*(#include|namespace|int\s+main)\s/.test(snippet); // Yet to test c++ - const docIsGo = /^(package|import|func|type|var|const)\s/.test(snippet); - - let newLanguage; - let languageType; - let languageLabel; - - if (docIsPython) { - newLanguage = python(); - languageLabel = "Python"; - languageType = pythonLanguage; - } else if (docIsJava) { - newLanguage = java(); - languageLabel = "Java"; - languageType = javaLanguage; - } else if (docIsGo) { - newLanguage = go(); - languageLabel = "Go"; - languageType = goLanguage; - } else if (docIsCpp) { - newLanguage = cpp(); - languageLabel = "C++"; - languageType = cppLanguage; - } else { - newLanguage = javascript(); // Default to JavaScript - languageLabel = "JavaScript"; - languageType = javascriptLanguage; - } - - const stateLanguage = tr.startState.facet(language); - if (languageType == stateLanguage) return null; - - setSelectedLanguage(languageLabel); - - return { - effects: languageConf.reconfigure(newLanguage), - }; - }); +const CollaborativeEditor = forwardRef( + ( + props: CollaborativeEditorProps, + ref: ForwardedRef + ) => { + const editorRef = useRef(null); + const providerRef = useRef(null); + const [selectedLanguage, setSelectedLanguage] = useState("JavaScript"); + // const [sessionEndNotified, setSessionEndNotified] = + // useState(false); + let sessionEndNotified = false; - const [messageApi, contextHolder] = message.useMessage(); + const languageConf = new Compartment(); - const success = (message: string) => { - messageApi.open({ - type: "success", - content: message, - }); - }; + // Referenced: https://codemirror.net/examples/config/#dynamic-configuration + const autoLanguage = EditorState.transactionExtender.of((tr) => { + if (!tr.docChanged) return null; - const error = (message: string) => { - messageApi.open({ - type: "error", - content: message, - }); - }; + const snippet = tr.newDoc.sliceString(0, 100); + // Test for various language + const docIsPython = /^\s*(def|class)\s/.test(snippet); + const docIsJava = /^\s*(class|public\s+static\s+void\s+main)\s/.test( + snippet + ); // Java has some problems + const docIsCpp = /^\s*(#include|namespace|int\s+main)\s/.test(snippet); // Yet to test c++ + const docIsGo = /^(package|import|func|type|var|const)\s/.test(snippet); - const warning = (message: string) => { - messageApi.open({ - type: "warning", - content: message, - }); - }; - - // const handleLanguageChange = (val: any) => { - // console.log("came in here"); - // console.log(val); - // setSelectedLanguage(val); - - // let languageExtension; - // switch (val) { - // case "python": - // languageExtension = python(); - // break; - // default: - // languageExtension = javascript(); - // } - - // // Update the language configuration - // if (viewRef.current) { - // console.log("insude here"); - // viewRef.current.dispatch({ - // effects: languageConf.reconfigure(languageExtension), - // }); - // } - // }; - - useEffect(() => { - if (process.env.NEXT_PUBLIC_SIGNALLING_SERVICE_URL === undefined) { - error("Missing Signalling Service Url"); - return; - } - - const ydoc = new Y.Doc(); - const provider = new WebrtcProvider(props.collaborationId, ydoc, { - signaling: [process.env.NEXT_PUBLIC_SIGNALLING_SERVICE_URL], - maxConns: 2, - }); - const ytext = ydoc.getText("codemirror"); - const undoManager = new Y.UndoManager(ytext); + let newLanguage; + let languageType; + let languageLabel; + + if (docIsPython) { + newLanguage = python(); + languageLabel = "Python"; + languageType = pythonLanguage; + } else if (docIsJava) { + newLanguage = java(); + languageLabel = "Java"; + languageType = javaLanguage; + } else if (docIsGo) { + newLanguage = go(); + languageLabel = "Go"; + languageType = goLanguage; + } else if (docIsCpp) { + newLanguage = cpp(); + languageLabel = "C++"; + languageType = cppLanguage; + } else { + newLanguage = javascript(); // Default to JavaScript + languageLabel = "JavaScript"; + languageType = javascriptLanguage; + } - provider.awareness.setLocalStateField("user", { - name: props.user, - color: userColor.color, - colorLight: userColor.light, + const stateLanguage = tr.startState.facet(language); + if (languageType == stateLanguage) return null; + + setSelectedLanguage(languageLabel); + + return { + effects: languageConf.reconfigure(newLanguage), + }; }); - // Check initial awareness states - const states = provider.awareness.getStates(); - for (const [clientID, state] of Array.from(states)) { - if (state.user && state.user.name !== props.user) { - props.setMatchedUser(state.user.name); - break; + const [messageApi, contextHolder] = message.useMessage(); + + const success = (message: string) => { + messageApi.open({ + type: "success", + content: message, + }); + }; + + const info = (message: string) => { + messageApi.open({ + type: "info", + content: message, + }); + }; + + const error = (message: string) => { + messageApi.open({ + type: "error", + content: message, + }); + }; + + const warning = (message: string) => { + messageApi.open({ + type: "warning", + content: message, + }); + }; + + useImperativeHandle(ref, () => ({ + endSession: () => { + if (providerRef.current) { + // Set awareness state to indicate session ended to notify peer about session ending + providerRef.current.awareness.setLocalStateField( + "sessionEnded", + true + ); + success("Session ended. All participants will be notified."); + } + }, + })); + + useEffect(() => { + if (process.env.NEXT_PUBLIC_SIGNALLING_SERVICE_URL === undefined) { + error("Missing Signalling Service Url"); + return; } - } - // Listen for awareness changes - provider.awareness.on("change", () => { - const updatedStates = provider.awareness.getStates(); - for (const [clientID, state] of Array.from(updatedStates)) { + const ydoc = new Y.Doc(); + const provider = new WebrtcProvider(props.collaborationId, ydoc, { + signaling: [process.env.NEXT_PUBLIC_SIGNALLING_SERVICE_URL], + maxConns: 2, + }); + + providerRef.current = provider; + const ytext = ydoc.getText("codemirror"); + const undoManager = new Y.UndoManager(ytext); + + provider.awareness.setLocalStateField("user", { + name: props.user, + color: userColor.color, + colorLight: userColor.light, + }); + + // Check initial awareness states + const states = provider.awareness.getStates(); + for (const [clientID, state] of Array.from(states)) { if (state.user && state.user.name !== props.user) { props.setMatchedUser(state.user.name); break; } } - }); - const state = EditorState.create({ - doc: ytext.toString(), - extensions: [ - basicSetup, - languageConf.of(javascript()), - autoLanguage, - yCollab(ytext, provider.awareness, { undoManager }), - ], - }); + // Listen for awareness changes + provider.awareness.on("change", () => { + const updatedStates = provider.awareness.getStates(); + for (const [clientID, state] of Array.from(updatedStates)) { + if (state.sessionEnded && state.user.name !== props.user) { + if (!sessionEndNotified) { + info( + `Session has been ended by another participant ${state.user.name}` + ); - const view = new EditorView({ - state, - parent: editorRef.current || undefined, - }); + props.handleCloseCollaboration("peer"); + sessionEndNotified = true; + if (providerRef.current) { + providerRef.current.disconnect(); + } + return; + } + } - return () => { - // Cleanup on component unmount - console.log("unmounting collaboration editor"); // TODO: remove - view.destroy(); - // viewRef.current?.destroy(); - provider.disconnect(); - ydoc.destroy(); - }; - }, []); - - return ( - <> - {contextHolder} -
-
Select Language:
- setSelectedLanguage(val)} + disabled + /> +
+
-
-
-
- Current Language Detected: {selectedLanguage} -
- - ); -}; +
+ Current Language Detected: {selectedLanguage} +
+ + ); + } +); export default CollaborativeEditor; From 5be7f3c10f312e66f0219848a565477682b8c22c Mon Sep 17 00:00:00 2001 From: bensohh Date: Mon, 28 Oct 2024 16:48:53 +0800 Subject: [PATCH 082/258] Minor UI adjustment for modal --- apps/frontend/src/app/collaboration/[id]/page.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/frontend/src/app/collaboration/[id]/page.tsx b/apps/frontend/src/app/collaboration/[id]/page.tsx index fbfde4c2b4..abedefacba 100644 --- a/apps/frontend/src/app/collaboration/[id]/page.tsx +++ b/apps/frontend/src/app/collaboration/[id]/page.tsx @@ -221,8 +221,7 @@ export default function CollaborationPage(props: CollaborationProps) { >

The collaboration session has ended. You will be redirected in{" "} - {countDown} - seconds + {countDown} seconds

Question:{" "} From 3502e42e495849819e9c2d6646e034744179fb28 Mon Sep 17 00:00:00 2001 From: solomonng2001 Date: Tue, 29 Oct 2024 01:43:06 +0800 Subject: [PATCH 083/258] Sync submission across webrtc and update history-service routing --- .../src/app/collaboration/[id]/page.tsx | 43 +++--- apps/frontend/src/app/services/history.ts | 61 ++++++--- .../CollaborativeEditor.tsx | 35 ++++- apps/history-service/handlers/create.go | 21 +-- .../handlers/createOrUpdate.go | 125 ++++++++++++++++++ apps/history-service/handlers/delete.go | 4 +- apps/history-service/handlers/list.go | 69 ++++++++++ apps/history-service/handlers/read.go | 6 +- apps/history-service/handlers/update.go | 12 +- apps/history-service/main.go | 21 ++- apps/history-service/models/models.go | 1 - 11 files changed, 314 insertions(+), 84 deletions(-) create mode 100644 apps/history-service/handlers/createOrUpdate.go create mode 100644 apps/history-service/handlers/list.go diff --git a/apps/frontend/src/app/collaboration/[id]/page.tsx b/apps/frontend/src/app/collaboration/[id]/page.tsx index 9c9538e614..1e9c5548c8 100644 --- a/apps/frontend/src/app/collaboration/[id]/page.tsx +++ b/apps/frontend/src/app/collaboration/[id]/page.tsx @@ -16,7 +16,7 @@ import { import { Content } from "antd/es/layout/layout"; import "./styles.scss"; import { useRouter, useSearchParams } from "next/navigation"; -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { GetSingleQuestion, Question } from "@/app/services/question"; import { ClockCircleOutlined, @@ -28,13 +28,15 @@ import { } from "@ant-design/icons"; import { ProgrammingLanguageOptions } from "@/utils/SelectOptions"; import CollaborativeEditor from "@/components/CollaborativeEditor/CollaborativeEditor"; -import { CreateHistory, UpdateHistory } from "@/app/services/history"; +import { CreateOrUpdateHistory } from "@/app/services/history"; import { Language } from "@codemirror/language"; +import { WebrtcProvider } from "y-webrtc"; interface CollaborationProps {} export default function CollaborationPage(props: CollaborationProps) { const router = useRouter(); + const providerRef = useRef(null); const [isLoading, setIsLoading] = useState(false); @@ -80,26 +82,18 @@ export default function CollaborationPage(props: CollaborationProps) { }); }; - const handleSubmitCode = async () => { - if (!historyDocRefId) { - const data = await CreateHistory({ - title: questionTitle ?? "", - code: code, - language: selectedLanguage, - user: currentUser ?? "", - matchedUser: matchedUser ?? "", - matchId: collaborationId ?? "", - matchedTopics: matchedTopics ?? [], - questionDocRefId: questionDocRefId ?? "", - questionDifficulty: complexity ?? "", - questionTopics: categories, - }); - setHistoryDocRefId(data.docRefId); - successMessage("Code submitted successfully!"); - return; + const sendCodeSavedStatusToMatchedUser = () => { + if (!providerRef.current) { + throw new Error("Provider not initialized"); } + providerRef.current.awareness.setLocalStateField("codeSavedStatus", true); + } - UpdateHistory({ + const handleSubmitCode = async () => { + if (!collaborationId) { + throw new Error("Collaboration ID not found"); + } + const data = await CreateOrUpdateHistory({ title: questionTitle ?? "", code: code, language: selectedLanguage, @@ -110,8 +104,9 @@ export default function CollaborationPage(props: CollaborationProps) { questionDocRefId: questionDocRefId ?? "", questionDifficulty: complexity ?? "", questionTopics: categories, - }, historyDocRefId!); - successMessage("Code updated successfully!"); + }, collaborationId); + successMessage("Code saved successfully!"); + sendCodeSavedStatusToMatchedUser(); } const handleCodeChange = (code: string) => { @@ -273,7 +268,9 @@ export default function CollaborationPage(props: CollaborationProps) { user={currentUser} collaborationId={collaborationId} language={selectedLanguage} - onCodeChange={handleCodeChange} + providerRef={providerRef} + matchedUser={matchedUser} + onCodeChange={handleCodeChange} /> )}

diff --git a/apps/frontend/src/app/services/history.ts b/apps/frontend/src/app/services/history.ts index ddce38c46e..fc01f913ec 100644 --- a/apps/frontend/src/app/services/history.ts +++ b/apps/frontend/src/app/services/history.ts @@ -13,41 +13,64 @@ export interface History { questionTopics: string[]; createdAt?: string; updatedAt?: string; - docRefId?: string; } -export const CreateHistory = async ( - history: History +export const CreateOrUpdateHistory = async ( + history: History, + matchId: string, ): Promise => { - const response = await fetch(`${HISTORY_SERVICE_URL}histories`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(history), - }); + const response = await fetch( + `${HISTORY_SERVICE_URL}histories/${matchId}`, + { + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(history), + } + ); if (response.status === 200) { return response.json(); } else { throw new Error( - `Error creating history: ${response.status} ${response.statusText}` + `Error saving history: ${response.status} ${response.statusText}` ); } -}; +} -export const UpdateHistory = async ( - history: History, - historyDocRefId: string +export const GetHistory = async ( + matchId: string, ): Promise => { const response = await fetch( - `${HISTORY_SERVICE_URL}histories/${historyDocRefId}`, + `${HISTORY_SERVICE_URL}histories/${matchId}`, { - method: "PUT", + method: "GET", + headers: { + "Content-Type": "application/json", + }, + } + ); + + if (response.status === 200) { + return response.json(); + } else { + throw new Error( + `Error reading history: ${response.status} ${response.statusText}` + ); + } +} + +export const GetUserHistories = async ( + username: string, +): Promise => { + const response = await fetch( + `${HISTORY_SERVICE_URL}histories/${username}`, + { + method: "GET", headers: { "Content-Type": "application/json", }, - body: JSON.stringify(history), } ); @@ -55,7 +78,7 @@ export const UpdateHistory = async ( return response.json(); } else { throw new Error( - `Error updating history: ${response.status} ${response.statusText}` + `Error reading user histories: ${response.status} ${response.statusText}` ); } } diff --git a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx index 1174a24601..5b5c01c06f 100644 --- a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx +++ b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx @@ -1,5 +1,5 @@ // Referenced from example in https://www.npmjs.com/package/y-codemirror.next -import React, { useEffect, useRef, useState } from "react"; +import React, { MutableRefObject, useEffect, useRef, useState } from "react"; import * as Y from "yjs"; import { yCollab } from "y-codemirror.next"; import { WebrtcProvider } from "y-webrtc"; @@ -19,9 +19,26 @@ interface CollaborativeEditorProps { user: string; collaborationId: string; language: string; + providerRef: MutableRefObject; + matchedUser: string | undefined; onCodeChange: (code: string) => void; } +interface AwarenessUpdate { + added: number[]; + updated: number[]; + removed: number[]; +} + +interface Awareness { + user: { + name: string; + color: string; + colorLight: string; + }; + codeSavedStatus: boolean; +} + export const usercolors = [ { color: "#30bced", light: "#30bced33" }, { color: "#6eeb83", light: "#6eeb8333" }, @@ -154,8 +171,8 @@ const CollaborativeEditor = (props: CollaborativeEditorProps) => { const provider = new WebrtcProvider(props.collaborationId, ydoc, { signaling: [process.env.NEXT_PUBLIC_SIGNALLING_SERVICE_URL], }); + props.providerRef.current = provider; const ytext = ydoc.getText("codemirror"); - console.log("testing y text", ytext); // TODO: remove const undoManager = new Y.UndoManager(ytext); provider.awareness.setLocalStateField("user", { @@ -164,6 +181,20 @@ const CollaborativeEditor = (props: CollaborativeEditorProps) => { colorLight: userColor.light, }); + // Listener for awareness updates to receive status changes from peers + provider.awareness.on("update", ({ added, updated } : AwarenessUpdate) => { + added.concat(updated).filter(clientId => clientId !== provider.awareness.clientID).forEach((clientID) => { + const state = provider.awareness.getStates().get(clientID) as Awareness; + if (state && state.codeSavedStatus) { + // Display the received status message + messageApi.open({ + type: "success", + content: `${props.matchedUser ?? "Peer"} saved code successfully!`, + }); + } + }); + }); + const state = EditorState.create({ doc: ytext.toString(), extensions: [ diff --git a/apps/history-service/handlers/create.go b/apps/history-service/handlers/create.go index c2098ced19..d981fb9190 100644 --- a/apps/history-service/handlers/create.go +++ b/apps/history-service/handlers/create.go @@ -1,6 +1,7 @@ package handlers import ( + "cloud.google.com/go/firestore" "encoding/json" "google.golang.org/api/iterator" "history-service/models" @@ -10,40 +11,36 @@ import ( // Create a new code snippet func (s *Service) CreateHistory(w http.ResponseWriter, r *http.Request) { - println("test1") ctx := r.Context() // Parse request var collaborationHistory models.CollaborationHistory if err := utils.DecodeJSONBody(w, r, &collaborationHistory); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) - println(err.Error()) return } - println("test2") + // Document reference ID in firestore mapped to the match ID in model + docRef := s.Client.Collection("collaboration-history").Doc(collaborationHistory.MatchID) - docRef, _, err := s.Client.Collection("collaboration-history").Add(ctx, map[string]interface{}{ + _, err := docRef.Set(ctx, map[string]interface{}{ "title": collaborationHistory.Title, "code": collaborationHistory.Code, "language": collaborationHistory.Language, "user": collaborationHistory.User, "matchedUser": collaborationHistory.MatchedUser, - "matchId": collaborationHistory.MatchID, "matchedTopics": collaborationHistory.MatchedTopics, "questionDocRefId": collaborationHistory.QuestionDocRefID, "questionDifficulty": collaborationHistory.QuestionDifficulty, "questionTopics": collaborationHistory.QuestionTopics, - "createdAt": collaborationHistory.CreatedAt, - "updatedAt": collaborationHistory.UpdatedAt, + "createdAt": firestore.ServerTimestamp, + "updatedAt": firestore.ServerTimestamp, }) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } - println("test3") - // Get data doc, err := docRef.Get(ctx) if err != nil { @@ -55,16 +52,12 @@ func (s *Service) CreateHistory(w http.ResponseWriter, r *http.Request) { return } - println("test4") - // Map data if err := doc.DataTo(&collaborationHistory); err != nil { http.Error(w, "Failed to map history data", http.StatusInternalServerError) return } - collaborationHistory.DocRefID = doc.Ref.ID - - println(collaborationHistory.Title, "test") + collaborationHistory.MatchID = doc.Ref.ID w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) diff --git a/apps/history-service/handlers/createOrUpdate.go b/apps/history-service/handlers/createOrUpdate.go new file mode 100644 index 0000000000..f9df4bcc33 --- /dev/null +++ b/apps/history-service/handlers/createOrUpdate.go @@ -0,0 +1,125 @@ +package handlers + +import ( + "cloud.google.com/go/firestore" + "encoding/json" + "github.com/go-chi/chi/v5" + "google.golang.org/api/iterator" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "history-service/models" + "history-service/utils" + "net/http" +) + +func (s *Service) CreateOrUpdateHistory(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + // Parse request + matchId := chi.URLParam(r, "matchId") + var collaborationHistory models.CollaborationHistory + if err := utils.DecodeJSONBody(w, r, &collaborationHistory); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + // Reference document + docRef := s.Client.Collection("collaboration-history").Doc(matchId) + + // Check if exists + _, err := docRef.Get(ctx) + if err != nil { + if status.Code(err) == codes.NotFound { + // Create collaboration history + _, err := docRef.Set(ctx, map[string]interface{}{ + "title": collaborationHistory.Title, + "code": collaborationHistory.Code, + "language": collaborationHistory.Language, + "user": collaborationHistory.User, + "matchedUser": collaborationHistory.MatchedUser, + "matchedTopics": collaborationHistory.MatchedTopics, + "questionDocRefId": collaborationHistory.QuestionDocRefID, + "questionDifficulty": collaborationHistory.QuestionDifficulty, + "questionTopics": collaborationHistory.QuestionTopics, + "createdAt": firestore.ServerTimestamp, + "updatedAt": firestore.ServerTimestamp, + }) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Get data + doc, err := docRef.Get(ctx) + if err != nil { + if err != iterator.Done { + http.Error(w, "History not found", http.StatusNotFound) + return + } + http.Error(w, "Failed to get history", http.StatusInternalServerError) + return + } + + // Map data + if err := doc.DataTo(&collaborationHistory); err != nil { + http.Error(w, "Failed to map history data", http.StatusInternalServerError) + return + } + collaborationHistory.MatchID = doc.Ref.ID + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(collaborationHistory) + return + } + } + + // Update collaboration history + + // Validation + // Check if exists + _, err = docRef.Get(ctx) + if err != nil { + if status.Code(err) == codes.NotFound { + http.Error(w, "History not found", http.StatusNotFound) + return + } + http.Error(w, "Error fetching history", http.StatusInternalServerError) + return + } + + // Prepare the update data. + updates := []firestore.Update{ + {Path: "code", Value: collaborationHistory.Code}, + {Path: "updatedAt", Value: firestore.ServerTimestamp}, + } + + // Update database + _, err = docRef.Update(ctx, updates) + if err != nil { + http.Error(w, "Error updating history", http.StatusInternalServerError) + return + } + + // Get data + doc, err := docRef.Get(ctx) + if err != nil { + if err != iterator.Done { + http.Error(w, "History not found", http.StatusNotFound) + return + } + http.Error(w, "Failed to get history", http.StatusInternalServerError) + return + } + + // Map data + if err := doc.DataTo(&collaborationHistory); err != nil { + http.Error(w, "Failed to map history data", http.StatusInternalServerError) + return + } + collaborationHistory.MatchID = doc.Ref.ID + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(collaborationHistory) +} diff --git a/apps/history-service/handlers/delete.go b/apps/history-service/handlers/delete.go index 5d73206174..a450b58ea4 100644 --- a/apps/history-service/handlers/delete.go +++ b/apps/history-service/handlers/delete.go @@ -12,10 +12,10 @@ func (s *Service) DeleteHistory(w http.ResponseWriter, r *http.Request) { ctx := r.Context() // Parse request - docRefId := chi.URLParam(r, "docRefId") + matchId := chi.URLParam(r, "matchId") // Reference document - docRef := s.Client.Collection("collaboration-history").Doc(docRefId) + docRef := s.Client.Collection("collaboration-history").Doc(matchId) // Validation // Check if exists diff --git a/apps/history-service/handlers/list.go b/apps/history-service/handlers/list.go new file mode 100644 index 0000000000..554dc159ca --- /dev/null +++ b/apps/history-service/handlers/list.go @@ -0,0 +1,69 @@ +package handlers + +import ( + "encoding/json" + "github.com/go-chi/chi/v5" + "google.golang.org/api/iterator" + "history-service/models" + "net/http" +) + +func (s *Service) ListUserHistories(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + // Parse request + username := chi.URLParam(r, "username") + + // Reference collection + collRef := s.Client.Collection("collaboration-history") + + // Query data + iterUser := collRef.Where("user", "==", username).Documents(ctx) + iterMatchedUser := collRef.Where("matchedUser", "==", username).Documents(ctx) + + // Map data + var histories []models.CollaborationHistory + for { + doc, err := iterUser.Next() + if err == iterator.Done { + break + } + if err != nil { + http.Error(w, "Failed to get histories for user", http.StatusInternalServerError) + return + } + + var history models.CollaborationHistory + if err := doc.DataTo(&history); err != nil { + http.Error(w, "Failed to map history data for user", http.StatusInternalServerError) + return + } + history.MatchID = doc.Ref.ID + + histories = append(histories, history) + } + + for { + doc, err := iterMatchedUser.Next() + if err == iterator.Done { + break + } + if err != nil { + http.Error(w, "Failed to get histories for matched user", http.StatusInternalServerError) + return + } + + var history models.CollaborationHistory + if err := doc.DataTo(&history); err != nil { + http.Error(w, "Failed to map history data for matched user", http.StatusInternalServerError) + return + } + history.MatchID = doc.Ref.ID + + histories = append(histories, history) + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(histories) +} diff --git a/apps/history-service/handlers/read.go b/apps/history-service/handlers/read.go index cc594e70af..fd97c5d031 100644 --- a/apps/history-service/handlers/read.go +++ b/apps/history-service/handlers/read.go @@ -12,10 +12,10 @@ import ( func (s *Service) ReadHistory(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - docRefID := chi.URLParam(r, "docRefId") + matchId := chi.URLParam(r, "matchId") // Reference document - docRef := s.Client.Collection("collaboration-history").Doc(docRefID) + docRef := s.Client.Collection("collaboration-history").Doc(matchId) // Get data doc, err := docRef.Get(ctx) @@ -34,7 +34,7 @@ func (s *Service) ReadHistory(w http.ResponseWriter, r *http.Request) { http.Error(w, "Failed to map history data", http.StatusInternalServerError) return } - collaborationHistory.DocRefID = doc.Ref.ID + collaborationHistory.MatchID = doc.Ref.ID w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) diff --git a/apps/history-service/handlers/update.go b/apps/history-service/handlers/update.go index 7eca693357..b6cb953709 100644 --- a/apps/history-service/handlers/update.go +++ b/apps/history-service/handlers/update.go @@ -1,6 +1,7 @@ package handlers import ( + "cloud.google.com/go/firestore" "encoding/json" "github.com/go-chi/chi/v5" "google.golang.org/api/iterator" @@ -9,9 +10,6 @@ import ( "history-service/models" "history-service/utils" "net/http" - "time" - - "cloud.google.com/go/firestore" ) // Update an existing code snippet @@ -19,7 +17,7 @@ func (s *Service) UpdateHistory(w http.ResponseWriter, r *http.Request) { ctx := r.Context() // Parse request - docRefId := chi.URLParam(r, "docRefId") + matchId := chi.URLParam(r, "matchId") var updatedHistory models.CollaborationHistory if err := utils.DecodeJSONBody(w, r, &updatedHistory); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) @@ -27,7 +25,7 @@ func (s *Service) UpdateHistory(w http.ResponseWriter, r *http.Request) { } // Reference document - docRef := s.Client.Collection("collaboration-history").Doc(docRefId) + docRef := s.Client.Collection("collaboration-history").Doc(matchId) // Validation // Check if exists @@ -44,7 +42,7 @@ func (s *Service) UpdateHistory(w http.ResponseWriter, r *http.Request) { // Prepare the update data. updates := []firestore.Update{ {Path: "code", Value: updatedHistory.Code}, - {Path: "updatedAt", Value: time.Now()}, + {Path: "updatedAt", Value: firestore.ServerTimestamp}, } // Update database @@ -70,7 +68,7 @@ func (s *Service) UpdateHistory(w http.ResponseWriter, r *http.Request) { http.Error(w, "Failed to map history data", http.StatusInternalServerError) return } - updatedHistory.DocRefID = doc.Ref.ID + updatedHistory.MatchID = doc.Ref.ID w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) diff --git a/apps/history-service/main.go b/apps/history-service/main.go index 6d4f745af8..cf69c934d2 100644 --- a/apps/history-service/main.go +++ b/apps/history-service/main.go @@ -23,13 +23,6 @@ func main() { log.Fatal("Error loading .env file") } - //ctx := context.Background() - //client, err := initFirestore(ctx) - //if err != nil { - // log.Fatalf("Failed to initialize Firestore client: %v", err) - //} - //defer client.Close() - // Initialize Firestore client ctx := context.Background() client, err := initFirestore(ctx) @@ -82,21 +75,23 @@ func initChiRouter(service *handlers.Service) *chi.Mux { func registerRoutes(r *chi.Mux, service *handlers.Service) { r.Route("/histories", func(r chi.Router) { - r.Post("/", service.CreateHistory) + r.Get("/{username}", service.ListUserHistories) + //r.Post("/", service.CreateHistory) - r.Route("/{docRefId}", func(r chi.Router) { + r.Route("/{matchId}", func(r chi.Router) { + r.Put("/", service.CreateOrUpdateHistory) r.Get("/", service.ReadHistory) - r.Put("/", service.UpdateHistory) - r.Delete("/", service.DeleteHistory) + //r.Put("/", service.UpdateHistory) + //r.Delete("/", service.DeleteHistory) }) }) } func initRestServer(r *chi.Mux) { - // Serve on port 8080 + // Serve on port 8082 if no port found port := os.Getenv("PORT") if port == "" { - port = "8080" + port = "8082" } // Start the server diff --git a/apps/history-service/models/models.go b/apps/history-service/models/models.go index 36102ee34b..9928b8809b 100644 --- a/apps/history-service/models/models.go +++ b/apps/history-service/models/models.go @@ -17,5 +17,4 @@ type CollaborationHistory struct { // Special DB fields CreatedAt time.Time `json:"createdAt" firestore:"createdAt"` UpdatedAt time.Time `json:"updatedAt" firestore:"updatedAt"` - DocRefID string `json:"docRefId" firestore:"docRefId"` } From 1fc5c9f9429ac69f004f690109319152df8b504e Mon Sep 17 00:00:00 2001 From: bensohh Date: Tue, 29 Oct 2024 11:05:02 +0800 Subject: [PATCH 084/258] Fix commented providerRef error --- .../src/app/collaboration/[id]/page.tsx | 57 ++++---- .../CollaborativeEditor.tsx | 133 +++++++++--------- 2 files changed, 103 insertions(+), 87 deletions(-) diff --git a/apps/frontend/src/app/collaboration/[id]/page.tsx b/apps/frontend/src/app/collaboration/[id]/page.tsx index 8c77ea6fc0..33fd1c61d5 100644 --- a/apps/frontend/src/app/collaboration/[id]/page.tsx +++ b/apps/frontend/src/app/collaboration/[id]/page.tsx @@ -40,7 +40,7 @@ interface CollaborationProps {} export default function CollaborationPage(props: CollaborationProps) { const router = useRouter(); -// const providerRef = useRef(null); + const providerRef = useRef(null); const editorRef = useRef(null); @@ -54,7 +54,9 @@ export default function CollaborationPage(props: CollaborationProps) { const [questionTitle, setQuestionTitle] = useState( undefined ); - const [questionDocRefId, setQuestionDocRefId] = useState(undefined); + const [questionDocRefId, setQuestionDocRefId] = useState( + undefined + ); const [complexity, setComplexity] = useState(undefined); const [categories, setCategories] = useState([]); // Store the selected filter categories const [description, setDescription] = useState(undefined); @@ -71,7 +73,9 @@ export default function CollaborationPage(props: CollaborationProps) { return storedTime ? parseInt(storedTime) : 0; }); // State for count-up timer (TODO: currently using localstorage to store time, change to db stored time in the future) const stopwatchRef = useRef(null); - const [matchedTopics, setMatchedTopics] = useState(undefined); + const [matchedTopics, setMatchedTopics] = useState( + undefined + ); // Chat states const [messageToSend, setMessageToSend] = useState( @@ -142,31 +146,34 @@ export default function CollaborationPage(props: CollaborationProps) { throw new Error("Provider not initialized"); } providerRef.current.awareness.setLocalStateField("codeSavedStatus", true); - } + }; const handleSubmitCode = async () => { if (!collaborationId) { throw new Error("Collaboration ID not found"); } - const data = await CreateOrUpdateHistory({ - title: questionTitle ?? "", - code: code, - language: selectedLanguage, - user: currentUser ?? "", - matchedUser: matchedUser ?? "", - matchId: collaborationId ?? "", - matchedTopics: matchedTopics ?? [], - questionDocRefId: questionDocRefId ?? "", - questionDifficulty: complexity ?? "", - questionTopics: categories, - }, collaborationId); + const data = await CreateOrUpdateHistory( + { + title: questionTitle ?? "", + code: code, + language: selectedLanguage, + user: currentUser ?? "", + matchedUser: matchedUser ?? "", + matchId: collaborationId ?? "", + matchedTopics: matchedTopics ?? [], + questionDocRefId: questionDocRefId ?? "", + questionDifficulty: complexity ?? "", + questionTopics: categories, + }, + collaborationId + ); successMessage("Code saved successfully!"); sendCodeSavedStatusToMatchedUser(); - } + }; const handleCodeChange = (code: string) => { setCode(code); - } + }; // Fetch the question on initialisation useEffect(() => { @@ -175,11 +182,13 @@ export default function CollaborationPage(props: CollaborationProps) { } // Retrieve details from localstorage - const questionDocRefId: string = localStorage.getItem("questionDocRefId") ?? ""; + const questionDocRefId: string = + localStorage.getItem("questionDocRefId") ?? ""; const collabId: string = localStorage.getItem("collabId") ?? ""; const matchedUser: string = localStorage.getItem("matchedUser") ?? ""; const currentUser: string = localStorage.getItem("user") ?? ""; - const matchedTopics: string[] = localStorage.getItem("matchedTopics")?.split(",") ?? []; + const matchedTopics: string[] = + localStorage.getItem("matchedTopics")?.split(",") ?? []; // Set states from localstorage setCollaborationId(collabId); @@ -377,10 +386,10 @@ export default function CollaborationPage(props: CollaborationProps) { Code
{/* TODO: Link to execution service for code submission */} - diff --git a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx index 7e058f74e4..1f8eafeb42 100644 --- a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx +++ b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx @@ -32,7 +32,7 @@ interface CollaborativeEditorProps { language: string; setMatchedUser: Dispatch>; handleCloseCollaboration: (type: string) => void; -// providerRef: MutableRefObject; + // providerRef: MutableRefObject; matchedUser: string; onCodeChange: (code: string) => void; } @@ -84,57 +84,57 @@ const CollaborativeEditor = forwardRef( const languageConf = new Compartment(); // Referenced: https://codemirror.net/examples/config/#dynamic-configuration - const autoLanguage = EditorState.transactionExtender.of((tr) => { - if (!tr.docChanged) return null; - - const snippet = tr.newDoc.sliceString(0, 100); - - // Handle code change - props.onCodeChange(tr.newDoc.toString()); - - // Test for various language - const docIsPython = /^\s*(def|class)\s/.test(snippet); - const docIsJava = /^\s*(class|public\s+static\s+void\s+main)\s/.test( - snippet - ); // Java has some problems - const docIsCpp = /^\s*(#include|namespace|int\s+main)\s/.test(snippet); // Yet to test c++ - const docIsGo = /^(package|import|func|type|var|const)\s/.test(snippet); - - let newLanguage; - let languageType; - let languageLabel; - - if (docIsPython) { - newLanguage = python(); - languageLabel = "Python"; - languageType = pythonLanguage; - } else if (docIsJava) { - newLanguage = java(); - languageLabel = "Java"; - languageType = javaLanguage; - } else if (docIsGo) { - newLanguage = go(); - languageLabel = "Go"; - languageType = goLanguage; - } else if (docIsCpp) { - newLanguage = cpp(); - languageLabel = "C++"; - languageType = cppLanguage; - } else { - newLanguage = javascript(); // Default to JavaScript - languageLabel = "JavaScript"; - languageType = javascriptLanguage; - } - - const stateLanguage = tr.startState.facet(language); - if (languageType == stateLanguage) return null; - - setSelectedLanguage(languageLabel); - - return { - effects: languageConf.reconfigure(newLanguage), - }; - }); + const autoLanguage = EditorState.transactionExtender.of((tr) => { + if (!tr.docChanged) return null; + + const snippet = tr.newDoc.sliceString(0, 100); + + // Handle code change + props.onCodeChange(tr.newDoc.toString()); + + // Test for various language + const docIsPython = /^\s*(def|class)\s/.test(snippet); + const docIsJava = /^\s*(class|public\s+static\s+void\s+main)\s/.test( + snippet + ); // Java has some problems + const docIsCpp = /^\s*(#include|namespace|int\s+main)\s/.test(snippet); // Yet to test c++ + const docIsGo = /^(package|import|func|type|var|const)\s/.test(snippet); + + let newLanguage; + let languageType; + let languageLabel; + + if (docIsPython) { + newLanguage = python(); + languageLabel = "Python"; + languageType = pythonLanguage; + } else if (docIsJava) { + newLanguage = java(); + languageLabel = "Java"; + languageType = javaLanguage; + } else if (docIsGo) { + newLanguage = go(); + languageLabel = "Go"; + languageType = goLanguage; + } else if (docIsCpp) { + newLanguage = cpp(); + languageLabel = "C++"; + languageType = cppLanguage; + } else { + newLanguage = javascript(); // Default to JavaScript + languageLabel = "JavaScript"; + languageType = javascriptLanguage; + } + + const stateLanguage = tr.startState.facet(language); + if (languageType == stateLanguage) return null; + + setSelectedLanguage(languageLabel); + + return { + effects: languageConf.reconfigure(newLanguage), + }; + }); const [messageApi, contextHolder] = message.useMessage(); @@ -235,20 +235,27 @@ const CollaborativeEditor = forwardRef( } } }); - + // Listener for awareness updates to receive status changes from peers - provider.awareness.on("update", ({ added, updated } : AwarenessUpdate) => { - added.concat(updated).filter(clientId => clientId !== provider.awareness.clientID).forEach((clientID) => { - const state = provider.awareness.getStates().get(clientID) as Awareness; - if (state && state.codeSavedStatus) { - // Display the received status message - messageApi.open({ - type: "success", - content: `${props.matchedUser ?? "Peer"} saved code successfully!`, + provider.awareness.on("update", ({ added, updated }: AwarenessUpdate) => { + added + .concat(updated) + .filter((clientId) => clientId !== provider.awareness.clientID) + .forEach((clientID) => { + const state = provider.awareness + .getStates() + .get(clientID) as Awareness; + if (state && state.codeSavedStatus) { + // Display the received status message + messageApi.open({ + type: "success", + content: `${ + props.matchedUser ?? "Peer" + } saved code successfully!`, + }); + } }); - } }); - }); const state = EditorState.create({ doc: ytext.toString(), From 09708e1435935d6a226a074ce0906d2809ad5052 Mon Sep 17 00:00:00 2001 From: bensohh Date: Tue, 29 Oct 2024 14:50:52 +0800 Subject: [PATCH 085/258] Add dockerfile and remove immediate redirect upon closing collab editor --- apps/signalling-service/Dockerfile | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 apps/signalling-service/Dockerfile diff --git a/apps/signalling-service/Dockerfile b/apps/signalling-service/Dockerfile new file mode 100644 index 0000000000..6189b2fde6 --- /dev/null +++ b/apps/signalling-service/Dockerfile @@ -0,0 +1,21 @@ +FROM node:18-alpine AS base + +# Install dependencies only when needed +FROM base AS deps +# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. +RUN apk add --no-cache libc6-compat +WORKDIR /app + +COPY package*.json pnpm-lock.yaml* ./ +RUN \ + if [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \ + else echo "Lockfile not found." && exit 1; \ + fi + +COPY . . + +# Expose port 3001 so it can be mapped by Docker daemon. +EXPOSE 4444 + +# Define the command to run your app using CMD which defines your runtime. +CMD [ "node", "server.js" ] \ No newline at end of file From b70f478925eac9d3f831e697b35aa6cccae61071 Mon Sep 17 00:00:00 2001 From: bensohh Date: Tue, 29 Oct 2024 15:50:13 +0800 Subject: [PATCH 086/258] Update docker-compose.yml to include signalling server --- apps/docker-compose.yml | 15 +++++++++++++++ apps/frontend/src/app/collaboration/[id]/page.tsx | 3 --- apps/signalling-service/README.md | 12 +++++++++++- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/apps/docker-compose.yml b/apps/docker-compose.yml index 0a0ef34fdf..6152c29757 100644 --- a/apps/docker-compose.yml +++ b/apps/docker-compose.yml @@ -11,6 +11,8 @@ services: - ./frontend/.env volumes: - ./frontend:/frontend + depends_on: + - signalling-service user-service: build: @@ -66,6 +68,19 @@ services: - apps_network volumes: - ./history-service:/history-service + + signalling-service: + build: + context: ./signalling-service + dockerfile: Dockerfile + ports: + - 4444:4444 + env_file: + - ./signalling-service/.env + networks: + - apps_network + volumes: + - ./signalling-service:/signalling-service redis: image: redis:latest diff --git a/apps/frontend/src/app/collaboration/[id]/page.tsx b/apps/frontend/src/app/collaboration/[id]/page.tsx index 33fd1c61d5..62b3e9398d 100644 --- a/apps/frontend/src/app/collaboration/[id]/page.tsx +++ b/apps/frontend/src/app/collaboration/[id]/page.tsx @@ -269,9 +269,6 @@ export default function CollaborationPage(props: CollaborationProps) { localStorage.removeItem("collabId"); localStorage.removeItem("questionDocRefId"); localStorage.removeItem("matchedTopics"); - - // Redirect back to matching page - router.push("/matching"); }; return ( diff --git a/apps/signalling-service/README.md b/apps/signalling-service/README.md index f51e5e76b8..c49ca99356 100644 --- a/apps/signalling-service/README.md +++ b/apps/signalling-service/README.md @@ -25,4 +25,14 @@ First, run the development server: pnpm dev ``` -## Build Dockerfile (TODO) +## Build Dockerfile + +```bash +docker build -t signalling-service -f Dockerfile . +``` + +## Run Docker Container + +```bash +docker run -p 4444:4444 --env-file .env -d signalling-service +``` From 5fdbaa8c656ac72bf4c2aeec6817710492d251c4 Mon Sep 17 00:00:00 2001 From: bensohh Date: Tue, 29 Oct 2024 16:30:32 +0800 Subject: [PATCH 087/258] Replace providerRef with outer ref reference and update test.yml --- .github/workflows/test.yml | 14 +++++++++++++- apps/frontend/src/app/collaboration/[id]/page.tsx | 2 +- .../CollaborativeEditor/CollaborativeEditor.tsx | 14 +++++++------- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2a73652149..82bd2743a4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,6 +30,7 @@ jobs: USER_SERVICE_URL: ${{ vars.USER_SERVICE_URL }} MATCHING_SERVICE_URL: ${{ vars.MATCHING_SERVICE_URL }} HISTORY_SERVICE_URL: ${{ vars.HISTORY_SERVICE_URL }} + SIGNALLING_SERVICE_URL: ${{ vars.SIGNALLING_SERVICE_URL }} JWT_SECRET: ${{ secrets.JWT_SECRET }} QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} HISTORY_FIREBASE_CREDENTIAL_PATH: ${{ vars.HISTORY_SERVICE_FIREBASE_CREDENTIAL_PATH }} @@ -37,6 +38,7 @@ jobs: USER_SERVICE_PORT: ${{ vars.USER_SERVICE_PORT }} MATCHING_SERVICE_PORT: ${{ vars.MATCHING_SERVICE_PORT }} HISTORY_SERVICE_PORT: ${{ vars.HISTORY_SERVICE_PORT }} + SIGNALLING_SERVICE_PORT: ${{ vars.SIGNALLING_SERVICE_PORT }} MATCHING_SERVICE_TIMEOUT: ${{ vars.MATCHING_SERVICE_TIMEOUT }} REDIS_URL: ${{ vars.REDIS_URL }} QUESTION_SERVICE_GRPC_URL: ${{ vars.QUESTION_SERVICE_GPRC_URL }} @@ -46,6 +48,7 @@ jobs: echo "NEXT_PUBLIC_USER_SERVICE_URL=$USER_SERVICE_URL" >> .env echo "NEXT_PUBLIC_MATCHING_SERVICE_URL=$MATCHING_SERVICE_URL" >> .env echo "NEXT_PUBLIC_HISTORY_SERVICE_URL=$HISTORY_SERVICE_URL" >> .env + echo "NEXT_PUBLIC_SIGNALLING_SERVICE_URL=$SIGNALLING_SERVICE_URL" >> .env cd ../question-service echo "FIREBASE_CREDENTIAL_PATH=$QUESTION_FIREBASE_CREDENTIAL_PATH" >> .env @@ -67,6 +70,9 @@ jobs: echo "FIREBASE_CREDENTIAL_PATH=$HISTORY_FIREBASE_CREDENTIAL_PATH" >> .env echo "PORT=$HISTORY_SERVICE_PORT" >> .env + cd ../signalling-service + echo "PORT=$SIGNALLING_SERVICE_PORT" >> .env + - name: Create Database Credential Files env: QUESTION_FIREBASE_JSON: ${{ secrets.QUESTION_SERVICE_FIREBASE_CREDENTIAL }} @@ -101,6 +107,7 @@ jobs: QUESTION_SERVICE_URL: ${{ vars.QUESTION_SERVICE_URL }} MATCHING_SERVICE_URL: ${{ vars.MATCHING_SERVICE_URL }} HISTORY_SERVICE_URL: ${{ vars.HISTORY_SERVICE_URL }} + SIGNALLING_SERVICE_URL: ${{ vars.SIGNALLING_SERVICE_URL }} run: | echo "Testing Question Service..." curl -sSL -o /dev/null $QUESTION_SERVICE_URL && echo "Question Service is up" @@ -117,5 +124,10 @@ jobs: echo "WebSocket for Matching Service is live" fi # Add in test for matching service in the future - + echo "Testing Signalling Service..." + if ! (echo "Hello" | websocat $SIGNALLING_SERVICE_URL); then + echo "WebSocket for Signalling Service is not live" + else + echo "WebSocket for Signalling Service is live" + fi # We can add more tests here diff --git a/apps/frontend/src/app/collaboration/[id]/page.tsx b/apps/frontend/src/app/collaboration/[id]/page.tsx index 62b3e9398d..41c56023f0 100644 --- a/apps/frontend/src/app/collaboration/[id]/page.tsx +++ b/apps/frontend/src/app/collaboration/[id]/page.tsx @@ -399,7 +399,7 @@ export default function CollaborationPage(props: CollaborationProps) { language={selectedLanguage} setMatchedUser={setMatchedUser} handleCloseCollaboration={handleCloseCollaboration} - // providerRef={providerRef} + providerRef={providerRef} matchedUser={matchedUser} onCodeChange={handleCodeChange} /> diff --git a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx index 1f8eafeb42..857e149be1 100644 --- a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx +++ b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx @@ -32,7 +32,7 @@ interface CollaborativeEditorProps { language: string; setMatchedUser: Dispatch>; handleCloseCollaboration: (type: string) => void; - // providerRef: MutableRefObject; + providerRef: MutableRefObject; matchedUser: string; onCodeChange: (code: string) => void; } @@ -77,7 +77,7 @@ const CollaborativeEditor = forwardRef( ref: ForwardedRef ) => { const editorRef = useRef(null); - const providerRef = useRef(null); + // const providerRef = useRef(null); const [selectedLanguage, setSelectedLanguage] = useState("JavaScript"); let sessionEndNotified = false; @@ -168,9 +168,9 @@ const CollaborativeEditor = forwardRef( useImperativeHandle(ref, () => ({ endSession: () => { - if (providerRef.current) { + if (props.providerRef.current) { // Set awareness state to indicate session ended to notify peer about session ending - providerRef.current.awareness.setLocalStateField( + props.providerRef.current.awareness.setLocalStateField( "sessionEnded", true ); @@ -191,7 +191,7 @@ const CollaborativeEditor = forwardRef( maxConns: 2, }); - providerRef.current = provider; + props.providerRef.current = provider; const ytext = ydoc.getText("codemirror"); const undoManager = new Y.UndoManager(ytext); @@ -222,8 +222,8 @@ const CollaborativeEditor = forwardRef( props.handleCloseCollaboration("peer"); sessionEndNotified = true; - if (providerRef.current) { - providerRef.current.disconnect(); + if (props.providerRef.current) { + props.providerRef.current.disconnect(); } return; } From 6f8952f97cc5f404baac95f30e7b9d15048e3828 Mon Sep 17 00:00:00 2001 From: solomonng2001 Date: Tue, 29 Oct 2024 18:35:20 +0800 Subject: [PATCH 088/258] Fix code saved message appearing on end session --- .../src/components/CollaborativeEditor/CollaborativeEditor.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx index 857e149be1..5fa8a88fe5 100644 --- a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx +++ b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx @@ -48,6 +48,7 @@ interface AwarenessUpdate { } interface Awareness { + sessionEnded: boolean; user: { name: string; color: string; @@ -245,7 +246,7 @@ const CollaborativeEditor = forwardRef( const state = provider.awareness .getStates() .get(clientID) as Awareness; - if (state && state.codeSavedStatus) { + if (state && state.codeSavedStatus && !state.sessionEnded) { // Display the received status message messageApi.open({ type: "success", From af687280a38e1980197be30b01f37ad85d352869 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Wed, 30 Oct 2024 13:43:54 +0800 Subject: [PATCH 089/258] merge --- .github/workflows/test.yml | 42 +- apps/README.md | 2 +- apps/docker-compose.yml | 29 + apps/frontend/.env.example | 4 +- apps/frontend/package.json | 14 +- apps/frontend/pnpm-lock.yaml | 824 +++++++++++++----- apps/frontend/src/app/layout.tsx | 4 +- .../src/app/matching/MatchingModal.tsx | 27 +- .../modalContent/MatchFoundContent.tsx | 4 +- apps/frontend/src/app/page.tsx | 10 +- apps/frontend/src/app/question/[id]/page.tsx | 72 +- apps/frontend/src/app/question/page.tsx | 2 +- .../frontend/src/app/services/use-matching.ts | 43 +- .../src/contexts/websocketcontext.tsx | 9 +- apps/frontend/src/utils/SelectOptions.ts | 4 + apps/matching-service/.env.example | 6 +- apps/matching-service/README.md | 25 +- apps/matching-service/go.mod | 9 +- apps/matching-service/go.sum | 20 +- apps/matching-service/handlers/websocket.go | 173 ++-- apps/matching-service/main.go | 26 +- apps/matching-service/models/complexity.go | 67 -- apps/matching-service/models/match.go | 24 +- apps/matching-service/processes/constants.go | 17 - apps/matching-service/processes/match.go | 107 --- apps/matching-service/processes/queue.go | 247 ------ apps/matching-service/processes/read.go | 22 - apps/matching-service/processes/redis.go | 35 - .../tests/websocket-test.html | 556 ++++++++++-- apps/matching-service/utils/timeout.go | 11 + apps/question-service/Dockerfile | 2 +- apps/question-service/README.md | 2 +- apps/question-service/go.mod | 4 +- apps/question-service/go.sum | 8 +- apps/question-service/handlers/list.go | 3 +- apps/question-service/handlers/types.go | 7 - apps/question-service/main.go | 74 +- 37 files changed, 1464 insertions(+), 1071 deletions(-) delete mode 100644 apps/matching-service/models/complexity.go delete mode 100644 apps/matching-service/processes/constants.go delete mode 100644 apps/matching-service/processes/match.go delete mode 100644 apps/matching-service/processes/queue.go delete mode 100644 apps/matching-service/processes/read.go delete mode 100644 apps/matching-service/processes/redis.go delete mode 100644 apps/question-service/handlers/types.go diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0d2a1ad306..82bd2743a4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,21 +29,29 @@ jobs: QUESTION_SERVICE_URL: ${{ vars.QUESTION_SERVICE_URL }} USER_SERVICE_URL: ${{ vars.USER_SERVICE_URL }} MATCHING_SERVICE_URL: ${{ vars.MATCHING_SERVICE_URL }} + HISTORY_SERVICE_URL: ${{ vars.HISTORY_SERVICE_URL }} + SIGNALLING_SERVICE_URL: ${{ vars.SIGNALLING_SERVICE_URL }} JWT_SECRET: ${{ secrets.JWT_SECRET }} - FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} + QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} + HISTORY_FIREBASE_CREDENTIAL_PATH: ${{ vars.HISTORY_SERVICE_FIREBASE_CREDENTIAL_PATH }} DB_CLOUD_URI: ${{ secrets.USER_SERVICE_DB_CLOUD_URI }} USER_SERVICE_PORT: ${{ vars.USER_SERVICE_PORT }} MATCHING_SERVICE_PORT: ${{ vars.MATCHING_SERVICE_PORT }} + HISTORY_SERVICE_PORT: ${{ vars.HISTORY_SERVICE_PORT }} + SIGNALLING_SERVICE_PORT: ${{ vars.SIGNALLING_SERVICE_PORT }} MATCHING_SERVICE_TIMEOUT: ${{ vars.MATCHING_SERVICE_TIMEOUT }} REDIS_URL: ${{ vars.REDIS_URL }} + QUESTION_SERVICE_GRPC_URL: ${{ vars.QUESTION_SERVICE_GPRC_URL }} run: | cd ./apps/frontend echo "NEXT_PUBLIC_QUESTION_SERVICE_URL=$QUESTION_SERVICE_URL" >> .env echo "NEXT_PUBLIC_USER_SERVICE_URL=$USER_SERVICE_URL" >> .env echo "NEXT_PUBLIC_MATCHING_SERVICE_URL=$MATCHING_SERVICE_URL" >> .env + echo "NEXT_PUBLIC_HISTORY_SERVICE_URL=$HISTORY_SERVICE_URL" >> .env + echo "NEXT_PUBLIC_SIGNALLING_SERVICE_URL=$SIGNALLING_SERVICE_URL" >> .env cd ../question-service - echo "FIREBASE_CREDENTIAL_PATH=$FIREBASE_CREDENTIAL_PATH" >> .env + echo "FIREBASE_CREDENTIAL_PATH=$QUESTION_FIREBASE_CREDENTIAL_PATH" >> .env echo "JWT_SECRET=$JWT_SECRET" >> .env cd ../user-service @@ -56,14 +64,27 @@ jobs: echo "MATCH_TIMEOUT=$MATCHING_SERVICE_TIMEOUT" >> .env echo "JWT_SECRET=$JWT_SECRET" >> .env echo "REDIS_URL=$REDIS_URL" >> .env + echo "QUESTION_SERVICE_GRPC_URL=$QUESTION_SERVICE_GRPC_URL" >> .env + + cd ../history-service + echo "FIREBASE_CREDENTIAL_PATH=$HISTORY_FIREBASE_CREDENTIAL_PATH" >> .env + echo "PORT=$HISTORY_SERVICE_PORT" >> .env + + cd ../signalling-service + echo "PORT=$SIGNALLING_SERVICE_PORT" >> .env - name: Create Database Credential Files env: - FIREBASE_JSON: ${{ secrets.QUESTION_SERVICE_FIREBASE_CREDENTIAL }} - FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} + QUESTION_FIREBASE_JSON: ${{ secrets.QUESTION_SERVICE_FIREBASE_CREDENTIAL }} + QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} + HISTORY_FIREBASE_JSON: ${{ secrets.HISTORY_SERVICE_FIREBASE_CREDENTIAL }} + HISTORY_FIREBASE_CREDENTIAL_PATH: ${{ vars.HISTORY_SERVICE_FIREBASE_CREDENTIAL_PATH }} run: | cd ./apps/question-service - echo "$FIREBASE_JSON" > "./$FIREBASE_CREDENTIAL_PATH" + echo "$QUESTION_FIREBASE_JSON" > "./$QUESTION_FIREBASE_CREDENTIAL_PATH" + + cd ../history-service + echo "$HISTORY_FIREBASE_JSON" > "./$HISTORY_FIREBASE_CREDENTIAL_PATH" - name: Build and Run Services run: | @@ -85,6 +106,8 @@ jobs: USER_SERVICE_URL: ${{ vars.USER_SERVICE_URL }} QUESTION_SERVICE_URL: ${{ vars.QUESTION_SERVICE_URL }} MATCHING_SERVICE_URL: ${{ vars.MATCHING_SERVICE_URL }} + HISTORY_SERVICE_URL: ${{ vars.HISTORY_SERVICE_URL }} + SIGNALLING_SERVICE_URL: ${{ vars.SIGNALLING_SERVICE_URL }} run: | echo "Testing Question Service..." curl -sSL -o /dev/null $QUESTION_SERVICE_URL && echo "Question Service is up" @@ -92,6 +115,8 @@ jobs: curl -fsSL -o /dev/null $USER_SERVICE_URL && echo "User Service is up" echo "Testing Frontend..." curl -fsSL -o /dev/null $FRONTEND_URL && echo "Frontend is up" + echo "Testing History Service..." + curl -fsSL -o /dev/null $HISTORY_SERVICE_URL && echo "History Service is up" echo "Testing Matching Service..." if ! (echo "Hello" | websocat $MATCHING_SERVICE_URL); then echo "WebSocket for Matching Service is not live" @@ -99,5 +124,10 @@ jobs: echo "WebSocket for Matching Service is live" fi # Add in test for matching service in the future - + echo "Testing Signalling Service..." + if ! (echo "Hello" | websocat $SIGNALLING_SERVICE_URL); then + echo "WebSocket for Signalling Service is not live" + else + echo "WebSocket for Signalling Service is live" + fi # We can add more tests here diff --git a/apps/README.md b/apps/README.md index 18525dd4f6..ae12a36fc1 100644 --- a/apps/README.md +++ b/apps/README.md @@ -56,7 +56,7 @@ Once running, you can access: - The **frontend** at http://localhost:3000 - The **user service** at http://localhost:3001 -- The **question service** at http://localhost:8080 +- The **question service** at http://localhost:8080 (REST) and http://localhost:50051 (gRPC) - The **matching service** at http://localhost:8081 - The **redis service** at http://localhost:6379 diff --git a/apps/docker-compose.yml b/apps/docker-compose.yml index e69e2bcc65..6152c29757 100644 --- a/apps/docker-compose.yml +++ b/apps/docker-compose.yml @@ -11,6 +11,8 @@ services: - ./frontend/.env volumes: - ./frontend:/frontend + depends_on: + - signalling-service user-service: build: @@ -31,6 +33,7 @@ services: dockerfile: Dockerfile ports: - 8080:8080 + - 50051:50051 env_file: - ./question-service/.env networks: @@ -53,6 +56,32 @@ services: depends_on: - redis + history-service: + build: + context: ./history-service + dockerfile: Dockerfile + ports: + - 8082:8082 + env_file: + - ./history-service/.env + networks: + - apps_network + volumes: + - ./history-service:/history-service + + signalling-service: + build: + context: ./signalling-service + dockerfile: Dockerfile + ports: + - 4444:4444 + env_file: + - ./signalling-service/.env + networks: + - apps_network + volumes: + - ./signalling-service:/signalling-service + redis: image: redis:latest networks: diff --git a/apps/frontend/.env.example b/apps/frontend/.env.example index 547a68c4c0..6482575b4e 100644 --- a/apps/frontend/.env.example +++ b/apps/frontend/.env.example @@ -1,4 +1,6 @@ # URL endpoints of the services NEXT_PUBLIC_QUESTION_SERVICE_URL="http://localhost:8080/" NEXT_PUBLIC_USER_SERVICE_URL="http://localhost:3001/" -NEXT_PUBLIC_MATCHING_SERVICE_URL="ws://localhost:8081/match" \ No newline at end of file +NEXT_PUBLIC_MATCHING_SERVICE_URL="ws://localhost:8081/match" +NEXT_PUBLIC_SIGNALLING_SERVICE_URL="ws://localhost:4444/" +NEXT_PUBLIC_HISTORY_SERVICE_URL="http://localhost:8082/" \ No newline at end of file diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 97d014fb96..94cc9de16b 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -9,17 +9,27 @@ "lint": "next lint" }, "dependencies": { - "@ant-design/cssinjs": "^1.21.1", "@ant-design/icons": "^5.5.1", "@ant-design/nextjs-registry": "^1.0.1", + "@codemirror/lang-cpp": "^6.0.2", + "@codemirror/lang-go": "^6.0.1", + "@codemirror/lang-java": "^6.0.1", + "@codemirror/lang-javascript": "^6.2.2", + "@codemirror/lang-python": "^6.1.6", + "@codemirror/language": "^6.10.3", + "@codemirror/state": "^6.4.1", "antd": "^5.20.6", + "codemirror": "^6.0.1", "next": "14.2.13", "react": "^18.2.0", "react-dom": "^18.2.0", "react-timer-hook": "^3.0.7", "react-use-websocket": "^4.9.0", "sass": "^1.79.2", - "typeface-montserrat": "^1.1.13" + "typeface-montserrat": "^1.1.13", + "y-codemirror.next": "^0.3.5", + "y-webrtc": "^10.3.0", + "yjs": "^13.6.20" }, "devDependencies": { "@types/node": "^20", diff --git a/apps/frontend/pnpm-lock.yaml b/apps/frontend/pnpm-lock.yaml index 7e165fe896..c114790857 100644 --- a/apps/frontend/pnpm-lock.yaml +++ b/apps/frontend/pnpm-lock.yaml @@ -8,21 +8,42 @@ importers: .: dependencies: - '@ant-design/cssinjs': - specifier: ^1.21.1 - version: 1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@ant-design/icons': specifier: ^5.5.1 - version: 5.5.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 5.5.1(react-dom@18.2.0)(react@18.2.0) '@ant-design/nextjs-registry': specifier: ^1.0.1 - version: 1.0.1(@ant-design/cssinjs@1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(antd@5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(next@14.2.13(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 1.0.1(@ant-design/cssinjs@1.21.1)(antd@5.20.6)(next@14.2.13)(react-dom@18.2.0)(react@18.2.0) + '@codemirror/lang-cpp': + specifier: ^6.0.2 + version: 6.0.2 + '@codemirror/lang-go': + specifier: ^6.0.1 + version: 6.0.1(@codemirror/view@6.34.1) + '@codemirror/lang-java': + specifier: ^6.0.1 + version: 6.0.1 + '@codemirror/lang-javascript': + specifier: ^6.2.2 + version: 6.2.2 + '@codemirror/lang-python': + specifier: ^6.1.6 + version: 6.1.6(@codemirror/view@6.34.1) + '@codemirror/language': + specifier: ^6.10.3 + version: 6.10.3 + '@codemirror/state': + specifier: ^6.4.1 + version: 6.4.1 antd: specifier: ^5.20.6 - version: 5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 5.20.6(react-dom@18.2.0)(react@18.2.0) + codemirror: + specifier: ^6.0.1 + version: 6.0.1(@lezer/common@1.2.3) next: specifier: 14.2.13 - version: 14.2.13(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2) + version: 14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2) react: specifier: ^18.2.0 version: 18.2.0 @@ -41,6 +62,15 @@ importers: typeface-montserrat: specifier: ^1.1.13 version: 1.1.13 + y-codemirror.next: + specifier: ^0.3.5 + version: 0.3.5(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(yjs@13.6.20) + y-webrtc: + specifier: ^10.3.0 + version: 10.3.0(yjs@13.6.20) + yjs: + specifier: ^13.6.20 + version: 13.6.20 devDependencies: '@types/node': specifier: ^20 @@ -110,6 +140,47 @@ packages: resolution: {integrity: sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==} engines: {node: '>=6.9.0'} + '@codemirror/autocomplete@6.18.1': + resolution: {integrity: sha512-iWHdj/B1ethnHRTwZj+C1obmmuCzquH29EbcKr0qIjA9NfDeBDJ7vs+WOHsFeLeflE4o+dHfYndJloMKHUkWUA==} + peerDependencies: + '@codemirror/language': ^6.0.0 + '@codemirror/state': ^6.0.0 + '@codemirror/view': ^6.0.0 + '@lezer/common': ^1.0.0 + + '@codemirror/commands@6.7.1': + resolution: {integrity: sha512-llTrboQYw5H4THfhN4U3qCnSZ1SOJ60ohhz+SzU0ADGtwlc533DtklQP0vSFaQuCPDn3BPpOd1GbbnUtwNjsrw==} + + '@codemirror/lang-cpp@6.0.2': + resolution: {integrity: sha512-6oYEYUKHvrnacXxWxYa6t4puTlbN3dgV662BDfSH8+MfjQjVmP697/KYTDOqpxgerkvoNm7q5wlFMBeX8ZMocg==} + + '@codemirror/lang-go@6.0.1': + resolution: {integrity: sha512-7fNvbyNylvqCphW9HD6WFnRpcDjr+KXX/FgqXy5H5ZS0eC5edDljukm/yNgYkwTsgp2busdod50AOTIy6Jikfg==} + + '@codemirror/lang-java@6.0.1': + resolution: {integrity: sha512-OOnmhH67h97jHzCuFaIEspbmsT98fNdhVhmA3zCxW0cn7l8rChDhZtwiwJ/JOKXgfm4J+ELxQihxaI7bj7mJRg==} + + '@codemirror/lang-javascript@6.2.2': + resolution: {integrity: sha512-VGQfY+FCc285AhWuwjYxQyUQcYurWlxdKYT4bqwr3Twnd5wP5WSeu52t4tvvuWmljT4EmgEgZCqSieokhtY8hg==} + + '@codemirror/lang-python@6.1.6': + resolution: {integrity: sha512-ai+01WfZhWqM92UqjnvorkxosZ2aq2u28kHvr+N3gu012XqY2CThD67JPMHnGceRfXPDBmn1HnyqowdpF57bNg==} + + '@codemirror/language@6.10.3': + resolution: {integrity: sha512-kDqEU5sCP55Oabl6E7m5N+vZRoc0iWqgDVhEKifcHzPzjqCegcO4amfrYVL9PmPZpl4G0yjkpTpUO/Ui8CzO8A==} + + '@codemirror/lint@6.8.2': + resolution: {integrity: sha512-PDFG5DjHxSEjOXk9TQYYVjZDqlZTFaDBfhQixHnQOEVDDNHUbEh/hstAjcQJaA6FQdZTD1hquXTK0rVBLADR1g==} + + '@codemirror/search@6.5.6': + resolution: {integrity: sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==} + + '@codemirror/state@6.4.1': + resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==} + + '@codemirror/view@6.34.1': + resolution: {integrity: sha512-t1zK/l9UiRqwUNPm+pdIT0qzJlzuVckbTEMVNFhfWkGiBQClstzg+78vedCvLSX0xJEZ6lwZbPpnljL7L6iwMQ==} + '@ctrl/tinycolor@3.6.1': resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} engines: {node: '>=10'} @@ -147,6 +218,30 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@lezer/common@1.2.3': + resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==} + + '@lezer/cpp@1.1.2': + resolution: {integrity: sha512-macwKtyeUO0EW86r3xWQCzOV9/CF8imJLpJlPv3sDY57cPGeUZ8gXWOWNlJr52TVByMV3PayFQCA5SHEERDmVQ==} + + '@lezer/go@1.0.0': + resolution: {integrity: sha512-co9JfT3QqX1YkrMmourYw2Z8meGC50Ko4d54QEcQbEYpvdUvN4yb0NBZdn/9ertgvjsySxHsKzH3lbm3vqJ4Jw==} + + '@lezer/highlight@1.2.1': + resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==} + + '@lezer/java@1.1.3': + resolution: {integrity: sha512-yHquUfujwg6Yu4Fd1GNHCvidIvJwi/1Xu2DaKl/pfWIA2c1oXkVvawH3NyXhCaFx4OdlYBVX5wvz2f7Aoa/4Xw==} + + '@lezer/javascript@1.4.19': + resolution: {integrity: sha512-j44kbR1QL26l6dMunZ1uhKBFteVGLVCBGNUD2sUaMnic+rbTviVuoK0CD1l9FTW31EueWvFFswCKMH7Z+M3JRA==} + + '@lezer/lr@1.4.2': + resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==} + + '@lezer/python@1.1.14': + resolution: {integrity: sha512-ykDOb2Ti24n76PJsSa4ZoDF0zH12BSw1LGfQXCYJhJyOGiFTfGaX0Du66Ze72R+u/P35U+O6I9m8TFXov1JzsA==} + '@next/env@14.2.13': resolution: {integrity: sha512-s3lh6K8cbW1h5Nga7NNeXrbe0+2jIIYK9YaA9T7IufDWnZpozdFUp6Hf0d5rNWUKu4fEuSX2rCKlGjCrtylfDw==} @@ -464,6 +559,9 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -474,6 +572,9 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} @@ -503,6 +604,9 @@ packages: client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + codemirror@6.0.1: + resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -519,6 +623,9 @@ packages: copy-to-clipboard@3.3.3: resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + crelt@1.0.6: + resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -601,6 +708,9 @@ packages: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} + err-code@3.0.1: + resolution: {integrity: sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==} + es-abstract@1.23.3: resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} engines: {node: '>= 0.4'} @@ -810,6 +920,9 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + get-browser-rtc@1.1.0: + resolution: {integrity: sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ==} + get-intrinsic@1.2.4: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} @@ -881,6 +994,9 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@4.0.6: resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} engines: {node: '>= 4'} @@ -1025,6 +1141,9 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isomorphic.js@0.2.5: + resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} + iterator.prototype@1.1.2: resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} @@ -1073,6 +1192,11 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lib0@0.2.98: + resolution: {integrity: sha512-XteTiNO0qEXqqweWx+b21p/fBnNHUA1NwAtJNJek1oPrewEZs2uiT4gWivHKr9GqCjDPAhchz0UQO8NwU3bBNA==} + engines: {node: '>=16'} + hasBin: true + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -1229,6 +1353,9 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + rc-cascader@3.28.1: resolution: {integrity: sha512-9+8oHIMWVLHxuaapDiqFNmD9KSyKN/P4bo9x/MBuDbyTqP8f2/POmmZxdXWBO3yq/uE3pKyQCXYNUxrNfHRv2A==} peerDependencies: @@ -1480,6 +1607,10 @@ packages: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} engines: {node: '>=0.10.0'} + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + readdirp@4.0.1: resolution: {integrity: sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw==} engines: {node: '>= 14.16.0'} @@ -1533,6 +1664,9 @@ packages: resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} engines: {node: '>=0.4'} + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-regex-test@1.0.3: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} @@ -1581,6 +1715,9 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + simple-peer@9.11.1: + resolution: {integrity: sha512-D1SaWpOW8afq1CZGWB8xTfrT3FekjQmPValrqncJMX7QFl8YwhrPTZvMCANLtgBwwdS+7zURyqxDDEmY558tTw==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -1625,6 +1762,9 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -1641,6 +1781,9 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + style-mod@4.1.2: + resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} + styled-jsx@5.1.1: resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} engines: {node: '>= 12.0.0'} @@ -1733,9 +1876,15 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + v8-compile-cache@2.4.0: resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==} + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} @@ -1771,28 +1920,64 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + y-codemirror.next@0.3.5: + resolution: {integrity: sha512-VluNu3e5HfEXybnypnsGwKAj+fKLd4iAnR7JuX1Sfyydmn1jCBS5wwEL/uS04Ch2ib0DnMAOF6ZRR/8kK3wyGw==} + peerDependencies: + '@codemirror/state': ^6.0.0 + '@codemirror/view': ^6.0.0 + yjs: ^13.5.6 + + y-protocols@1.0.6: + resolution: {integrity: sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + peerDependencies: + yjs: ^13.0.0 + + y-webrtc@10.3.0: + resolution: {integrity: sha512-KalJr7dCgUgyVFxoG3CQYbpS0O2qybegD0vI4bYnYHI0MOwoVbucED3RZ5f2o1a5HZb1qEssUKS0H/Upc6p1lA==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + yjs: ^13.6.8 + + yjs@13.6.20: + resolution: {integrity: sha512-Z2YZI+SYqK7XdWlloI3lhMiKnCdFCVC4PchpdO+mCYwtiTwncjUbnRK9R1JmkNfdmHyDXuWN3ibJAt0wsqTbLQ==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + snapshots: '@ant-design/colors@7.1.0': dependencies: '@ctrl/tinycolor': 3.6.1 - '@ant-design/cssinjs-utils@1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@ant-design/cssinjs-utils@1.1.0(react-dom@18.2.0)(react@18.2.0)': dependencies: - '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0)(react@18.2.0) '@babel/runtime': 7.25.7 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@ant-design/cssinjs@1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@ant-design/cssinjs@1.21.1(react-dom@18.2.0)(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 '@emotion/hash': 0.8.0 '@emotion/unitless': 0.7.5 classnames: 2.5.1 csstype: 3.1.3 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) stylis: 4.3.4 @@ -1803,21 +1988,21 @@ snapshots: '@ant-design/icons-svg@4.4.2': {} - '@ant-design/icons@5.5.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@ant-design/icons@5.5.1(react-dom@18.2.0)(react@18.2.0)': dependencies: '@ant-design/colors': 7.1.0 '@ant-design/icons-svg': 4.4.2 '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@ant-design/nextjs-registry@1.0.1(@ant-design/cssinjs@1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(antd@5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(next@14.2.13(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@ant-design/nextjs-registry@1.0.1(@ant-design/cssinjs@1.21.1)(antd@5.20.6)(next@14.2.13)(react-dom@18.2.0)(react@18.2.0)': dependencies: - '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - antd: 5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - next: 14.2.13(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2) + '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0)(react@18.2.0) + antd: 5.20.6(react-dom@18.2.0)(react@18.2.0) + next: 14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -1834,6 +2019,89 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 + '@codemirror/autocomplete@6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3)': + dependencies: + '@codemirror/language': 6.10.3 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + '@lezer/common': 1.2.3 + + '@codemirror/commands@6.7.1': + dependencies: + '@codemirror/language': 6.10.3 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + '@lezer/common': 1.2.3 + + '@codemirror/lang-cpp@6.0.2': + dependencies: + '@codemirror/language': 6.10.3 + '@lezer/cpp': 1.1.2 + + '@codemirror/lang-go@6.0.1(@codemirror/view@6.34.1)': + dependencies: + '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3) + '@codemirror/language': 6.10.3 + '@codemirror/state': 6.4.1 + '@lezer/common': 1.2.3 + '@lezer/go': 1.0.0 + transitivePeerDependencies: + - '@codemirror/view' + + '@codemirror/lang-java@6.0.1': + dependencies: + '@codemirror/language': 6.10.3 + '@lezer/java': 1.1.3 + + '@codemirror/lang-javascript@6.2.2': + dependencies: + '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3) + '@codemirror/language': 6.10.3 + '@codemirror/lint': 6.8.2 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + '@lezer/common': 1.2.3 + '@lezer/javascript': 1.4.19 + + '@codemirror/lang-python@6.1.6(@codemirror/view@6.34.1)': + dependencies: + '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3) + '@codemirror/language': 6.10.3 + '@codemirror/state': 6.4.1 + '@lezer/common': 1.2.3 + '@lezer/python': 1.1.14 + transitivePeerDependencies: + - '@codemirror/view' + + '@codemirror/language@6.10.3': + dependencies: + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + style-mod: 4.1.2 + + '@codemirror/lint@6.8.2': + dependencies: + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + crelt: 1.0.6 + + '@codemirror/search@6.5.6': + dependencies: + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + crelt: 1.0.6 + + '@codemirror/state@6.4.1': {} + + '@codemirror/view@6.34.1': + dependencies: + '@codemirror/state': 6.4.1 + style-mod: 4.1.2 + w3c-keyname: 2.2.8 + '@ctrl/tinycolor@3.6.1': {} '@emotion/hash@0.8.0': {} @@ -1880,6 +2148,46 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@lezer/common@1.2.3': {} + + '@lezer/cpp@1.1.2': + dependencies: + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@lezer/go@1.0.0': + dependencies: + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@lezer/highlight@1.2.1': + dependencies: + '@lezer/common': 1.2.3 + + '@lezer/java@1.1.3': + dependencies: + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@lezer/javascript@1.4.19': + dependencies: + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@lezer/lr@1.4.2': + dependencies: + '@lezer/common': 1.2.3 + + '@lezer/python@1.1.14': + dependencies: + '@lezer/common': 1.2.3 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + '@next/env@14.2.13': {} '@next/eslint-plugin-next@14.2.13': @@ -1934,19 +2242,19 @@ snapshots: dependencies: '@babel/runtime': 7.25.7 - '@rc-component/color-picker@2.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@rc-component/color-picker@2.0.1(react-dom@18.2.0)(react@18.2.0)': dependencies: '@ant-design/fast-color': 2.0.6 '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/context@1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@rc-component/context@1.4.0(react-dom@18.2.0)(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -1954,48 +2262,48 @@ snapshots: dependencies: '@babel/runtime': 7.25.7 - '@rc-component/mutate-observer@1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@rc-component/mutate-observer@1.1.0(react-dom@18.2.0)(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/portal@1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@rc-component/portal@1.1.2(react-dom@18.2.0)(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/qrcode@1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@rc-component/qrcode@1.0.0(react-dom@18.2.0)(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/tour@1.15.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@rc-component/tour@1.15.1(react-dom@18.2.0)(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/trigger@2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@rc-component/trigger@2.2.3(react-dom@18.2.0)(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -2025,7 +2333,7 @@ snapshots: '@types/prop-types': 15.7.13 csstype: 3.1.3 - '@typescript-eslint/eslint-plugin@8.8.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint@8.0.0)(typescript@5.0.2)': + '@typescript-eslint/eslint-plugin@8.8.0(@typescript-eslint/parser@8.8.0)(eslint@8.0.0)(typescript@5.0.2)': dependencies: '@eslint-community/regexpp': 4.11.1 '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) @@ -2038,7 +2346,6 @@ snapshots: ignore: 5.3.2 natural-compare: 1.4.0 ts-api-utils: 1.3.0(typescript@5.0.2) - optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - supports-color @@ -2051,7 +2358,6 @@ snapshots: '@typescript-eslint/visitor-keys': 8.8.0 debug: 4.3.7 eslint: 8.0.0 - optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - supports-color @@ -2067,7 +2373,6 @@ snapshots: '@typescript-eslint/utils': 8.8.0(eslint@8.0.0)(typescript@5.0.2) debug: 4.3.7 ts-api-utils: 1.3.0(typescript@5.0.2) - optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - eslint @@ -2085,7 +2390,6 @@ snapshots: minimatch: 9.0.5 semver: 7.6.3 ts-api-utils: 1.3.0(typescript@5.0.2) - optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - supports-color @@ -2131,55 +2435,55 @@ snapshots: ansi-styles@6.2.1: {} - antd@5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + antd@5.20.6(react-dom@18.2.0)(react@18.2.0): dependencies: '@ant-design/colors': 7.1.0 - '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@ant-design/cssinjs-utils': 1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@ant-design/icons': 5.5.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0)(react@18.2.0) + '@ant-design/cssinjs-utils': 1.1.0(react-dom@18.2.0)(react@18.2.0) + '@ant-design/icons': 5.5.1(react-dom@18.2.0)(react@18.2.0) '@ant-design/react-slick': 1.1.2(react@18.2.0) '@babel/runtime': 7.25.7 '@ctrl/tinycolor': 3.6.1 - '@rc-component/color-picker': 2.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@rc-component/mutate-observer': 1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@rc-component/qrcode': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@rc-component/tour': 1.15.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/color-picker': 2.0.1(react-dom@18.2.0)(react@18.2.0) + '@rc-component/mutate-observer': 1.1.0(react-dom@18.2.0)(react@18.2.0) + '@rc-component/qrcode': 1.0.0(react-dom@18.2.0)(react@18.2.0) + '@rc-component/tour': 1.15.1(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 copy-to-clipboard: 3.3.3 dayjs: 1.11.13 - rc-cascader: 3.28.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-checkbox: 3.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-collapse: 3.7.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-dialog: 9.5.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-drawer: 7.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-dropdown: 4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-field-form: 2.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-image: 7.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-input: 1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-input-number: 9.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-mentions: 2.15.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-menu: 9.14.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-notification: 5.6.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-pagination: 4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-picker: 4.6.15(dayjs@1.11.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-progress: 4.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-rate: 2.13.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-segmented: 2.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-select: 14.15.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-slider: 11.1.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-steps: 6.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-switch: 4.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-table: 7.45.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-tabs: 15.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-textarea: 1.8.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-tooltip: 6.2.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-tree: 5.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-tree-select: 5.23.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-upload: 4.7.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-cascader: 3.28.1(react-dom@18.2.0)(react@18.2.0) + rc-checkbox: 3.3.0(react-dom@18.2.0)(react@18.2.0) + rc-collapse: 3.7.3(react-dom@18.2.0)(react@18.2.0) + rc-dialog: 9.5.2(react-dom@18.2.0)(react@18.2.0) + rc-drawer: 7.2.0(react-dom@18.2.0)(react@18.2.0) + rc-dropdown: 4.2.0(react-dom@18.2.0)(react@18.2.0) + rc-field-form: 2.4.0(react-dom@18.2.0)(react@18.2.0) + rc-image: 7.9.0(react-dom@18.2.0)(react@18.2.0) + rc-input: 1.6.3(react-dom@18.2.0)(react@18.2.0) + rc-input-number: 9.2.0(react-dom@18.2.0)(react@18.2.0) + rc-mentions: 2.15.0(react-dom@18.2.0)(react@18.2.0) + rc-menu: 9.14.1(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) + rc-notification: 5.6.2(react-dom@18.2.0)(react@18.2.0) + rc-pagination: 4.2.0(react-dom@18.2.0)(react@18.2.0) + rc-picker: 4.6.15(dayjs@1.11.13)(react-dom@18.2.0)(react@18.2.0) + rc-progress: 4.0.0(react-dom@18.2.0)(react@18.2.0) + rc-rate: 2.13.0(react-dom@18.2.0)(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) + rc-segmented: 2.3.0(react-dom@18.2.0)(react@18.2.0) + rc-select: 14.15.2(react-dom@18.2.0)(react@18.2.0) + rc-slider: 11.1.6(react-dom@18.2.0)(react@18.2.0) + rc-steps: 6.0.1(react-dom@18.2.0)(react@18.2.0) + rc-switch: 4.1.0(react-dom@18.2.0)(react@18.2.0) + rc-table: 7.45.7(react-dom@18.2.0)(react@18.2.0) + rc-tabs: 15.1.1(react-dom@18.2.0)(react@18.2.0) + rc-textarea: 1.8.2(react-dom@18.2.0)(react@18.2.0) + rc-tooltip: 6.2.1(react-dom@18.2.0)(react@18.2.0) + rc-tree: 5.9.0(react-dom@18.2.0)(react@18.2.0) + rc-tree-select: 5.23.0(react-dom@18.2.0)(react@18.2.0) + rc-upload: 4.7.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) scroll-into-view-if-needed: 3.1.0 @@ -2274,6 +2578,8 @@ snapshots: balanced-match@1.0.2: {} + base64-js@1.5.1: {} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -2287,6 +2593,11 @@ snapshots: dependencies: fill-range: 7.1.1 + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + busboy@1.6.0: dependencies: streamsearch: 1.1.0 @@ -2316,6 +2627,18 @@ snapshots: client-only@0.0.1: {} + codemirror@6.0.1(@lezer/common@1.2.3): + dependencies: + '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3) + '@codemirror/commands': 6.7.1 + '@codemirror/language': 6.10.3 + '@codemirror/lint': 6.8.2 + '@codemirror/search': 6.5.6 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + transitivePeerDependencies: + - '@lezer/common' + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -2330,6 +2653,8 @@ snapshots: dependencies: toggle-selection: 1.0.6 + crelt@1.0.6: {} + cross-spawn@7.0.3: dependencies: path-key: 3.1.1 @@ -2427,6 +2752,8 @@ snapshots: ansi-colors: 4.1.3 strip-ansi: 6.0.1 + err-code@3.0.1: {} + es-abstract@1.23.3: dependencies: array-buffer-byte-length: 1.0.1 @@ -2537,16 +2864,15 @@ snapshots: dependencies: '@next/eslint-plugin-next': 14.2.13 '@rushstack/eslint-patch': 1.10.4 - '@typescript-eslint/eslint-plugin': 8.8.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint@8.0.0)(typescript@5.0.2) + '@typescript-eslint/eslint-plugin': 8.8.0(@typescript-eslint/parser@8.8.0)(eslint@8.0.0)(typescript@5.0.2) '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) eslint: 8.0.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0) - eslint-plugin-import: 2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0) + eslint-plugin-import: 2.30.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) eslint-plugin-jsx-a11y: 6.10.0(eslint@8.0.0) eslint-plugin-react: 7.37.1(eslint@8.0.0) eslint-plugin-react-hooks: 4.6.2(eslint@8.0.0) - optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - eslint-import-resolver-webpack @@ -2561,39 +2887,38 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0): + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 8.0.0 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0))(eslint@8.0.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) + eslint-plugin-import: 2.30.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 is-glob: 4.0.3 - optionalDependencies: - eslint-plugin-import: 2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-node - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0))(eslint@8.0.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): dependencies: - debug: 3.2.7 - optionalDependencies: '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) + debug: 3.2.7 eslint: 8.0.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): + eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): dependencies: '@rtsao/scc': 1.1.0 + '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 array.prototype.flat: 1.3.2 @@ -2602,7 +2927,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.0.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0))(eslint@8.0.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -2612,8 +2937,6 @@ snapshots: object.values: 1.2.0 semver: 6.3.1 tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -2798,6 +3121,8 @@ snapshots: functions-have-names@1.2.3: {} + get-browser-rtc@1.1.0: {} + get-intrinsic@1.2.4: dependencies: es-errors: 1.3.0 @@ -2878,6 +3203,8 @@ snapshots: dependencies: function-bind: 1.1.2 + ieee754@1.2.1: {} + ignore@4.0.6: {} ignore@5.3.2: {} @@ -3009,6 +3336,8 @@ snapshots: isexe@2.0.0: {} + isomorphic.js@0.2.5: {} + iterator.prototype@1.1.2: dependencies: define-properties: 1.2.1 @@ -3065,6 +3394,10 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lib0@0.2.98: + dependencies: + isomorphic.js: 0.2.5 + lodash.merge@4.6.2: {} loose-envify@1.4.0: @@ -3098,7 +3431,7 @@ snapshots: natural-compare@1.4.0: {} - next@14.2.13(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2): + next@14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2): dependencies: '@next/env': 14.2.13 '@swc/helpers': 0.5.5 @@ -3108,6 +3441,7 @@ snapshots: postcss: 8.4.31 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + sass: 1.79.2 styled-jsx: 5.1.1(react@18.2.0) optionalDependencies: '@next/swc-darwin-arm64': 14.2.13 @@ -3119,7 +3453,6 @@ snapshots: '@next/swc-win32-arm64-msvc': 14.2.13 '@next/swc-win32-ia32-msvc': 14.2.13 '@next/swc-win32-x64-msvc': 14.2.13 - sass: 1.79.2 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -3221,322 +3554,325 @@ snapshots: queue-microtask@1.2.3: {} - rc-cascader@3.28.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + rc-cascader@3.28.1(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 array-tree-filter: 2.1.0 classnames: 2.5.1 - rc-select: 14.15.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-tree: 5.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-select: 14.15.2(react-dom@18.2.0)(react@18.2.0) + rc-tree: 5.9.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-checkbox@3.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-checkbox@3.3.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-collapse@3.7.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-collapse@3.7.3(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-dialog@9.5.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-dialog@9.5.2(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-drawer@7.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-drawer@7.2.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-dropdown@4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-dropdown@4.2.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-field-form@2.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-field-form@2.4.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/async-validator': 5.0.4 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-image@7.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-image@7.9.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 - rc-dialog: 9.5.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-dialog: 9.5.2(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-input-number@9.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-input-number@9.2.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/mini-decimal': 1.1.0 classnames: 2.5.1 - rc-input: 1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-input: 1.6.3(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-input@1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-input@1.6.3(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-mentions@2.15.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-mentions@2.15.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 - rc-input: 1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-menu: 9.14.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-textarea: 1.8.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-input: 1.6.3(react-dom@18.2.0)(react@18.2.0) + rc-menu: 9.14.1(react-dom@18.2.0)(react@18.2.0) + rc-textarea: 1.8.2(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-menu@9.14.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-menu@9.14.1(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-overflow: 1.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) + rc-overflow: 1.3.2(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-motion@2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-motion@2.9.3(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-notification@5.6.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-notification@5.6.2(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-overflow@1.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-overflow@1.3.2(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-pagination@4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-pagination@4.2.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-picker@4.6.15(dayjs@1.11.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-picker@4.6.15(dayjs@1.11.13)(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 - rc-overflow: 1.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + dayjs: 1.11.13 + rc-overflow: 1.3.2(react-dom@18.2.0)(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - optionalDependencies: - dayjs: 1.11.13 - rc-progress@4.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-progress@4.0.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-rate@2.13.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-rate@2.13.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-resize-observer@1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-resize-observer@1.4.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) resize-observer-polyfill: 1.5.1 - rc-segmented@2.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-segmented@2.3.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-select@14.15.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-select@14.15.2(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-overflow: 1.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-virtual-list: 3.14.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) + rc-overflow: 1.3.2(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-virtual-list: 3.14.8(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-slider@11.1.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-slider@11.1.6(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-steps@6.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-steps@6.0.1(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-switch@4.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-switch@4.1.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-table@7.45.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-table@7.45.7(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/context': 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/context': 1.4.0(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 - rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-virtual-list: 3.14.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-virtual-list: 3.14.8(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-tabs@15.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-tabs@15.1.1(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-dropdown: 4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-menu: 9.14.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-dropdown: 4.2.0(react-dom@18.2.0)(react@18.2.0) + rc-menu: 9.14.1(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-textarea@1.8.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-textarea@1.8.2(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-input: 1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-input: 1.6.3(react-dom@18.2.0)(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-tooltip@6.2.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-tooltip@6.2.1(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-tree-select@5.23.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-tree-select@5.23.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-select: 14.15.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-tree: 5.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-select: 14.15.2(react-dom@18.2.0)(react@18.2.0) + rc-tree: 5.9.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-tree@5.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-tree@5.9.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-virtual-list: 3.14.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-virtual-list: 3.14.8(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-upload@4.7.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-upload@4.7.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-util@5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-util@5.43.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-is: 18.3.1 - rc-virtual-list@3.14.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + rc-virtual-list@3.14.8(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -3560,6 +3896,12 @@ snapshots: dependencies: loose-envify: 1.4.0 + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + readdirp@4.0.1: {} reflect.getprototypeof@1.0.6: @@ -3618,6 +3960,8 @@ snapshots: has-symbols: 1.0.3 isarray: 2.0.5 + safe-buffer@5.2.1: {} + safe-regex-test@1.0.3: dependencies: call-bind: 1.0.7 @@ -3673,6 +4017,18 @@ snapshots: signal-exit@4.1.0: {} + simple-peer@9.11.1: + dependencies: + buffer: 6.0.3 + debug: 4.3.7 + err-code: 3.0.1 + get-browser-rtc: 1.1.0 + queue-microtask: 1.2.3 + randombytes: 2.1.0 + readable-stream: 3.6.2 + transitivePeerDependencies: + - supports-color + source-map-js@1.2.1: {} stop-iteration-iterator@1.0.0: @@ -3739,6 +4095,10 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -3751,6 +4111,8 @@ snapshots: strip-json-comments@3.1.1: {} + style-mod@4.1.2: {} + styled-jsx@5.1.1(react@18.2.0): dependencies: client-only: 0.0.1 @@ -3842,8 +4204,12 @@ snapshots: dependencies: punycode: 2.3.1 + util-deprecate@1.0.2: {} + v8-compile-cache@2.4.0: {} + w3c-keyname@2.2.8: {} + which-boxed-primitive@1.0.2: dependencies: is-bigint: 1.0.4 @@ -3901,3 +4267,35 @@ snapshots: strip-ansi: 7.1.0 wrappy@1.0.2: {} + + ws@8.18.0: + optional: true + + y-codemirror.next@0.3.5(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(yjs@13.6.20): + dependencies: + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + lib0: 0.2.98 + yjs: 13.6.20 + + y-protocols@1.0.6(yjs@13.6.20): + dependencies: + lib0: 0.2.98 + yjs: 13.6.20 + + y-webrtc@10.3.0(yjs@13.6.20): + dependencies: + lib0: 0.2.98 + simple-peer: 9.11.1 + y-protocols: 1.0.6(yjs@13.6.20) + yjs: 13.6.20 + optionalDependencies: + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + yjs@13.6.20: + dependencies: + lib0: 0.2.98 diff --git a/apps/frontend/src/app/layout.tsx b/apps/frontend/src/app/layout.tsx index 61070cf842..e68cebe340 100644 --- a/apps/frontend/src/app/layout.tsx +++ b/apps/frontend/src/app/layout.tsx @@ -25,9 +25,7 @@ const RootLayout = ({ }} > - - {children} - + {children} diff --git a/apps/frontend/src/app/matching/MatchingModal.tsx b/apps/frontend/src/app/matching/MatchingModal.tsx index df5dd4af8f..03af2ae2a0 100644 --- a/apps/frontend/src/app/matching/MatchingModal.tsx +++ b/apps/frontend/src/app/matching/MatchingModal.tsx @@ -15,6 +15,7 @@ import MatchCancelledContent from './modalContent/MatchCancelledContent'; import useMatching from '../services/use-matching'; import { ValidateUser } from '../services/user'; import { useTimer } from 'react-timer-hook'; +import { useRouter } from 'next/router'; interface MatchingModalProps { isOpen: boolean; @@ -32,6 +33,7 @@ const MatchingModal: React.FC = ({ isOpen, close: _close }) const matchingState = useMatching(); const [closedType, setClosedType] = useState<"finding" | "cancelled" | "joined">("finding"); const isClosable = ["timeout", "closed"].includes(matchingState.state); + const router = useRouter(); const { totalSeconds, pause: pauseTimer, restart: restartTimer } = useTimer({ expiryTimestamp: new Date(Date.now() + MATCH_TIMEOUT * 1000), autoStart: false, @@ -104,8 +106,8 @@ const MatchingModal: React.FC = ({ isOpen, close: _close }) cancel={() => { setClosedType("cancelled"); }} - name1={matchingState.info?.myName ?? ""} - name2={matchingState.info?.partnerName ??""} + name1={matchingState.info?.user ?? ""} + name2={matchingState.info?.matchedUser ?? ""} />; } case 'matching': @@ -128,11 +130,22 @@ const MatchingModal: React.FC = ({ isOpen, close: _close }) setClosedType("cancelled"); }} join={() => { - matchingState.ok(); - setClosedType("joined"); + matchingState.ok(); + setClosedType("joined"); + localStorage.setItem("user", matchingState.info.user); + localStorage.setItem( + "matchedUser", + matchingState.info.matchedUser + ); + localStorage.setItem("collabId", matchingState.info.matchId); + localStorage.setItem("questionDocRefId", matchingState.info.questionDocRefId); + localStorage.setItem("matchedTopics", matchingState.info.matchedTopics.join(",")); + + // Redirect to collaboration page + router.push(`/collaboration/${matchingState.info.matchId}`); }} - name1={matchingState.info.myName} - name2={matchingState.info.partnerName} + name1={matchingState.info.user} + name2={matchingState.info.matchedUser} joiningIn={totalSeconds} /> case 'timeout': @@ -140,7 +153,7 @@ const MatchingModal: React.FC = ({ isOpen, close: _close }) default: throw new Error('Invalid matching state.'); } - }; + } return ( = ({join, cancel, name1: me, name2: you Cancel - ) -} + ); +}; export default MatchFoundContent; diff --git a/apps/frontend/src/app/page.tsx b/apps/frontend/src/app/page.tsx index da2ded7c96..6af2a788e7 100644 --- a/apps/frontend/src/app/page.tsx +++ b/apps/frontend/src/app/page.tsx @@ -14,13 +14,13 @@ const HomePage = () => { const closeMatchingModal = () => { setMatchingModalOpen(false); - } + }; return (
- +
@@ -28,10 +28,10 @@ const HomePage = () => {
Prep
- + A better way to prepare for coding interviews with - - peers + + peers
- Topics: + Topics: {categories.map((category) => ( {category} ))}
- {description} + {description}
@@ -184,9 +174,9 @@ export default function Home() {
- + Select Language:  - + + + +
+
+

Summary of User Match Requests

+
+
+
+
diff --git a/apps/matching-service/utils/timeout.go b/apps/matching-service/utils/timeout.go index 1876518f07..08d6b8c340 100644 --- a/apps/matching-service/utils/timeout.go +++ b/apps/matching-service/utils/timeout.go @@ -1,6 +1,7 @@ package utils import ( + "context" "os" "strconv" "time" @@ -15,3 +16,13 @@ func GetTimeoutDuration() (time.Duration, error) { } return time.Duration(timeout) * time.Second, nil } + +// createTimeoutContext sets up a timeout context based on configuration. +func CreateTimeoutContext() (context.Context, context.CancelFunc, error) { + timeoutDuration, err := GetTimeoutDuration() + if err != nil { + return nil, nil, err + } + ctx, cancel := context.WithTimeout(context.Background(), timeoutDuration) + return ctx, cancel, nil +} diff --git a/apps/question-service/Dockerfile b/apps/question-service/Dockerfile index c2a9e0836b..0f7b9b698a 100644 --- a/apps/question-service/Dockerfile +++ b/apps/question-service/Dockerfile @@ -11,6 +11,6 @@ COPY . . RUN go build -v -o /usr/local/bin/app ./main.go -EXPOSE 8080 +EXPOSE 8080 50051 CMD ["app"] diff --git a/apps/question-service/README.md b/apps/question-service/README.md index 99ed749159..3045231030 100644 --- a/apps/question-service/README.md +++ b/apps/question-service/README.md @@ -58,7 +58,7 @@ docker build -t question-service . ``` ```bash -docker run -p 8080:8080 --env-file .env -d question-service +docker run -p 8080:8080 -p 50051:50051 --env-file .env -d question-service ``` The server will be available at http://localhost:8080. diff --git a/apps/question-service/go.mod b/apps/question-service/go.mod index 4ac0fa8e1e..481f8efbb7 100644 --- a/apps/question-service/go.mod +++ b/apps/question-service/go.mod @@ -7,7 +7,7 @@ require ( firebase.google.com/go/v4 v4.14.1 github.com/go-chi/chi/v5 v5.1.0 google.golang.org/api v0.198.0 - google.golang.org/grpc v1.67.0 + google.golang.org/grpc v1.67.1 ) require github.com/joho/godotenv v1.5.1 @@ -49,5 +49,5 @@ require ( google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.35.1 ) diff --git a/apps/question-service/go.sum b/apps/question-service/go.sum index 1b4b765942..02ba516f91 100644 --- a/apps/question-service/go.sum +++ b/apps/question-service/go.sum @@ -188,8 +188,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= -google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -201,8 +201,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/apps/question-service/handlers/list.go b/apps/question-service/handlers/list.go index 8f2463cdfa..47c00800ec 100644 --- a/apps/question-service/handlers/list.go +++ b/apps/question-service/handlers/list.go @@ -1,12 +1,13 @@ package handlers import ( - "cloud.google.com/go/firestore" "encoding/json" "net/http" "question-service/models" "strconv" "strings" + + "cloud.google.com/go/firestore" ) var isValidSortField = map[string]bool{ diff --git a/apps/question-service/handlers/types.go b/apps/question-service/handlers/types.go deleted file mode 100644 index 5829c0ad39..0000000000 --- a/apps/question-service/handlers/types.go +++ /dev/null @@ -1,7 +0,0 @@ -package handlers - -import "cloud.google.com/go/firestore" - -type Service struct { - Client *firestore.Client -} diff --git a/apps/question-service/main.go b/apps/question-service/main.go index 9f9c11d2c7..349a66402e 100644 --- a/apps/question-service/main.go +++ b/apps/question-service/main.go @@ -5,10 +5,12 @@ import ( "flag" "fmt" "log" + "net" "net/http" "os" "question-service/handlers" mymiddleware "question-service/middleware" + pb "question-service/proto" "question-service/utils" "time" @@ -19,23 +21,9 @@ import ( "github.com/go-chi/cors" "github.com/joho/godotenv" "google.golang.org/api/option" + "google.golang.org/grpc" ) -// initFirestore initializes the Firestore client -func initFirestore(ctx context.Context, credentialsPath string) (*firestore.Client, error) { - opt := option.WithCredentialsFile(credentialsPath) - app, err := firebase.NewApp(ctx, nil, opt) - if err != nil { - return nil, fmt.Errorf("failed to initialize Firebase App: %v", err) - } - - client, err := app.Firestore(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get Firestore client: %v", err) - } - return client, nil -} - func main() { // Load .env file err := godotenv.Load() @@ -45,8 +33,7 @@ func main() { // Initialize Firestore client ctx := context.Background() - firebaseCredentialPath := os.Getenv("FIREBASE_CREDENTIAL_PATH") - client, err := initFirestore(ctx, firebaseCredentialPath) + client, err := initFirestore(ctx) if err != nil { log.Fatalf("Failed to initialize Firestore client: %v", err) } @@ -62,7 +49,29 @@ func main() { return } - // Set up chi router + go initGrpcServer(service) + + r := initChiRouter(service) + initRestServer(r) +} + +// initFirestore initializes the Firestore client +func initFirestore(ctx context.Context) (*firestore.Client, error) { + credentialsPath := os.Getenv("FIREBASE_CREDENTIAL_PATH") + opt := option.WithCredentialsFile(credentialsPath) + app, err := firebase.NewApp(ctx, nil, opt) + if err != nil { + return nil, fmt.Errorf("failed to initialize Firebase App: %v", err) + } + + client, err := app.Firestore(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get Firestore client: %v", err) + } + return client, nil +} + +func initChiRouter(service *handlers.Service) *chi.Mux { r := chi.NewRouter() r.Use(middleware.Logger) r.Use(middleware.Timeout(60 * time.Second)) @@ -79,7 +88,12 @@ func main() { MaxAge: 300, // Maximum value not ignored by any of major browsers })) - // Register routes + registerRoutes(r, service) + + return r +} + +func registerRoutes(r *chi.Mux, service *handlers.Service) { r.Route("/questions", func(r chi.Router) { r.Get("/", service.ListQuestions) r.Post("/", service.CreateQuestion) @@ -90,7 +104,9 @@ func main() { r.Delete("/", service.DeleteQuestion) }) }) +} +func initRestServer(r *chi.Mux) { // Serve on port 8080 port := os.Getenv("PORT") if port == "" { @@ -98,9 +114,25 @@ func main() { } // Start the server - log.Printf("Starting server on http://localhost:%s", port) - err = http.ListenAndServe(fmt.Sprintf(":%s", port), r) + log.Printf("Starting REST server on http://localhost:%s", port) + err := http.ListenAndServe(fmt.Sprintf(":%s", port), r) if err != nil { log.Fatalf("Failed to start server: %v", err) } } + +func initGrpcServer(service *handlers.Service) { + lis, err := net.Listen("tcp", ":50051") + if err != nil { + log.Fatalf("failed to listen: %v", err) + } + s := grpc.NewServer() + pb.RegisterQuestionMatchingServiceServer(s, &handlers.GrpcServer{ + Client: service.Client, + }) + + log.Printf("gRPC Server is listening on port 50051...") + if err := s.Serve(lis); err != nil { + log.Fatalf("failed to serve: %v", err) + } +} From f558075bfbd4ea28826505b464ba30d3997f11e5 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Wed, 30 Oct 2024 14:40:53 +0800 Subject: [PATCH 090/258] Remove cancel, join button from Found UI --- .../src/app/matching/MatchingModal.tsx | 53 ++++++++++--------- .../modalContent/FindMatchContent.tsx | 6 +-- .../modalContent/MatchFoundContent.tsx | 4 +- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/apps/frontend/src/app/matching/MatchingModal.tsx b/apps/frontend/src/app/matching/MatchingModal.tsx index 02bb1ccedb..0a2d33472c 100644 --- a/apps/frontend/src/app/matching/MatchingModal.tsx +++ b/apps/frontend/src/app/matching/MatchingModal.tsx @@ -1,3 +1,5 @@ +"use client" + import React, { useState, useEffect } from 'react'; import { Form, @@ -15,7 +17,7 @@ import MatchCancelledContent from './modalContent/MatchCancelledContent'; import useMatching from '../services/use-matching'; import { ValidateUser } from '../services/user'; import { useTimer } from 'react-timer-hook'; -import { useRouter } from 'next/router'; +import { useRouter } from 'next/navigation'; interface MatchingModalProps { isOpen: boolean; @@ -43,8 +45,7 @@ const MatchingModal: React.FC = ({ isOpen, close: _close }) return; } if (matchingState.state === "found") { - matchingState.ok(); - setClosedType("joined"); + join(); return; } console.warn(`matching is in ${matchingState.state}`) @@ -52,14 +53,14 @@ const MatchingModal: React.FC = ({ isOpen, close: _close }) }); const passed = MATCH_TIMEOUT - totalSeconds; - function close() { - // clean up matching and closedType State - if (matchingState.state === "timeout") { - matchingState.ok(); + function close() { + // clean up matching and closedType State + if (matchingState.state === "timeout") { + matchingState.ok(); + } + setClosedType("finding"); + _close(); } - setClosedType("finding"); - _close(); - } const startMatch = matchingState.state == "closed" || matchingState.state == "timeout" ? async (params: MatchParams): Promise => { const user = await ValidateUser(); @@ -75,6 +76,22 @@ const MatchingModal: React.FC = ({ isOpen, close: _close }) ...params }); } : undefined; + + const join = matchingState.state == "found" ? (() => { + matchingState.ok(); + setClosedType("joined"); + localStorage.setItem("user", matchingState.info.user); + localStorage.setItem( + "matchedUser", + matchingState.info.matchedUser + ); + localStorage.setItem("collabId", matchingState.info.matchId); + localStorage.setItem("questionDocRefId", matchingState.info.questionDocRefId); + localStorage.setItem("matchedTopics", matchingState.info.matchedTopics.join(",")); + + // Redirect to collaboration page + router.push(`/collaboration/${matchingState.info.matchId}`); + }) : () => { throw new Error("join called when not found"); } useEffect(() => { if (matchingState.state === "cancelling" || matchingState.state === "timeout") { @@ -129,21 +146,7 @@ const MatchingModal: React.FC = ({ isOpen, close: _close }) matchingState.ok(); setClosedType("cancelled"); }} - join={() => { - matchingState.ok(); - setClosedType("joined"); - localStorage.setItem("user", matchingState.info.user); - localStorage.setItem( - "matchedUser", - matchingState.info.matchedUser - ); - localStorage.setItem("collabId", matchingState.info.matchId); - localStorage.setItem("questionDocRefId", matchingState.info.questionDocRefId); - localStorage.setItem("matchedTopics", matchingState.info.matchedTopics.join(",")); - - // Redirect to collaboration page - router.push(`/collaboration/${matchingState.info.matchId}`); - }} + join={join} name1={matchingState.info.user} name2={matchingState.info.matchedUser} joiningIn={totalSeconds} diff --git a/apps/frontend/src/app/matching/modalContent/FindMatchContent.tsx b/apps/frontend/src/app/matching/modalContent/FindMatchContent.tsx index 3dd95d9d3e..393500569f 100644 --- a/apps/frontend/src/app/matching/modalContent/FindMatchContent.tsx +++ b/apps/frontend/src/app/matching/modalContent/FindMatchContent.tsx @@ -56,12 +56,12 @@ const TagInput: React.FC<{ { onChange( enabled - ? [...value, difficultyOption.label] - : value.filter(diff => diff !== difficultyOption.label) + ? [...value, difficultyOption.value] + : value.filter(diff => diff !== difficultyOption.value) ) }} > diff --git a/apps/frontend/src/app/matching/modalContent/MatchFoundContent.tsx b/apps/frontend/src/app/matching/modalContent/MatchFoundContent.tsx index 8a6d49a8ad..21ac3ed738 100644 --- a/apps/frontend/src/app/matching/modalContent/MatchFoundContent.tsx +++ b/apps/frontend/src/app/matching/modalContent/MatchFoundContent.tsx @@ -43,7 +43,7 @@ const MatchFoundContent: React.FC = ({join, cancel, name1: me, name2: you
Joining in... {formatTime(joiningIn)}
- + */} ); }; From de92010b69489b24af87ad9e775bfda01d7f53ae Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Wed, 30 Oct 2024 17:36:41 +0800 Subject: [PATCH 091/258] feat: update backend routes --- apps/history-service/handlers/create.go | 5 +- .../handlers/createOrUpdate.go | 9 +-- apps/history-service/handlers/delete.go | 3 +- .../handlers/listquestionhistory.go | 70 +++++++++++++++++++ .../handlers/{list.go => listuserhistory.go} | 0 apps/history-service/handlers/read.go | 5 +- apps/history-service/handlers/update.go | 9 +-- apps/history-service/main.go | 27 ++++--- 8 files changed, 100 insertions(+), 28 deletions(-) create mode 100644 apps/history-service/handlers/listquestionhistory.go rename apps/history-service/handlers/{list.go => listuserhistory.go} (100%) diff --git a/apps/history-service/handlers/create.go b/apps/history-service/handlers/create.go index d981fb9190..7ce6037eff 100644 --- a/apps/history-service/handlers/create.go +++ b/apps/history-service/handlers/create.go @@ -1,12 +1,13 @@ package handlers import ( - "cloud.google.com/go/firestore" "encoding/json" - "google.golang.org/api/iterator" "history-service/models" "history-service/utils" "net/http" + + "cloud.google.com/go/firestore" + "google.golang.org/api/iterator" ) // Create a new code snippet diff --git a/apps/history-service/handlers/createOrUpdate.go b/apps/history-service/handlers/createOrUpdate.go index f9df4bcc33..6f091eba19 100644 --- a/apps/history-service/handlers/createOrUpdate.go +++ b/apps/history-service/handlers/createOrUpdate.go @@ -1,15 +1,16 @@ package handlers import ( - "cloud.google.com/go/firestore" "encoding/json" + "history-service/models" + "history-service/utils" + "net/http" + + "cloud.google.com/go/firestore" "github.com/go-chi/chi/v5" "google.golang.org/api/iterator" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "history-service/models" - "history-service/utils" - "net/http" ) func (s *Service) CreateOrUpdateHistory(w http.ResponseWriter, r *http.Request) { diff --git a/apps/history-service/handlers/delete.go b/apps/history-service/handlers/delete.go index a450b58ea4..f528e4bc34 100644 --- a/apps/history-service/handlers/delete.go +++ b/apps/history-service/handlers/delete.go @@ -1,10 +1,11 @@ package handlers import ( + "net/http" + "github.com/go-chi/chi/v5" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "net/http" ) // Delete a code snippet by ID diff --git a/apps/history-service/handlers/listquestionhistory.go b/apps/history-service/handlers/listquestionhistory.go new file mode 100644 index 0000000000..486f83363a --- /dev/null +++ b/apps/history-service/handlers/listquestionhistory.go @@ -0,0 +1,70 @@ +package handlers + +import ( + "encoding/json" + "history-service/models" + "net/http" + + "github.com/go-chi/chi/v5" + "google.golang.org/api/iterator" +) + +func (s *Service) ListUserQuestionHistories(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + // Parse request + username := chi.URLParam(r, "username") + + // Reference collection + collRef := s.Client.Collection("collaboration-history") + + // Query data + iterUser := collRef.Where("user", "==", username).Documents(ctx) + iterMatchedUser := collRef.Where("matchedUser", "==", username).Documents(ctx) + + // Map data + var histories []models.CollaborationHistory + for { + doc, err := iterUser.Next() + if err == iterator.Done { + break + } + if err != nil { + http.Error(w, "Failed to get histories for user", http.StatusInternalServerError) + return + } + + var history models.CollaborationHistory + if err := doc.DataTo(&history); err != nil { + http.Error(w, "Failed to map history data for user", http.StatusInternalServerError) + return + } + history.MatchID = doc.Ref.ID + + histories = append(histories, history) + } + + for { + doc, err := iterMatchedUser.Next() + if err == iterator.Done { + break + } + if err != nil { + http.Error(w, "Failed to get histories for matched user", http.StatusInternalServerError) + return + } + + var history models.CollaborationHistory + if err := doc.DataTo(&history); err != nil { + http.Error(w, "Failed to map history data for matched user", http.StatusInternalServerError) + return + } + history.MatchID = doc.Ref.ID + + histories = append(histories, history) + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(histories) +} diff --git a/apps/history-service/handlers/list.go b/apps/history-service/handlers/listuserhistory.go similarity index 100% rename from apps/history-service/handlers/list.go rename to apps/history-service/handlers/listuserhistory.go diff --git a/apps/history-service/handlers/read.go b/apps/history-service/handlers/read.go index fd97c5d031..d7c6ea23a0 100644 --- a/apps/history-service/handlers/read.go +++ b/apps/history-service/handlers/read.go @@ -2,10 +2,11 @@ package handlers import ( "encoding/json" - "github.com/go-chi/chi/v5" - "google.golang.org/api/iterator" "history-service/models" "net/http" + + "github.com/go-chi/chi/v5" + "google.golang.org/api/iterator" ) // Read a code snippet by ID diff --git a/apps/history-service/handlers/update.go b/apps/history-service/handlers/update.go index b6cb953709..401953a472 100644 --- a/apps/history-service/handlers/update.go +++ b/apps/history-service/handlers/update.go @@ -1,15 +1,16 @@ package handlers import ( - "cloud.google.com/go/firestore" "encoding/json" + "history-service/models" + "history-service/utils" + "net/http" + + "cloud.google.com/go/firestore" "github.com/go-chi/chi/v5" "google.golang.org/api/iterator" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "history-service/models" - "history-service/utils" - "net/http" ) // Update an existing code snippet diff --git a/apps/history-service/main.go b/apps/history-service/main.go index cf69c934d2..17194b9f49 100644 --- a/apps/history-service/main.go +++ b/apps/history-service/main.go @@ -1,20 +1,21 @@ package main import ( - "cloud.google.com/go/firestore" "context" - firebase "firebase.google.com/go/v4" "fmt" - "github.com/go-chi/chi/v5" - "github.com/go-chi/chi/v5/middleware" - "github.com/go-chi/cors" - "github.com/joho/godotenv" - "google.golang.org/api/option" "history-service/handlers" "log" "net/http" "os" "time" + + "cloud.google.com/go/firestore" + firebase "firebase.google.com/go/v4" + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" + "github.com/go-chi/cors" + "github.com/joho/godotenv" + "google.golang.org/api/option" ) func main() { @@ -75,14 +76,10 @@ func initChiRouter(service *handlers.Service) *chi.Mux { func registerRoutes(r *chi.Mux, service *handlers.Service) { r.Route("/histories", func(r chi.Router) { - r.Get("/{username}", service.ListUserHistories) - //r.Post("/", service.CreateHistory) - - r.Route("/{matchId}", func(r chi.Router) { - r.Put("/", service.CreateOrUpdateHistory) - r.Get("/", service.ReadHistory) - //r.Put("/", service.UpdateHistory) - //r.Delete("/", service.DeleteHistory) + r.Post("/", service.CreateHistory) + r.Route("/{username}", func(r chi.Router) { + r.Get("/", service.ListUserHistories) + r.Get("/{questionDocRefId}", service.ListUserQuestionHistories) }) }) } From 6772a30f5286bc42a816846ca0a87b4f7fd4e0db Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Wed, 30 Oct 2024 17:40:49 +0800 Subject: [PATCH 092/258] delete cookie by setting expiry to 0 --- apps/frontend/src/app/services/login-store.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/src/app/services/login-store.ts b/apps/frontend/src/app/services/login-store.ts index 0afdf63d80..f8809ed583 100644 --- a/apps/frontend/src/app/services/login-store.ts +++ b/apps/frontend/src/app/services/login-store.ts @@ -22,5 +22,5 @@ export function getToken(): string { } export function deleteToken() { - document.cookie = `${KEY}=`; + document.cookie = `${KEY}=nothinghere;expires=0`; } \ No newline at end of file From 483525f869bef309990fd1da70840282b86cc98b Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Fri, 1 Nov 2024 12:43:56 +0800 Subject: [PATCH 093/258] setup jest --- apps/frontend/__tests__/Datetime.test.ts | 10 + apps/frontend/jest.config.ts | 206 ++ apps/frontend/package.json | 10 +- apps/frontend/pnpm-lock.yaml | 3263 ++++++++++++++++++++-- 4 files changed, 3218 insertions(+), 271 deletions(-) create mode 100644 apps/frontend/__tests__/Datetime.test.ts create mode 100644 apps/frontend/jest.config.ts diff --git a/apps/frontend/__tests__/Datetime.test.ts b/apps/frontend/__tests__/Datetime.test.ts new file mode 100644 index 0000000000..7438ff5d67 --- /dev/null +++ b/apps/frontend/__tests__/Datetime.test.ts @@ -0,0 +1,10 @@ +import { describe, expect, it } from "@jest/globals" +import { formatTime } from "@/utils/DateTime" + +describe("datetime module", () => { + it("formats a time correctly", () => { + expect(formatTime(10)).toBe("00:10") + }); +}) + + diff --git a/apps/frontend/jest.config.ts b/apps/frontend/jest.config.ts new file mode 100644 index 0000000000..cf78af5d8e --- /dev/null +++ b/apps/frontend/jest.config.ts @@ -0,0 +1,206 @@ +/** + * For a detailed explanation regarding each configuration property, visit: + * https://jestjs.io/docs/configuration + */ + +import type { Config } from 'jest'; +import nextJest from "next/jest" + +const createJestConfig = nextJest({ + // Provide the path to your Next.js app to load next.config.js and .env files in your test environment + dir: './', +}) + +const config: Config = { + // All imported modules in your tests should be mocked automatically + // automock: false, + + // Stop running tests after `n` failures + // bail: 0, + + // The directory where Jest should store its cached dependency information + // cacheDirectory: "C:\\Users\\user\\AppData\\Local\\Temp\\jest", + + // Automatically clear mock calls, instances, contexts and results before every test + clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + // collectCoverage: false, + + // An array of glob patterns indicating a set of files for which coverage information should be collected + // collectCoverageFrom: undefined, + + // The directory where Jest should output its coverage files + // coverageDirectory: undefined, + + // An array of regexp pattern strings used to skip coverage collection + // coveragePathIgnorePatterns: [ + // "\\\\node_modules\\\\" + // ], + + // Indicates which provider should be used to instrument code for coverage + coverageProvider: "v8", + + // A list of reporter names that Jest uses when writing coverage reports + // coverageReporters: [ + // "json", + // "text", + // "lcov", + // "clover" + // ], + + // An object that configures minimum threshold enforcement for coverage results + // coverageThreshold: undefined, + + // A path to a custom dependency extractor + // dependencyExtractor: undefined, + + // Make calling deprecated APIs throw helpful error messages + // errorOnDeprecated: false, + + // The default configuration for fake timers + // fakeTimers: { + // "enableGlobally": false + // }, + + // Force coverage collection from ignored files using an array of glob patterns + // forceCoverageMatch: [], + + // A path to a module which exports an async function that is triggered once before all test suites + // globalSetup: undefined, + + // A path to a module which exports an async function that is triggered once after all test suites + // globalTeardown: undefined, + + // A set of global variables that need to be available in all test environments + // globals: {}, + + // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. + // maxWorkers: "50%", + + // An array of directory names to be searched recursively up from the requiring module's location + // moduleDirectories: [ + // "node_modules" + // ], + + // An array of file extensions your modules use + // moduleFileExtensions: [ + // "js", + // "mjs", + // "cjs", + // "jsx", + // "ts", + // "tsx", + // "json", + // "node" + // ], + + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + // moduleNameMapper: {}, + + // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader + // modulePathIgnorePatterns: [], + + // Activates notifications for test results + // notify: false, + + // An enum that specifies notification mode. Requires { notify: true } + // notifyMode: "failure-change", + + // A preset that is used as a base for Jest's configuration + // preset: undefined, + + // Run tests from one or more projects + // projects: undefined, + + // Use this configuration option to add custom reporters to Jest + // reporters: undefined, + + // Automatically reset mock state before every test + // resetMocks: false, + + // Reset the module registry before running each individual test + // resetModules: false, + + // A path to a custom resolver + // resolver: undefined, + + // Automatically restore mock state and implementation before every test + // restoreMocks: false, + + // The root directory that Jest should scan for tests and modules within + // rootDir: undefined, + + // A list of paths to directories that Jest should use to search for files in + // roots: [ + // "" + // ], + + // Allows you to use a custom runner instead of Jest's default test runner + // runner: "jest-runner", + + // The paths to modules that run some code to configure or set up the testing environment before each test + // setupFiles: [], + + // A list of paths to modules that run some code to configure or set up the testing framework before each test + // setupFilesAfterEnv: [], + + // The number of seconds after which a test is considered as slow and reported as such in the results. + // slowTestThreshold: 5, + + // A list of paths to snapshot serializer modules Jest should use for snapshot testing + // snapshotSerializers: [], + + // The test environment that will be used for testing + testEnvironment: "jsdom", + + // Options that will be passed to the testEnvironment + // testEnvironmentOptions: {}, + + // Adds a location field to test results + // testLocationInResults: false, + + // The glob patterns Jest uses to detect test files + // testMatch: [ + // "**/__tests__/**/*.[jt]s?(x)", + // "**/?(*.)+(spec|test).[tj]s?(x)" + // ], + + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + // testPathIgnorePatterns: [ + // "\\\\node_modules\\\\" + // ], + + // The regexp pattern or array of patterns that Jest uses to detect test files + // testRegex: [], + + // This option allows the use of a custom results processor + // testResultsProcessor: undefined, + + // This option allows use of a custom test runner + // testRunner: "jest-circus/runner", + + // A map from regular expressions to paths to transformers + // transform: undefined, + + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + // transformIgnorePatterns: [ + // "\\\\node_modules\\\\", + // "\\.pnp\\.[^\\\\]+$" + // ], + + // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them + // unmockedModulePathPatterns: undefined, + + // Indicates whether each individual test should be reported during the run + // verbose: undefined, + + // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode + // watchPathIgnorePatterns: [], + + // Whether to use watchman for file crawling + // watchman: true, +}; + +export default createJestConfig(config); + diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 94cc9de16b..5cd1b9a9e7 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -6,7 +6,8 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "test": "jest" }, "dependencies": { "@ant-design/icons": "^5.5.1", @@ -32,11 +33,18 @@ "yjs": "^13.6.20" }, "devDependencies": { + "@jest/globals": "^29.7.0", + "@testing-library/dom": "^10.4.0", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/react": "^16.0.1", "@types/node": "^20", "@types/react": "^18.3.8", "@types/react-dom": "^18.3.0", "eslint": "^8", "eslint-config-next": "14.2.13", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", + "ts-node": "^10.9.2", "typescript": "^5" }, "packageManager": "pnpm@9.1.4+sha512.9df9cf27c91715646c7d675d1c9c8e41f6fce88246f1318c1aa6a1ed1aeb3c4f032fcdf4ba63cc69c4fe6d634279176b5358727d8f2cc1e65b65f43ce2f8bfb0" diff --git a/apps/frontend/pnpm-lock.yaml b/apps/frontend/pnpm-lock.yaml index c114790857..faff30a404 100644 --- a/apps/frontend/pnpm-lock.yaml +++ b/apps/frontend/pnpm-lock.yaml @@ -10,10 +10,10 @@ importers: dependencies: '@ant-design/icons': specifier: ^5.5.1 - version: 5.5.1(react-dom@18.2.0)(react@18.2.0) + version: 5.5.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@ant-design/nextjs-registry': specifier: ^1.0.1 - version: 1.0.1(@ant-design/cssinjs@1.21.1)(antd@5.20.6)(next@14.2.13)(react-dom@18.2.0)(react@18.2.0) + version: 1.0.1(@ant-design/cssinjs@1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(antd@5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(next@14.2.13(@babel/core@7.26.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@codemirror/lang-cpp': specifier: ^6.0.2 version: 6.0.2 @@ -37,13 +37,13 @@ importers: version: 6.4.1 antd: specifier: ^5.20.6 - version: 5.20.6(react-dom@18.2.0)(react@18.2.0) + version: 5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) codemirror: specifier: ^6.0.1 version: 6.0.1(@lezer/common@1.2.3) next: specifier: 14.2.13 - version: 14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2) + version: 14.2.13(@babel/core@7.26.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2) react: specifier: ^18.2.0 version: 18.2.0 @@ -72,6 +72,18 @@ importers: specifier: ^13.6.20 version: 13.6.20 devDependencies: + '@jest/globals': + specifier: ^29.7.0 + version: 29.7.0 + '@testing-library/dom': + specifier: ^10.4.0 + version: 10.4.0 + '@testing-library/jest-dom': + specifier: ^6.6.3 + version: 6.6.3 + '@testing-library/react': + specifier: ^16.0.1 + version: 16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@types/node': specifier: ^20 version: 20.0.0 @@ -87,12 +99,28 @@ importers: eslint-config-next: specifier: 14.2.13 version: 14.2.13(eslint@8.0.0)(typescript@5.0.2) + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@20.0.0)(ts-node@10.9.2(@types/node@20.0.0)(typescript@5.0.2)) + jest-environment-jsdom: + specifier: ^29.7.0 + version: 29.7.0 + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@20.0.0)(typescript@5.0.2) typescript: specifier: ^5 version: 5.0.2 packages: + '@adobe/css-tools@4.4.0': + resolution: {integrity: sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==} + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + '@ant-design/colors@7.1.0': resolution: {integrity: sha512-MMoDGWn1y9LdQJQSHiCC20x3uZ3CwQnv9QMz6pCmJOrqdgM9YxsoVVY0wtrdXbmfSgnV0KNk6zi09NAhMR2jvg==} @@ -136,10 +164,171 @@ packages: peerDependencies: react: '>=16.9.0' + '@babel/code-frame@7.26.2': + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.26.2': + resolution: {integrity: sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.26.0': + resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.26.2': + resolution: {integrity: sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.25.9': + resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.25.9': + resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.26.0': + resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.25.9': + resolution: {integrity: sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.25.9': + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.25.9': + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.25.9': + resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.26.0': + resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.26.2': + resolution: {integrity: sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-async-generators@7.8.4': + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-static-block@7.14.5': + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.26.0': + resolution: {integrity: sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-json-strings@7.8.3': + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.25.9': + resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-numeric-separator@7.10.4': + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-object-rest-spread@7.8.3': + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3': + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-chaining@7.8.3': + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-private-property-in-object@7.14.5': + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-top-level-await@7.14.5': + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.25.9': + resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/runtime@7.25.7': resolution: {integrity: sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==} engines: {node: '>=6.9.0'} + '@babel/template@7.25.9': + resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.25.9': + resolution: {integrity: sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.26.0': + resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@codemirror/autocomplete@6.18.1': resolution: {integrity: sha512-iWHdj/B1ethnHRTwZj+C1obmmuCzquH29EbcKr0qIjA9NfDeBDJ7vs+WOHsFeLeflE4o+dHfYndJloMKHUkWUA==} peerDependencies: @@ -181,6 +370,10 @@ packages: '@codemirror/view@6.34.1': resolution: {integrity: sha512-t1zK/l9UiRqwUNPm+pdIT0qzJlzuVckbTEMVNFhfWkGiBQClstzg+78vedCvLSX0xJEZ6lwZbPpnljL7L6iwMQ==} + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + '@ctrl/tinycolor@3.6.1': resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} engines: {node: '>=10'} @@ -218,6 +411,101 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + + '@jest/console@29.7.0': + resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/core@29.7.0': + resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/environment@29.7.0': + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect-utils@29.7.0': + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect@29.7.0': + resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/fake-timers@29.7.0': + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/globals@29.7.0': + resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/reporters@29.7.0': + resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/source-map@29.6.3': + resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-result@29.7.0': + resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-sequencer@29.7.0': + resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/transform@29.7.0': + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jridgewell/gen-mapping@0.3.5': + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@lezer/common@1.2.3': resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==} @@ -383,12 +671,90 @@ packages: '@rushstack/eslint-patch@1.10.4': resolution: {integrity: sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==} + '@sinclair/typebox@0.27.8': + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@10.3.0': + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} '@swc/helpers@0.5.5': resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} + '@testing-library/dom@10.4.0': + resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==} + engines: {node: '>=18'} + + '@testing-library/jest-dom@6.6.3': + resolution: {integrity: sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==} + engines: {node: '>=14', npm: '>=6', yarn: '>=1'} + + '@testing-library/react@16.0.1': + resolution: {integrity: sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg==} + engines: {node: '>=18'} + peerDependencies: + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 + '@types/react-dom': ^18.0.0 + react: ^18.0.0 + react-dom: ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@tootallnate/once@2.0.0': + resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} + engines: {node: '>= 10'} + + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.6.8': + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.20.6': + resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + + '@types/graceful-fs@4.1.9': + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/jsdom@20.0.1': + resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==} + '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} @@ -404,6 +770,18 @@ packages: '@types/react@18.3.8': resolution: {integrity: sha512-syBUrW3/XpnW4WJ41Pft+I+aPoDVbrBVQGEnbD7NijDGlVC+8gV/XKRY+7vMDlfPpbwYt0l1vd/Sj8bJGMbs9Q==} + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/tough-cookie@4.0.5': + resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.33': + resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + '@typescript-eslint/eslint-plugin@8.8.0': resolution: {integrity: sha512-wORFWjU30B2WJ/aXBfOm1LX9v9nyt9D3jsSOxC3cCaTQGCW5k4jNpmjFv3U7p/7s4yvdjHzwtv2Sd2dOyhjS0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -461,16 +839,31 @@ packages: resolution: {integrity: sha512-8mq51Lx6Hpmd7HnA2fcHQo3YgfX1qbccxQOgZcb4tvasu//zXRaA1j5ZRFeCw/VRAdFi4mRM9DnZw0Nu0Q2d1g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + abab@2.0.6: + resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} + deprecated: Use your platform's native atob() and btoa() methods instead + + acorn-globals@7.0.1: + resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + engines: {node: '>=0.4.0'} + acorn@8.12.1: resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} engines: {node: '>=0.4.0'} hasBin: true + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -478,6 +871,10 @@ packages: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -490,6 +887,10 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} @@ -500,12 +901,25 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} aria-query@5.1.3: resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + array-buffer-byte-length@1.0.1: resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} engines: {node: '>= 0.4'} @@ -544,6 +958,9 @@ packages: ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -556,6 +973,31 @@ packages: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} + babel-jest@29.7.0: + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + + babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + + babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + babel-preset-current-node-syntax@1.1.0: + resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==} + peerDependencies: + '@babel/core': ^7.0.0 + + babel-preset-jest@29.6.3: + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -572,6 +1014,17 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + browserslist@4.24.2: + resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} @@ -587,26 +1040,63 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + caniuse-lite@1.0.30001666: resolution: {integrity: sha512-gD14ICmoV5ZZM1OdzPWmpx+q4GyefaK06zi8hmfHV5xe4/2nOQX3+Dw5o+fSqOws2xVwL9j+anOPFwHzdEdV4g==} + caniuse-lite@1.0.30001676: + resolution: {integrity: sha512-Qz6zwGCiPghQXGJvgQAem79esjitvJ+CxSbSQkW9H/UX5hg8XM88d4lp2W+MEQ81j+Hip58Il+jGVdazk1z9cw==} + + chalk@3.0.0: + resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} + engines: {node: '>=8'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + chokidar@4.0.1: resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} engines: {node: '>= 14.16.0'} + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + cjs-module-lexer@1.4.1: + resolution: {integrity: sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==} + classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + codemirror@6.0.1: resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==} + collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -614,15 +1104,30 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + compute-scroll-into-view@3.1.0: resolution: {integrity: sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==} concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + copy-to-clipboard@3.3.3: resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + create-jest@29.7.0: + resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} @@ -630,12 +1135,29 @@ packages: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} + css.escape@1.5.1: + resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} + + cssom@0.3.8: + resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} + + cssom@0.5.0: + resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==} + + cssstyle@2.3.0: + resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==} + engines: {node: '>=8'} + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + data-urls@3.0.2: + resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==} + engines: {node: '>=12'} + data-view-buffer@1.0.1: resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} engines: {node: '>= 0.4'} @@ -668,6 +1190,17 @@ packages: supports-color: optional: true + decimal.js@10.4.3: + resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} + + dedent@1.5.3: + resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + deep-equal@2.2.3: resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==} engines: {node: '>= 0.4'} @@ -675,6 +1208,10 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -683,6 +1220,26 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -691,9 +1248,27 @@ packages: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + + dom-accessibility-api@0.6.3: + resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} + + domexception@4.0.0: + resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} + engines: {node: '>=12'} + deprecated: Use your platform's native DOMException instead + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + electron-to-chromium@1.5.50: + resolution: {integrity: sha512-eMVObiUQ2LdgeO1F/ySTXsvqvxb6ZH2zPGaMYsWzRDdOddUa77tdmI0ltg+L16UpbWdhPmuF3wIQYyQq65WfZw==} + + emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -708,9 +1283,16 @@ packages: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + err-code@3.0.1: resolution: {integrity: sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==} + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + es-abstract@1.23.3: resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} engines: {node: '>= 0.4'} @@ -745,10 +1327,23 @@ packages: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} engines: {node: '>= 0.4'} + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + eslint-config-next@14.2.13: resolution: {integrity: sha512-aro1EKAoyYchnO/3Tlo91hnNBO7QO7qnv/79MAFC+4Jq8TdUVKQlht5d2F+YjrePjdpOvfL+mV9JPfyYNwkk1g==} peerDependencies: @@ -850,6 +1445,11 @@ packages: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + esquery@1.6.0: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} @@ -866,6 +1466,18 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + exit@0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + + expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -882,6 +1494,9 @@ packages: fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -890,6 +1505,10 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + flat-cache@3.2.0: resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} engines: {node: ^10.12.0 || >=12.0.0} @@ -904,9 +1523,18 @@ packages: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} + form-data@4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} + engines: {node: '>= 6'} + fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} @@ -920,13 +1548,29 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + get-browser-rtc@1.1.0: resolution: {integrity: sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ==} + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + get-intrinsic@1.2.4: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + get-symbol-description@1.0.2: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} @@ -951,6 +1595,10 @@ packages: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + globals@13.24.0: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} @@ -994,6 +1642,29 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + html-encoding-sniffer@3.0.0: + resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} + engines: {node: '>=12'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + http-proxy-agent@5.0.0: + resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} + engines: {node: '>= 6'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -1012,10 +1683,19 @@ packages: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} + import-local@3.2.0: + resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} + engines: {node: '>=8'} + hasBin: true + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. @@ -1035,6 +1715,9 @@ packages: resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} engines: {node: '>= 0.4'} + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-async-function@2.0.0: resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} engines: {node: '>= 0.4'} @@ -1076,6 +1759,10 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + is-generator-function@1.0.10: resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} engines: {node: '>= 0.4'} @@ -1100,6 +1787,9 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} @@ -1112,6 +1802,10 @@ packages: resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} engines: {node: '>= 0.4'} + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + is-string@1.0.7: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} @@ -1144,6 +1838,30 @@ packages: isomorphic.js@0.2.5: resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@6.0.3: + resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} + engines: {node: '>=10'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + + istanbul-reports@3.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + engines: {node: '>=8'} + iterator.prototype@1.1.2: resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} @@ -1151,16 +1869,175 @@ packages: resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} engines: {node: '>=14'} + jest-changed-files@29.7.0: + resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-circus@29.7.0: + resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-cli@29.7.0: + resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@29.7.0: + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + + jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-docblock@29.7.0: + resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-each@29.7.0: + resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-environment-jsdom@29.7.0: + resolution: {integrity: sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + + jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-leak-detector@29.7.0: + resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-pnp-resolver@1.2.3: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + + jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve-dependencies@29.7.0: + resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve@29.7.0: + resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runner@29.7.0: + resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runtime@29.7.0: + resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-snapshot@29.7.0: + resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-watcher@29.7.0: + resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest@29.7.0: + resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true + jsdom@20.0.3: + resolution: {integrity: sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==} + engines: {node: '>=14'} + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + + jsesc@3.0.2: + resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} + engines: {node: '>=6'} + hasBin: true + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -1174,6 +2051,11 @@ packages: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} @@ -1181,6 +2063,10 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + language-subtag-registry@0.3.23: resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} @@ -1188,6 +2074,10 @@ packages: resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} engines: {node: '>=0.10'} + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -1197,9 +2087,19 @@ packages: engines: {node: '>=16'} hasBin: true + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -1207,6 +2107,26 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1215,6 +2135,22 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -1258,6 +2194,23 @@ packages: sass: optional: true + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + + node-releases@2.0.18: + resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + nwsapi@2.2.13: + resolution: {integrity: sha512-cTGB9ptp9dY9A5VbMSe7fQBcl/tt22Vcqdq8+eN93rblOuE0aCFu4aZ2vMwct/2t+lFnosm8RkQW1I0Omb1UtQ==} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -1297,14 +2250,45 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parse5@7.2.1: + resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -1327,6 +2311,14 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + possible-typed-array-names@1.0.0: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} @@ -1339,17 +2331,38 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + progress@2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + psl@1.9.0: + resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + + querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -1592,6 +2605,9 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} @@ -1615,6 +2631,10 @@ packages: resolution: {integrity: sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw==} engines: {node: '>= 14.16.0'} + redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + reflect.getprototypeof@1.0.6: resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} engines: {node: '>= 0.4'} @@ -1630,16 +2650,35 @@ packages: resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} engines: {node: '>=8'} + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + resize-observer-polyfill@1.5.1: resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve.exports@2.0.2: + resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} + engines: {node: '>=10'} + resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -1671,11 +2710,18 @@ packages: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sass@1.79.2: resolution: {integrity: sha512-YmT1aoF1MwHsZEu/eXhbAJNsPGAhNP4UixW9ckEwWCvPcVdVF0/C104OGDVEqtoctKq0N+wM20O/rj+sSPsWeg==} engines: {node: '>=14.0.0'} hasBin: true + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + scheduler@0.23.2: resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} @@ -1711,6 +2757,9 @@ packages: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} engines: {node: '>= 0.4'} + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -1718,10 +2767,31 @@ packages: simple-peer@9.11.1: resolution: {integrity: sha512-D1SaWpOW8afq1CZGWB8xTfrT3FekjQmPValrqncJMX7QFl8YwhrPTZvMCANLtgBwwdS+7zURyqxDDEmY558tTw==} + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + stop-iteration-iterator@1.0.0: resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} engines: {node: '>= 0.4'} @@ -1733,6 +2803,10 @@ packages: string-convert@0.2.1: resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==} + string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -1777,6 +2851,18 @@ packages: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -1804,14 +2890,25 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -1819,6 +2916,9 @@ packages: resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} engines: {node: '>=12.22'} + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -1826,12 +2926,34 @@ packages: toggle-selection@1.0.6: resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} + tough-cookie@4.1.4: + resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} + engines: {node: '>=6'} + + tr46@3.0.0: + resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==} + engines: {node: '>=12'} + ts-api-utils@1.3.0: resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} @@ -1842,10 +2964,18 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + type-fest@0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + typed-array-buffer@1.0.2: resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} @@ -1873,18 +3003,61 @@ packages: unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + + update-browserslist-db@1.1.1: + resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + v8-compile-cache@2.4.0: resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==} + v8-to-istanbul@9.3.0: + resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} + engines: {node: '>=10.12.0'} + w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + w3c-xmlserializer@4.0.0: + resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} + engines: {node: '>=14'} + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + whatwg-encoding@2.0.0: + resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} + engines: {node: '>=12'} + + whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + + whatwg-url@11.0.0: + resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==} + engines: {node: '>=12'} + which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} @@ -1920,6 +3093,10 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} @@ -1932,6 +3109,13 @@ packages: utf-8-validate: optional: true + xml-name-validator@4.0.0: + resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} + engines: {node: '>=12'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + y-codemirror.next@0.3.5: resolution: {integrity: sha512-VluNu3e5HfEXybnypnsGwKAj+fKLd4iAnR7JuX1Sfyydmn1jCBS5wwEL/uS04Ch2ib0DnMAOF6ZRR/8kK3wyGw==} peerDependencies: @@ -1952,32 +3136,62 @@ packages: peerDependencies: yjs: ^13.6.8 + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + yjs@13.6.20: resolution: {integrity: sha512-Z2YZI+SYqK7XdWlloI3lhMiKnCdFCVC4PchpdO+mCYwtiTwncjUbnRK9R1JmkNfdmHyDXuWN3ibJAt0wsqTbLQ==} engines: {node: '>=16.0.0', npm: '>=8.0.0'} + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + snapshots: + '@adobe/css-tools@4.4.0': {} + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + '@ant-design/colors@7.1.0': dependencies: '@ctrl/tinycolor': 3.6.1 - '@ant-design/cssinjs-utils@1.1.0(react-dom@18.2.0)(react@18.2.0)': + '@ant-design/cssinjs-utils@1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0)(react@18.2.0) + '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@babel/runtime': 7.25.7 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@ant-design/cssinjs@1.21.1(react-dom@18.2.0)(react@18.2.0)': + '@ant-design/cssinjs@1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 '@emotion/hash': 0.8.0 '@emotion/unitless': 0.7.5 classnames: 2.5.1 csstype: 3.1.3 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) stylis: 4.3.4 @@ -1988,21 +3202,21 @@ snapshots: '@ant-design/icons-svg@4.4.2': {} - '@ant-design/icons@5.5.1(react-dom@18.2.0)(react@18.2.0)': + '@ant-design/icons@5.5.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@ant-design/colors': 7.1.0 '@ant-design/icons-svg': 4.4.2 '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@ant-design/nextjs-registry@1.0.1(@ant-design/cssinjs@1.21.1)(antd@5.20.6)(next@14.2.13)(react-dom@18.2.0)(react@18.2.0)': + '@ant-design/nextjs-registry@1.0.1(@ant-design/cssinjs@1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(antd@5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(next@14.2.13(@babel/core@7.26.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0)(react@18.2.0) - antd: 5.20.6(react-dom@18.2.0)(react@18.2.0) - next: 14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2) + '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + antd: 5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + next: 14.2.13(@babel/core@7.26.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -2015,23 +3229,210 @@ snapshots: resize-observer-polyfill: 1.5.1 throttle-debounce: 5.0.2 - '@babel/runtime@7.25.7': + '@babel/code-frame@7.26.2': dependencies: - regenerator-runtime: 0.14.1 + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.0 - '@codemirror/autocomplete@6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3)': - dependencies: - '@codemirror/language': 6.10.3 - '@codemirror/state': 6.4.1 - '@codemirror/view': 6.34.1 - '@lezer/common': 1.2.3 + '@babel/compat-data@7.26.2': {} + + '@babel/core@7.26.0': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.2 + '@babel/helper-compilation-targets': 7.25.9 + '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) + '@babel/helpers': 7.26.0 + '@babel/parser': 7.26.2 + '@babel/template': 7.25.9 + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + convert-source-map: 2.0.0 + debug: 4.3.7 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color - '@codemirror/commands@6.7.1': + '@babel/generator@7.26.2': dependencies: - '@codemirror/language': 6.10.3 - '@codemirror/state': 6.4.1 - '@codemirror/view': 6.34.1 - '@lezer/common': 1.2.3 + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.0.2 + + '@babel/helper-compilation-targets@7.25.9': + dependencies: + '@babel/compat-data': 7.26.2 + '@babel/helper-validator-option': 7.25.9 + browserslist: 4.24.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-module-imports@7.25.9': + dependencies: + '@babel/traverse': 7.25.9 + '@babel/types': 7.26.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + '@babel/traverse': 7.25.9 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.25.9': {} + + '@babel/helper-string-parser@7.25.9': {} + + '@babel/helper-validator-identifier@7.25.9': {} + + '@babel/helper-validator-option@7.25.9': {} + + '@babel/helpers@7.26.0': + dependencies: + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 + + '@babel/parser@7.26.2': + dependencies: + '@babel/types': 7.26.0 + + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.0)': + dependencies: + '@babel/core': 7.26.0 + '@babel/helper-plugin-utils': 7.25.9 + + '@babel/runtime@7.25.7': + dependencies: + regenerator-runtime: 0.14.1 + + '@babel/template@7.25.9': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + + '@babel/traverse@7.25.9': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/generator': 7.26.2 + '@babel/parser': 7.26.2 + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 + debug: 4.3.7 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.26.0': + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + + '@bcoe/v8-coverage@0.2.3': {} + + '@codemirror/autocomplete@6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3)': + dependencies: + '@codemirror/language': 6.10.3 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + '@lezer/common': 1.2.3 + + '@codemirror/commands@6.7.1': + dependencies: + '@codemirror/language': 6.10.3 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + '@lezer/common': 1.2.3 '@codemirror/lang-cpp@6.0.2': dependencies: @@ -2102,6 +3503,10 @@ snapshots: style-mod: 4.1.2 w3c-keyname: 2.2.8 + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + '@ctrl/tinycolor@3.6.1': {} '@emotion/hash@0.8.0': {} @@ -2148,6 +3553,200 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@istanbuljs/load-nyc-config@1.1.0': + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + + '@istanbuljs/schema@0.1.3': {} + + '@jest/console@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.0.0 + chalk: 4.1.2 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@20.0.0)(typescript@5.0.2))': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.0.0 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.0.0)(ts-node@10.9.2(@types/node@20.0.0)(typescript@5.0.2)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + + '@jest/environment@29.7.0': + dependencies: + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.0.0 + jest-mock: 29.7.0 + + '@jest/expect-utils@29.7.0': + dependencies: + jest-get-type: 29.6.3 + + '@jest/expect@29.7.0': + dependencies: + expect: 29.7.0 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + + '@jest/fake-timers@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@sinonjs/fake-timers': 10.3.0 + '@types/node': 20.0.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + '@jest/globals@29.7.0': + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/types': 29.6.3 + jest-mock: 29.7.0 + transitivePeerDependencies: + - supports-color + + '@jest/reporters@29.7.0': + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.25 + '@types/node': 20.0.0 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.3 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.7 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + jest-worker: 29.7.0 + slash: 3.0.0 + string-length: 4.0.2 + strip-ansi: 6.0.1 + v8-to-istanbul: 9.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.8 + + '@jest/source-map@29.6.3': + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + callsites: 3.1.0 + graceful-fs: 4.2.11 + + '@jest/test-result@29.7.0': + dependencies: + '@jest/console': 29.7.0 + '@jest/types': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.2 + + '@jest/test-sequencer@29.7.0': + dependencies: + '@jest/test-result': 29.7.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + slash: 3.0.0 + + '@jest/transform@29.7.0': + dependencies: + '@babel/core': 7.26.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.25 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + micromatch: 4.0.8 + pirates: 4.0.6 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 20.0.0 + '@types/yargs': 17.0.33 + chalk: 4.1.2 + + '@jridgewell/gen-mapping@0.3.5': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + '@lezer/common@1.2.3': {} '@lezer/cpp@1.1.2': @@ -2242,19 +3841,19 @@ snapshots: dependencies: '@babel/runtime': 7.25.7 - '@rc-component/color-picker@2.0.1(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/color-picker@2.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@ant-design/fast-color': 2.0.6 '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/context@1.4.0(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/context@1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -2262,48 +3861,48 @@ snapshots: dependencies: '@babel/runtime': 7.25.7 - '@rc-component/mutate-observer@1.1.0(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/mutate-observer@1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/portal@1.1.2(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/portal@1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/qrcode@1.0.0(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/qrcode@1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/tour@1.15.1(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/tour@1.15.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/trigger@2.2.3(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/trigger@2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -2311,6 +3910,16 @@ snapshots: '@rushstack/eslint-patch@1.10.4': {} + '@sinclair/typebox@0.27.8': {} + + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@10.3.0': + dependencies: + '@sinonjs/commons': 3.0.1 + '@swc/counter@0.1.3': {} '@swc/helpers@0.5.5': @@ -2318,6 +3927,90 @@ snapshots: '@swc/counter': 0.1.3 tslib: 2.7.0 + '@testing-library/dom@10.4.0': + dependencies: + '@babel/code-frame': 7.26.2 + '@babel/runtime': 7.25.7 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + chalk: 4.1.2 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + pretty-format: 27.5.1 + + '@testing-library/jest-dom@6.6.3': + dependencies: + '@adobe/css-tools': 4.4.0 + aria-query: 5.1.3 + chalk: 3.0.0 + css.escape: 1.5.1 + dom-accessibility-api: 0.6.3 + lodash: 4.17.21 + redent: 3.0.0 + + '@testing-library/react@16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + dependencies: + '@babel/runtime': 7.25.7 + '@testing-library/dom': 10.4.0 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + '@types/react': 18.3.8 + '@types/react-dom': 18.3.0 + + '@tootallnate/once@2.0.0': {} + + '@tsconfig/node10@1.0.11': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + + '@types/aria-query@5.0.4': {} + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.6 + + '@types/babel__generator@7.6.8': + dependencies: + '@babel/types': 7.26.0 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.26.2 + '@babel/types': 7.26.0 + + '@types/babel__traverse@7.20.6': + dependencies: + '@babel/types': 7.26.0 + + '@types/graceful-fs@4.1.9': + dependencies: + '@types/node': 20.0.0 + + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + + '@types/jsdom@20.0.1': + dependencies: + '@types/node': 20.0.0 + '@types/tough-cookie': 4.0.5 + parse5: 7.2.1 + '@types/json5@0.0.29': {} '@types/node@20.0.0': {} @@ -2333,7 +4026,17 @@ snapshots: '@types/prop-types': 15.7.13 csstype: 3.1.3 - '@typescript-eslint/eslint-plugin@8.8.0(@typescript-eslint/parser@8.8.0)(eslint@8.0.0)(typescript@5.0.2)': + '@types/stack-utils@2.0.3': {} + + '@types/tough-cookie@4.0.5': {} + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.33': + dependencies: + '@types/yargs-parser': 21.0.3 + + '@typescript-eslint/eslint-plugin@8.8.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint@8.0.0)(typescript@5.0.2)': dependencies: '@eslint-community/regexpp': 4.11.1 '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) @@ -2346,6 +4049,7 @@ snapshots: ignore: 5.3.2 natural-compare: 1.4.0 ts-api-utils: 1.3.0(typescript@5.0.2) + optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - supports-color @@ -2358,6 +4062,7 @@ snapshots: '@typescript-eslint/visitor-keys': 8.8.0 debug: 4.3.7 eslint: 8.0.0 + optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - supports-color @@ -2373,6 +4078,7 @@ snapshots: '@typescript-eslint/utils': 8.8.0(eslint@8.0.0)(typescript@5.0.2) debug: 4.3.7 ts-api-utils: 1.3.0(typescript@5.0.2) + optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - eslint @@ -2390,6 +4096,7 @@ snapshots: minimatch: 9.0.5 semver: 7.6.3 ts-api-utils: 1.3.0(typescript@5.0.2) + optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - supports-color @@ -2410,12 +4117,29 @@ snapshots: '@typescript-eslint/types': 8.8.0 eslint-visitor-keys: 3.4.3 + abab@2.0.6: {} + + acorn-globals@7.0.1: + dependencies: + acorn: 8.12.1 + acorn-walk: 8.3.4 + acorn-jsx@5.3.2(acorn@8.12.1): dependencies: acorn: 8.12.1 + acorn-walk@8.3.4: + dependencies: + acorn: 8.12.1 + acorn@8.12.1: {} + agent-base@6.0.2: + dependencies: + debug: 4.3.7 + transitivePeerDependencies: + - supports-color + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -2425,6 +4149,10 @@ snapshots: ansi-colors@4.1.3: {} + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + ansi-regex@5.0.1: {} ansi-regex@6.1.0: {} @@ -2433,57 +4161,59 @@ snapshots: dependencies: color-convert: 2.0.1 + ansi-styles@5.2.0: {} + ansi-styles@6.2.1: {} - antd@5.20.6(react-dom@18.2.0)(react@18.2.0): + antd@5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@ant-design/colors': 7.1.0 - '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0)(react@18.2.0) - '@ant-design/cssinjs-utils': 1.1.0(react-dom@18.2.0)(react@18.2.0) - '@ant-design/icons': 5.5.1(react-dom@18.2.0)(react@18.2.0) + '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@ant-design/cssinjs-utils': 1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@ant-design/icons': 5.5.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@ant-design/react-slick': 1.1.2(react@18.2.0) '@babel/runtime': 7.25.7 '@ctrl/tinycolor': 3.6.1 - '@rc-component/color-picker': 2.0.1(react-dom@18.2.0)(react@18.2.0) - '@rc-component/mutate-observer': 1.1.0(react-dom@18.2.0)(react@18.2.0) - '@rc-component/qrcode': 1.0.0(react-dom@18.2.0)(react@18.2.0) - '@rc-component/tour': 1.15.1(react-dom@18.2.0)(react@18.2.0) - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/color-picker': 2.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/mutate-observer': 1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/qrcode': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/tour': 1.15.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 copy-to-clipboard: 3.3.3 dayjs: 1.11.13 - rc-cascader: 3.28.1(react-dom@18.2.0)(react@18.2.0) - rc-checkbox: 3.3.0(react-dom@18.2.0)(react@18.2.0) - rc-collapse: 3.7.3(react-dom@18.2.0)(react@18.2.0) - rc-dialog: 9.5.2(react-dom@18.2.0)(react@18.2.0) - rc-drawer: 7.2.0(react-dom@18.2.0)(react@18.2.0) - rc-dropdown: 4.2.0(react-dom@18.2.0)(react@18.2.0) - rc-field-form: 2.4.0(react-dom@18.2.0)(react@18.2.0) - rc-image: 7.9.0(react-dom@18.2.0)(react@18.2.0) - rc-input: 1.6.3(react-dom@18.2.0)(react@18.2.0) - rc-input-number: 9.2.0(react-dom@18.2.0)(react@18.2.0) - rc-mentions: 2.15.0(react-dom@18.2.0)(react@18.2.0) - rc-menu: 9.14.1(react-dom@18.2.0)(react@18.2.0) - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-notification: 5.6.2(react-dom@18.2.0)(react@18.2.0) - rc-pagination: 4.2.0(react-dom@18.2.0)(react@18.2.0) - rc-picker: 4.6.15(dayjs@1.11.13)(react-dom@18.2.0)(react@18.2.0) - rc-progress: 4.0.0(react-dom@18.2.0)(react@18.2.0) - rc-rate: 2.13.0(react-dom@18.2.0)(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-segmented: 2.3.0(react-dom@18.2.0)(react@18.2.0) - rc-select: 14.15.2(react-dom@18.2.0)(react@18.2.0) - rc-slider: 11.1.6(react-dom@18.2.0)(react@18.2.0) - rc-steps: 6.0.1(react-dom@18.2.0)(react@18.2.0) - rc-switch: 4.1.0(react-dom@18.2.0)(react@18.2.0) - rc-table: 7.45.7(react-dom@18.2.0)(react@18.2.0) - rc-tabs: 15.1.1(react-dom@18.2.0)(react@18.2.0) - rc-textarea: 1.8.2(react-dom@18.2.0)(react@18.2.0) - rc-tooltip: 6.2.1(react-dom@18.2.0)(react@18.2.0) - rc-tree: 5.9.0(react-dom@18.2.0)(react@18.2.0) - rc-tree-select: 5.23.0(react-dom@18.2.0)(react@18.2.0) - rc-upload: 4.7.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-cascader: 3.28.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-checkbox: 3.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-collapse: 3.7.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-dialog: 9.5.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-drawer: 7.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-dropdown: 4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-field-form: 2.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-image: 7.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-input: 1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-input-number: 9.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-mentions: 2.15.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-menu: 9.14.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-notification: 5.6.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-pagination: 4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-picker: 4.6.15(dayjs@1.11.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-progress: 4.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-rate: 2.13.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-segmented: 2.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-select: 14.15.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-slider: 11.1.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-steps: 6.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-switch: 4.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-table: 7.45.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-tabs: 15.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-textarea: 1.8.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-tooltip: 6.2.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-tree: 5.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-tree-select: 5.23.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-upload: 4.7.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) scroll-into-view-if-needed: 3.1.0 @@ -2493,12 +4223,27 @@ snapshots: - luxon - moment + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + arg@4.1.3: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + argparse@2.0.1: {} aria-query@5.1.3: dependencies: deep-equal: 2.2.3 + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + array-buffer-byte-length@1.0.1: dependencies: call-bind: 1.0.7 @@ -2568,6 +4313,8 @@ snapshots: ast-types-flow@0.0.8: {} + asynckit@0.4.0: {} + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.0.0 @@ -2576,6 +4323,61 @@ snapshots: axobject-query@4.1.0: {} + babel-jest@29.7.0(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + '@jest/transform': 29.7.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.26.0) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-istanbul@6.1.1: + dependencies: + '@babel/helper-plugin-utils': 7.25.9 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jest-hoist@29.6.3: + dependencies: + '@babel/template': 7.25.9 + '@babel/types': 7.26.0 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.20.6 + + babel-preset-current-node-syntax@1.1.0(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.26.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.26.0) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.26.0) + '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.26.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.26.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.26.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.26.0) + + babel-preset-jest@29.6.3(@babel/core@7.26.0): + dependencies: + '@babel/core': 7.26.0 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.0) + balanced-match@1.0.2: {} base64-js@1.5.1: {} @@ -2593,6 +4395,19 @@ snapshots: dependencies: fill-range: 7.1.1 + browserslist@4.24.2: + dependencies: + caniuse-lite: 1.0.30001676 + electron-to-chromium: 1.5.50 + node-releases: 2.0.18 + update-browserslist-db: 1.1.1(browserslist@4.24.2) + + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + + buffer-from@1.1.2: {} + buffer@6.0.3: dependencies: base64-js: 1.5.1 @@ -2612,21 +4427,46 @@ snapshots: callsites@3.1.0: {} + camelcase@5.3.1: {} + + camelcase@6.3.0: {} + caniuse-lite@1.0.30001666: {} + caniuse-lite@1.0.30001676: {} + + chalk@3.0.0: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 + char-regex@1.0.2: {} + chokidar@4.0.1: dependencies: readdirp: 4.0.1 + ci-info@3.9.0: {} + + cjs-module-lexer@1.4.1: {} + classnames@2.5.1: {} client-only@0.0.1: {} + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + co@4.6.0: {} + codemirror@6.0.1(@lezer/common@1.2.3): dependencies: '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3) @@ -2639,20 +4479,45 @@ snapshots: transitivePeerDependencies: - '@lezer/common' + collect-v8-coverage@1.0.2: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 color-name@1.1.4: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + compute-scroll-into-view@3.1.0: {} concat-map@0.0.1: {} + convert-source-map@2.0.0: {} + copy-to-clipboard@3.3.3: dependencies: toggle-selection: 1.0.6 + create-jest@29.7.0(@types/node@20.0.0)(ts-node@10.9.2(@types/node@20.0.0)(typescript@5.0.2)): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@20.0.0)(ts-node@10.9.2(@types/node@20.0.0)(typescript@5.0.2)) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + create-require@1.1.1: {} + crelt@1.0.6: {} cross-spawn@7.0.3: @@ -2661,10 +4526,26 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + css.escape@1.5.1: {} + + cssom@0.3.8: {} + + cssom@0.5.0: {} + + cssstyle@2.3.0: + dependencies: + cssom: 0.3.8 + csstype@3.1.3: {} damerau-levenshtein@1.0.8: {} + data-urls@3.0.2: + dependencies: + abab: 2.0.6 + whatwg-mimetype: 3.0.0 + whatwg-url: 11.0.0 + data-view-buffer@1.0.1: dependencies: call-bind: 1.0.7 @@ -2693,6 +4574,10 @@ snapshots: dependencies: ms: 2.1.3 + decimal.js@10.4.3: {} + + dedent@1.5.3: {} + deep-equal@2.2.3: dependencies: array-buffer-byte-length: 1.0.1 @@ -2716,6 +4601,8 @@ snapshots: deep-is@0.1.4: {} + deepmerge@4.3.1: {} + define-data-property@1.1.4: dependencies: es-define-property: 1.0.0 @@ -2728,6 +4615,16 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + delayed-stream@1.0.0: {} + + dequal@2.0.3: {} + + detect-newline@3.1.0: {} + + diff-sequences@29.6.3: {} + + diff@4.0.2: {} + doctrine@2.1.0: dependencies: esutils: 2.0.3 @@ -2736,8 +4633,20 @@ snapshots: dependencies: esutils: 2.0.3 + dom-accessibility-api@0.5.16: {} + + dom-accessibility-api@0.6.3: {} + + domexception@4.0.0: + dependencies: + webidl-conversions: 7.0.0 + eastasianwidth@0.2.0: {} + electron-to-chromium@1.5.50: {} + + emittery@0.13.1: {} + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -2752,8 +4661,14 @@ snapshots: ansi-colors: 4.1.3 strip-ansi: 6.0.1 + entities@4.5.0: {} + err-code@3.0.1: {} + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + es-abstract@1.23.3: dependencies: array-buffer-byte-length: 1.0.1 @@ -2858,21 +4773,34 @@ snapshots: is-date-object: 1.0.5 is-symbol: 1.0.4 + escalade@3.2.0: {} + + escape-string-regexp@2.0.0: {} + escape-string-regexp@4.0.0: {} + escodegen@2.1.0: + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + eslint-config-next@14.2.13(eslint@8.0.0)(typescript@5.0.2): dependencies: '@next/eslint-plugin-next': 14.2.13 '@rushstack/eslint-patch': 1.10.4 - '@typescript-eslint/eslint-plugin': 8.8.0(@typescript-eslint/parser@8.8.0)(eslint@8.0.0)(typescript@5.0.2) + '@typescript-eslint/eslint-plugin': 8.8.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint@8.0.0)(typescript@5.0.2) '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) eslint: 8.0.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0) - eslint-plugin-import: 2.30.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0) + eslint-plugin-import: 2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) eslint-plugin-jsx-a11y: 6.10.0(eslint@8.0.0) eslint-plugin-react: 7.37.1(eslint@8.0.0) eslint-plugin-react-hooks: 4.6.2(eslint@8.0.0) + optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - eslint-import-resolver-webpack @@ -2887,38 +4815,39 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0): + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 8.0.0 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) - eslint-plugin-import: 2.30.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0))(eslint@8.0.0) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 is-glob: 4.0.3 + optionalDependencies: + eslint-plugin-import: 2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-node - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0))(eslint@8.0.0): dependencies: - '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) eslint: 8.0.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): + eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): dependencies: '@rtsao/scc': 1.1.0 - '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 array.prototype.flat: 1.3.2 @@ -2927,7 +4856,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.0.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0))(eslint@8.0.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -2937,6 +4866,8 @@ snapshots: object.values: 1.2.0 semver: 6.3.1 tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -3051,6 +4982,8 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.12.1) eslint-visitor-keys: 3.4.3 + esprima@4.0.1: {} + esquery@1.6.0: dependencies: estraverse: 5.3.0 @@ -3063,6 +4996,28 @@ snapshots: esutils@2.0.3: {} + execa@5.1.1: + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + exit@0.1.2: {} + + expect@29.7.0: + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + fast-deep-equal@3.1.3: {} fast-glob@3.3.2: @@ -3081,6 +5036,10 @@ snapshots: dependencies: reusify: 1.0.4 + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + file-entry-cache@6.0.1: dependencies: flat-cache: 3.2.0 @@ -3089,6 +5048,11 @@ snapshots: dependencies: to-regex-range: 5.0.1 + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + flat-cache@3.2.0: dependencies: flatted: 3.3.1 @@ -3106,8 +5070,17 @@ snapshots: cross-spawn: 7.0.3 signal-exit: 4.1.0 + form-data@4.0.1: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + fs.realpath@1.0.0: {} + fsevents@2.3.3: + optional: true + function-bind@1.1.2: {} function.prototype.name@1.1.6: @@ -3121,8 +5094,12 @@ snapshots: functions-have-names@1.2.3: {} + gensync@1.0.0-beta.2: {} + get-browser-rtc@1.1.0: {} + get-caller-file@2.0.5: {} + get-intrinsic@1.2.4: dependencies: es-errors: 1.3.0 @@ -3131,6 +5108,10 @@ snapshots: has-symbols: 1.0.3 hasown: 2.0.2 + get-package-type@0.1.0: {} + + get-stream@6.0.1: {} + get-symbol-description@1.0.2: dependencies: call-bind: 1.0.7 @@ -3166,6 +5147,8 @@ snapshots: once: 1.4.0 path-is-absolute: 1.0.1 + globals@11.12.0: {} + globals@13.24.0: dependencies: type-fest: 0.20.2 @@ -3203,6 +5186,33 @@ snapshots: dependencies: function-bind: 1.1.2 + html-encoding-sniffer@3.0.0: + dependencies: + whatwg-encoding: 2.0.0 + + html-escaper@2.0.2: {} + + http-proxy-agent@5.0.0: + dependencies: + '@tootallnate/once': 2.0.0 + agent-base: 6.0.2 + debug: 4.3.7 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.3.7 + transitivePeerDependencies: + - supports-color + + human-signals@2.1.0: {} + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + ieee754@1.2.1: {} ignore@4.0.6: {} @@ -3216,8 +5226,15 @@ snapshots: parent-module: 1.0.1 resolve-from: 4.0.0 + import-local@3.2.0: + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + imurmurhash@0.1.4: {} + indent-string@4.0.0: {} + inflight@1.0.6: dependencies: once: 1.4.0 @@ -3241,6 +5258,8 @@ snapshots: call-bind: 1.0.7 get-intrinsic: 1.2.4 + is-arrayish@0.2.1: {} + is-async-function@2.0.0: dependencies: has-tostringtag: 1.0.2 @@ -3264,102 +5283,515 @@ snapshots: dependencies: hasown: 2.0.2 - is-data-view@1.0.1: + is-data-view@1.0.1: + dependencies: + is-typed-array: 1.1.13 + + is-date-object@1.0.5: + dependencies: + has-tostringtag: 1.0.2 + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.0.2: + dependencies: + call-bind: 1.0.7 + + is-fullwidth-code-point@3.0.0: {} + + is-generator-fn@2.1.0: {} + + is-generator-function@1.0.10: + dependencies: + has-tostringtag: 1.0.2 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-potential-custom-element-name@1.0.1: {} + + is-regex@1.1.4: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.3: + dependencies: + call-bind: 1.0.7 + + is-stream@2.0.1: {} + + is-string@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + + is-symbol@1.0.4: + dependencies: + has-symbols: 1.0.3 + + is-typed-array@1.1.13: + dependencies: + which-typed-array: 1.1.15 + + is-weakmap@2.0.2: {} + + is-weakref@1.0.2: + dependencies: + call-bind: 1.0.7 + + is-weakset@2.0.3: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + isomorphic.js@0.2.5: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-instrument@5.2.1: + dependencies: + '@babel/core': 7.26.0 + '@babel/parser': 7.26.2 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + istanbul-lib-instrument@6.0.3: + dependencies: + '@babel/core': 7.26.0 + '@babel/parser': 7.26.2 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 7.6.3 + transitivePeerDependencies: + - supports-color + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@4.0.1: + dependencies: + debug: 4.3.7 + istanbul-lib-coverage: 3.2.2 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.1.7: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + iterator.prototype@1.1.2: + dependencies: + define-properties: 1.2.1 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + reflect.getprototypeof: 1.0.6 + set-function-name: 2.0.2 + + jackspeak@2.3.6: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jest-changed-files@29.7.0: + dependencies: + execa: 5.1.1 + jest-util: 29.7.0 + p-limit: 3.1.0 + + jest-circus@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.0.0 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.5.3 + is-generator-fn: 2.1.0 + jest-each: 29.7.0 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + p-limit: 3.1.0 + pretty-format: 29.7.0 + pure-rand: 6.1.0 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-cli@29.7.0(@types/node@20.0.0)(ts-node@10.9.2(@types/node@20.0.0)(typescript@5.0.2)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.0.0)(typescript@5.0.2)) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@20.0.0)(ts-node@10.9.2(@types/node@20.0.0)(typescript@5.0.2)) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@20.0.0)(ts-node@10.9.2(@types/node@20.0.0)(typescript@5.0.2)) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + jest-config@29.7.0(@types/node@20.0.0)(ts-node@10.9.2(@types/node@20.0.0)(typescript@5.0.2)): + dependencies: + '@babel/core': 7.26.0 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.26.0) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 20.0.0 + ts-node: 10.9.2(@types/node@20.0.0)(typescript@5.0.2) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-diff@29.7.0: dependencies: - is-typed-array: 1.1.13 + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 - is-date-object@1.0.5: + jest-docblock@29.7.0: dependencies: - has-tostringtag: 1.0.2 + detect-newline: 3.1.0 - is-extglob@2.1.1: {} + jest-each@29.7.0: + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + jest-get-type: 29.6.3 + jest-util: 29.7.0 + pretty-format: 29.7.0 + + jest-environment-jsdom@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/jsdom': 20.0.1 + '@types/node': 20.0.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + jsdom: 20.0.3 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate - is-finalizationregistry@1.0.2: + jest-environment-node@29.7.0: dependencies: - call-bind: 1.0.7 + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.0.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 - is-fullwidth-code-point@3.0.0: {} + jest-get-type@29.6.3: {} - is-generator-function@1.0.10: + jest-haste-map@29.7.0: dependencies: - has-tostringtag: 1.0.2 + '@jest/types': 29.6.3 + '@types/graceful-fs': 4.1.9 + '@types/node': 20.0.0 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + jest-worker: 29.7.0 + micromatch: 4.0.8 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 - is-glob@4.0.3: + jest-leak-detector@29.7.0: dependencies: - is-extglob: 2.1.1 - - is-map@2.0.3: {} + jest-get-type: 29.6.3 + pretty-format: 29.7.0 - is-negative-zero@2.0.3: {} - - is-number-object@1.0.7: + jest-matcher-utils@29.7.0: dependencies: - has-tostringtag: 1.0.2 + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 - is-number@7.0.0: {} + jest-message-util@29.7.0: + dependencies: + '@babel/code-frame': 7.26.2 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 - is-regex@1.1.4: + jest-mock@29.7.0: dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 + '@jest/types': 29.6.3 + '@types/node': 20.0.0 + jest-util: 29.7.0 - is-set@2.0.3: {} + jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): + optionalDependencies: + jest-resolve: 29.7.0 - is-shared-array-buffer@1.0.3: + jest-regex-util@29.6.3: {} + + jest-resolve-dependencies@29.7.0: dependencies: - call-bind: 1.0.7 + jest-regex-util: 29.6.3 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color - is-string@1.0.7: + jest-resolve@29.7.0: dependencies: - has-tostringtag: 1.0.2 + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) + jest-util: 29.7.0 + jest-validate: 29.7.0 + resolve: 1.22.8 + resolve.exports: 2.0.2 + slash: 3.0.0 - is-symbol@1.0.4: + jest-runner@29.7.0: dependencies: - has-symbols: 1.0.3 + '@jest/console': 29.7.0 + '@jest/environment': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.0.0 + chalk: 4.1.2 + emittery: 0.13.1 + graceful-fs: 4.2.11 + jest-docblock: 29.7.0 + jest-environment-node: 29.7.0 + jest-haste-map: 29.7.0 + jest-leak-detector: 29.7.0 + jest-message-util: 29.7.0 + jest-resolve: 29.7.0 + jest-runtime: 29.7.0 + jest-util: 29.7.0 + jest-watcher: 29.7.0 + jest-worker: 29.7.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color - is-typed-array@1.1.13: + jest-runtime@29.7.0: dependencies: - which-typed-array: 1.1.15 + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/globals': 29.7.0 + '@jest/source-map': 29.6.3 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.0.0 + chalk: 4.1.2 + cjs-module-lexer: 1.4.1 + collect-v8-coverage: 1.0.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color - is-weakmap@2.0.2: {} + jest-snapshot@29.7.0: + dependencies: + '@babel/core': 7.26.0 + '@babel/generator': 7.26.2 + '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) + '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0) + '@babel/types': 7.26.0 + '@jest/expect-utils': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.0) + chalk: 4.1.2 + expect: 29.7.0 + graceful-fs: 4.2.11 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + natural-compare: 1.4.0 + pretty-format: 29.7.0 + semver: 7.6.3 + transitivePeerDependencies: + - supports-color - is-weakref@1.0.2: + jest-util@29.7.0: dependencies: - call-bind: 1.0.7 + '@jest/types': 29.6.3 + '@types/node': 20.0.0 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 - is-weakset@2.0.3: + jest-validate@29.7.0: dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - - isarray@2.0.5: {} - - isexe@2.0.0: {} + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 - isomorphic.js@0.2.5: {} + jest-watcher@29.7.0: + dependencies: + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.0.0 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 29.7.0 + string-length: 4.0.2 - iterator.prototype@1.1.2: + jest-worker@29.7.0: dependencies: - define-properties: 1.2.1 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 - reflect.getprototypeof: 1.0.6 - set-function-name: 2.0.2 + '@types/node': 20.0.0 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 - jackspeak@2.3.6: + jest@29.7.0(@types/node@20.0.0)(ts-node@10.9.2(@types/node@20.0.0)(typescript@5.0.2)): dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.0.0)(typescript@5.0.2)) + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@20.0.0)(ts-node@10.9.2(@types/node@20.0.0)(typescript@5.0.2)) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node js-tokens@4.0.0: {} + js-yaml@3.14.1: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + js-yaml@4.1.0: dependencies: argparse: 2.0.1 + jsdom@20.0.3: + dependencies: + abab: 2.0.6 + acorn: 8.12.1 + acorn-globals: 7.0.1 + cssom: 0.5.0 + cssstyle: 2.3.0 + data-urls: 3.0.2 + decimal.js: 10.4.3 + domexception: 4.0.0 + escodegen: 2.1.0 + form-data: 4.0.1 + html-encoding-sniffer: 3.0.0 + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.13 + parse5: 7.2.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 4.1.4 + w3c-xmlserializer: 4.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 2.0.0 + whatwg-mimetype: 3.0.0 + whatwg-url: 11.0.0 + ws: 8.18.0 + xml-name-validator: 4.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + jsesc@3.0.2: {} + json-buffer@3.0.1: {} + json-parse-even-better-errors@2.3.1: {} + json-schema-traverse@0.4.1: {} json-stable-stringify-without-jsonify@1.0.1: {} @@ -3372,6 +5804,8 @@ snapshots: dependencies: minimist: 1.2.8 + json5@2.2.3: {} + jsx-ast-utils@3.3.5: dependencies: array-includes: 3.1.8 @@ -3383,12 +5817,16 @@ snapshots: dependencies: json-buffer: 3.0.1 + kleur@3.0.3: {} + language-subtag-registry@0.3.23: {} language-tags@1.0.9: dependencies: language-subtag-registry: 0.3.23 + leven@3.1.0: {} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -3398,14 +5836,40 @@ snapshots: dependencies: isomorphic.js: 0.2.5 + lines-and-columns@1.2.4: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + lodash.merge@4.6.2: {} + lodash@4.17.21: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 lru-cache@10.4.3: {} + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lz-string@1.5.0: {} + + make-dir@4.0.0: + dependencies: + semver: 7.6.3 + + make-error@1.3.6: {} + + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + + merge-stream@2.0.0: {} + merge2@1.4.1: {} micromatch@4.0.8: @@ -3413,6 +5877,16 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mimic-fn@2.1.0: {} + + min-indent@1.0.1: {} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -3431,7 +5905,7 @@ snapshots: natural-compare@1.4.0: {} - next@14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2): + next@14.2.13(@babel/core@7.26.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2): dependencies: '@next/env': 14.2.13 '@swc/helpers': 0.5.5 @@ -3441,8 +5915,7 @@ snapshots: postcss: 8.4.31 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - sass: 1.79.2 - styled-jsx: 5.1.1(react@18.2.0) + styled-jsx: 5.1.1(@babel/core@7.26.0)(react@18.2.0) optionalDependencies: '@next/swc-darwin-arm64': 14.2.13 '@next/swc-darwin-x64': 14.2.13 @@ -3453,10 +5926,23 @@ snapshots: '@next/swc-win32-arm64-msvc': 14.2.13 '@next/swc-win32-ia32-msvc': 14.2.13 '@next/swc-win32-x64-msvc': 14.2.13 + sass: 1.79.2 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros + node-int64@0.4.0: {} + + node-releases@2.0.18: {} + + normalize-path@3.0.0: {} + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + nwsapi@2.2.13: {} + object-assign@4.1.1: {} object-inspect@1.13.2: {} @@ -3504,6 +5990,10 @@ snapshots: dependencies: wrappy: 1.0.2 + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -3513,10 +6003,37 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-try@2.2.0: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.26.2 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parse5@7.2.1: + dependencies: + entities: 4.5.0 + + path-exists@4.0.0: {} + path-is-absolute@1.0.1: {} path-key@3.1.1: {} @@ -3532,6 +6049,12 @@ snapshots: picomatch@2.3.1: {} + pirates@4.0.6: {} + + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + possible-typed-array-names@1.0.0: {} postcss@8.4.31: @@ -3542,337 +6065,361 @@ snapshots: prelude-ls@1.2.1: {} + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + progress@2.0.3: {} + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 + psl@1.9.0: {} + punycode@2.3.1: {} + pure-rand@6.1.0: {} + + querystringify@2.2.0: {} + queue-microtask@1.2.3: {} randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 - rc-cascader@3.28.1(react-dom@18.2.0)(react@18.2.0): + rc-cascader@3.28.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 array-tree-filter: 2.1.0 classnames: 2.5.1 - rc-select: 14.15.2(react-dom@18.2.0)(react@18.2.0) - rc-tree: 5.9.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-select: 14.15.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-tree: 5.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-checkbox@3.3.0(react-dom@18.2.0)(react@18.2.0): + rc-checkbox@3.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-collapse@3.7.3(react-dom@18.2.0)(react@18.2.0): + rc-collapse@3.7.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-dialog@9.5.2(react-dom@18.2.0)(react@18.2.0): + rc-dialog@9.5.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-drawer@7.2.0(react-dom@18.2.0)(react@18.2.0): + rc-drawer@7.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-dropdown@4.2.0(react-dom@18.2.0)(react@18.2.0): + rc-dropdown@4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-field-form@2.4.0(react-dom@18.2.0)(react@18.2.0): + rc-field-form@2.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/async-validator': 5.0.4 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-image@7.9.0(react-dom@18.2.0)(react@18.2.0): + rc-image@7.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-dialog: 9.5.2(react-dom@18.2.0)(react@18.2.0) - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-dialog: 9.5.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-input-number@9.2.0(react-dom@18.2.0)(react@18.2.0): + rc-input-number@9.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/mini-decimal': 1.1.0 classnames: 2.5.1 - rc-input: 1.6.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-input: 1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-input@1.6.3(react-dom@18.2.0)(react@18.2.0): + rc-input@1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-mentions@2.15.0(react-dom@18.2.0)(react@18.2.0): + rc-mentions@2.15.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-input: 1.6.3(react-dom@18.2.0)(react@18.2.0) - rc-menu: 9.14.1(react-dom@18.2.0)(react@18.2.0) - rc-textarea: 1.8.2(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-input: 1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-menu: 9.14.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-textarea: 1.8.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-menu@9.14.1(react-dom@18.2.0)(react@18.2.0): + rc-menu@9.14.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-overflow: 1.3.2(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-overflow: 1.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-motion@2.9.3(react-dom@18.2.0)(react@18.2.0): + rc-motion@2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-notification@5.6.2(react-dom@18.2.0)(react@18.2.0): + rc-notification@5.6.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-overflow@1.3.2(react-dom@18.2.0)(react@18.2.0): + rc-overflow@1.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-pagination@4.2.0(react-dom@18.2.0)(react@18.2.0): + rc-pagination@4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-picker@4.6.15(dayjs@1.11.13)(react-dom@18.2.0)(react@18.2.0): + rc-picker@4.6.15(dayjs@1.11.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - dayjs: 1.11.13 - rc-overflow: 1.3.2(react-dom@18.2.0)(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-overflow: 1.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + dayjs: 1.11.13 - rc-progress@4.0.0(react-dom@18.2.0)(react@18.2.0): + rc-progress@4.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-rate@2.13.0(react-dom@18.2.0)(react@18.2.0): + rc-rate@2.13.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-resize-observer@1.4.0(react-dom@18.2.0)(react@18.2.0): + rc-resize-observer@1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) resize-observer-polyfill: 1.5.1 - rc-segmented@2.3.0(react-dom@18.2.0)(react@18.2.0): + rc-segmented@2.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-select@14.15.2(react-dom@18.2.0)(react@18.2.0): + rc-select@14.15.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-overflow: 1.3.2(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) - rc-virtual-list: 3.14.8(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-overflow: 1.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-virtual-list: 3.14.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-slider@11.1.6(react-dom@18.2.0)(react@18.2.0): + rc-slider@11.1.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-steps@6.0.1(react-dom@18.2.0)(react@18.2.0): + rc-steps@6.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-switch@4.1.0(react-dom@18.2.0)(react@18.2.0): + rc-switch@4.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-table@7.45.7(react-dom@18.2.0)(react@18.2.0): + rc-table@7.45.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/context': 1.4.0(react-dom@18.2.0)(react@18.2.0) + '@rc-component/context': 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) - rc-virtual-list: 3.14.8(react-dom@18.2.0)(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-virtual-list: 3.14.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-tabs@15.1.1(react-dom@18.2.0)(react@18.2.0): + rc-tabs@15.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-dropdown: 4.2.0(react-dom@18.2.0)(react@18.2.0) - rc-menu: 9.14.1(react-dom@18.2.0)(react@18.2.0) - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-dropdown: 4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-menu: 9.14.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-textarea@1.8.2(react-dom@18.2.0)(react@18.2.0): + rc-textarea@1.8.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-input: 1.6.3(react-dom@18.2.0)(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-input: 1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-tooltip@6.2.1(react-dom@18.2.0)(react@18.2.0): + rc-tooltip@6.2.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-tree-select@5.23.0(react-dom@18.2.0)(react@18.2.0): + rc-tree-select@5.23.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-select: 14.15.2(react-dom@18.2.0)(react@18.2.0) - rc-tree: 5.9.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-select: 14.15.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-tree: 5.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-tree@5.9.0(react-dom@18.2.0)(react@18.2.0): + rc-tree@5.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) - rc-virtual-list: 3.14.8(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-virtual-list: 3.14.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-upload@4.7.0(react-dom@18.2.0)(react@18.2.0): + rc-upload@4.7.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-util@5.43.0(react-dom@18.2.0)(react@18.2.0): + rc-util@5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-is: 18.3.1 - rc-virtual-list@3.14.8(react-dom@18.2.0)(react@18.2.0): + rc-virtual-list@3.14.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -3884,6 +6431,8 @@ snapshots: react-is@16.13.1: {} + react-is@17.0.2: {} + react-is@18.3.1: {} react-timer-hook@3.0.7(react@18.2.0): @@ -3904,6 +6453,11 @@ snapshots: readdirp@4.0.1: {} + redent@3.0.0: + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + reflect.getprototypeof@1.0.6: dependencies: call-bind: 1.0.7 @@ -3925,12 +6479,24 @@ snapshots: regexpp@3.2.0: {} + require-directory@2.1.1: {} + + requires-port@1.0.0: {} + resize-observer-polyfill@1.5.1: {} + resolve-cwd@3.0.0: + dependencies: + resolve-from: 5.0.0 + resolve-from@4.0.0: {} + resolve-from@5.0.0: {} + resolve-pkg-maps@1.0.0: {} + resolve.exports@2.0.2: {} + resolve@1.22.8: dependencies: is-core-module: 2.15.1 @@ -3968,12 +6534,18 @@ snapshots: es-errors: 1.3.0 is-regex: 1.1.4 + safer-buffer@2.1.2: {} + sass@1.79.2: dependencies: chokidar: 4.0.1 immutable: 4.3.7 source-map-js: 1.2.1 + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + scheduler@0.23.2: dependencies: loose-envify: 1.4.0 @@ -4015,6 +6587,8 @@ snapshots: get-intrinsic: 1.2.4 object-inspect: 1.13.2 + signal-exit@3.0.7: {} + signal-exit@4.1.0: {} simple-peer@9.11.1: @@ -4029,8 +6603,25 @@ snapshots: transitivePeerDependencies: - supports-color + sisteransi@1.0.5: {} + + slash@3.0.0: {} + source-map-js@1.2.1: {} + source-map-support@0.5.13: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + sprintf-js@1.0.3: {} + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + stop-iteration-iterator@1.0.0: dependencies: internal-slot: 1.0.7 @@ -4039,6 +6630,11 @@ snapshots: string-convert@0.2.1: {} + string-length@4.0.2: + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -4109,14 +6705,24 @@ snapshots: strip-bom@3.0.0: {} + strip-bom@4.0.0: {} + + strip-final-newline@2.0.0: {} + + strip-indent@3.0.0: + dependencies: + min-indent: 1.0.1 + strip-json-comments@3.1.1: {} style-mod@4.1.2: {} - styled-jsx@5.1.1(react@18.2.0): + styled-jsx@5.1.1(@babel/core@7.26.0)(react@18.2.0): dependencies: client-only: 0.0.1 react: 18.2.0 + optionalDependencies: + '@babel/core': 7.26.0 stylis@4.3.4: {} @@ -4124,24 +6730,67 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} + symbol-tree@3.2.4: {} + tapable@2.2.1: {} + test-exclude@6.0.0: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + text-table@0.2.0: {} throttle-debounce@5.0.2: {} + tmpl@1.0.5: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 toggle-selection@1.0.6: {} + tough-cookie@4.1.4: + dependencies: + psl: 1.9.0 + punycode: 2.3.1 + universalify: 0.2.0 + url-parse: 1.5.10 + + tr46@3.0.0: + dependencies: + punycode: 2.3.1 + ts-api-utils@1.3.0(typescript@5.0.2): dependencies: typescript: 5.0.2 + ts-node@10.9.2(@types/node@20.0.0)(typescript@5.0.2): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.0.0 + acorn: 8.12.1 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.0.2 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 @@ -4155,8 +6804,12 @@ snapshots: dependencies: prelude-ls: 1.2.1 + type-detect@4.0.8: {} + type-fest@0.20.2: {} + type-fest@0.21.3: {} + typed-array-buffer@1.0.2: dependencies: call-bind: 1.0.7 @@ -4200,16 +6853,58 @@ snapshots: has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 + universalify@0.2.0: {} + + update-browserslist-db@1.1.1(browserslist@4.24.2): + dependencies: + browserslist: 4.24.2 + escalade: 3.2.0 + picocolors: 1.1.0 + uri-js@4.4.1: dependencies: punycode: 2.3.1 + url-parse@1.5.10: + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + util-deprecate@1.0.2: {} + v8-compile-cache-lib@3.0.1: {} + v8-compile-cache@2.4.0: {} + v8-to-istanbul@9.3.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + w3c-keyname@2.2.8: {} + w3c-xmlserializer@4.0.0: + dependencies: + xml-name-validator: 4.0.0 + + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + + webidl-conversions@7.0.0: {} + + whatwg-encoding@2.0.0: + dependencies: + iconv-lite: 0.6.3 + + whatwg-mimetype@3.0.0: {} + + whatwg-url@11.0.0: + dependencies: + tr46: 3.0.0 + webidl-conversions: 7.0.0 + which-boxed-primitive@1.0.2: dependencies: is-bigint: 1.0.4 @@ -4268,8 +6963,16 @@ snapshots: wrappy@1.0.2: {} - ws@8.18.0: - optional: true + write-file-atomic@4.0.2: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + + ws@8.18.0: {} + + xml-name-validator@4.0.0: {} + + xmlchars@2.2.0: {} y-codemirror.next@0.3.5(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(yjs@13.6.20): dependencies: @@ -4296,6 +6999,26 @@ snapshots: - supports-color - utf-8-validate + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + yjs@13.6.20: dependencies: lib0: 0.2.98 + + yn@3.1.1: {} + + yocto-queue@0.1.0: {} From 53016e1ebba1ad24131e81274c76701f936498be Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Fri, 1 Nov 2024 13:03:31 +0800 Subject: [PATCH 094/258] update action --- .github/workflows/test.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 82bd2743a4..0b32abd150 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,6 +12,33 @@ on: - staging jobs: + frontend-unit-tests: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: cd into apps/frontend + run: cd ./apps/frontend + + - name: Set up .env + run: cp .env.example .env + + - name: Set up Node.js + uses: actions/setup-node@v2 + with: + node-version: '22' + + - name: Install pnpm + run: npm i -g pnpm + + - name: Install dependencies + run: pnpm i + + - name: Run tests + run: pnpm test + test: runs-on: ubuntu-latest From 365616a647ff3f4ea134c03b1e696bb12a553961 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Fri, 1 Nov 2024 13:07:58 +0800 Subject: [PATCH 095/258] add trigger workflow-dispatch --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0b32abd150..b2f53de668 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,6 +10,7 @@ on: branches: - main - staging + workflow-dispatch jobs: frontend-unit-tests: From 0d77bfebe0121c56611e3c1ca6cb171e21d4f937 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Fri, 1 Nov 2024 13:08:51 +0800 Subject: [PATCH 096/258] asd --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b2f53de668..4746e29dec 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ on: branches: - main - staging - workflow-dispatch + workflow-dispatch: jobs: frontend-unit-tests: From ac0920260c545a81861f2d58dfa3c85b83ca8fc0 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Fri, 1 Nov 2024 13:09:44 +0800 Subject: [PATCH 097/258] asd --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4746e29dec..c572ddf8f0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,7 +10,7 @@ on: branches: - main - staging - workflow-dispatch: + workflow_dispatch: jobs: frontend-unit-tests: From 06b839c65dfa0aec372d7e2752260d7f7fc549d6 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Fri, 1 Nov 2024 13:17:19 +0800 Subject: [PATCH 098/258] asd --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c572ddf8f0..a223a3a1fa 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,7 +24,7 @@ jobs: run: cd ./apps/frontend - name: Set up .env - run: cp .env.example .env + run: cp ./.env.example .env - name: Set up Node.js uses: actions/setup-node@v2 From 1d0f6feef4a8b12979295620c988088dfceb8aa9 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Fri, 1 Nov 2024 13:21:10 +0800 Subject: [PATCH 099/258] asd --- .github/workflows/test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a223a3a1fa..49ba4f5f2e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,6 +23,9 @@ jobs: - name: cd into apps/frontend run: cd ./apps/frontend + - name: ls? + run: ls + - name: Set up .env run: cp ./.env.example .env From 54ad800ac62f684c3917b62a27738687227f9689 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Fri, 1 Nov 2024 16:03:51 +0800 Subject: [PATCH 100/258] asd --- .github/workflows/test.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 49ba4f5f2e..126016a66e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,11 +23,13 @@ jobs: - name: cd into apps/frontend run: cd ./apps/frontend - - name: ls? - run: ls - - name: Set up .env - run: cp ./.env.example .env + run: echo 'NEXT_PUBLIC_QUESTION_SERVICE_URL="http://localhost:8080/" +NEXT_PUBLIC_USER_SERVICE_URL="http://localhost:3001/" +NEXT_PUBLIC_MATCHING_SERVICE_URL="ws://localhost:8081/match" +NEXT_PUBLIC_SIGNALLING_SERVICE_URL="ws://localhost:4444/" +NEXT_PUBLIC_HISTORY_SERVICE_URL="http://localhost:8082/"' > .env + - name: Set up Node.js uses: actions/setup-node@v2 From 415161e056f33efbd4f4f36164860b0a94c98152 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Fri, 1 Nov 2024 16:15:04 +0800 Subject: [PATCH 101/258] asd2 --- .github/workflows/test.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 126016a66e..80fafefb68 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,11 +24,12 @@ jobs: run: cd ./apps/frontend - name: Set up .env - run: echo 'NEXT_PUBLIC_QUESTION_SERVICE_URL="http://localhost:8080/" -NEXT_PUBLIC_USER_SERVICE_URL="http://localhost:3001/" -NEXT_PUBLIC_MATCHING_SERVICE_URL="ws://localhost:8081/match" -NEXT_PUBLIC_SIGNALLING_SERVICE_URL="ws://localhost:4444/" -NEXT_PUBLIC_HISTORY_SERVICE_URL="http://localhost:8082/"' > .env + run: | + echo 'NEXT_PUBLIC_QUESTION_SERVICE_URL="http://localhost:8080/" + NEXT_PUBLIC_USER_SERVICE_URL="http://localhost:3001/" + NEXT_PUBLIC_MATCHING_SERVICE_URL="ws://localhost:8081/match" + NEXT_PUBLIC_SIGNALLING_SERVICE_URL="ws://localhost:4444/" + NEXT_PUBLIC_HISTORY_SERVICE_URL="http://localhost:8082/"' > newfile.env - name: Set up Node.js From 8b054f7329485c7104c93285bde9b0ed49952178 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Fri, 1 Nov 2024 16:23:27 +0800 Subject: [PATCH 102/258] asd --- .github/workflows/test.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 80fafefb68..3c0155556f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,7 +21,12 @@ jobs: uses: actions/checkout@v2 - name: cd into apps/frontend - run: cd ./apps/frontend + run: | + cd ./apps/frontend + + - name: ls? + run: | + ls - name: Set up .env run: | @@ -29,7 +34,7 @@ jobs: NEXT_PUBLIC_USER_SERVICE_URL="http://localhost:3001/" NEXT_PUBLIC_MATCHING_SERVICE_URL="ws://localhost:8081/match" NEXT_PUBLIC_SIGNALLING_SERVICE_URL="ws://localhost:4444/" - NEXT_PUBLIC_HISTORY_SERVICE_URL="http://localhost:8082/"' > newfile.env + NEXT_PUBLIC_HISTORY_SERVICE_URL="http://localhost:8082/"' > .env - name: Set up Node.js From 62a72a9c4c0ea8fe9485943fa28998a2011cf77c Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Fri, 1 Nov 2024 16:27:13 +0800 Subject: [PATCH 103/258] asd --- .github/workflows/test.yml | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3c0155556f..c961011353 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,22 +20,9 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 - - name: cd into apps/frontend - run: | - cd ./apps/frontend - - - name: ls? - run: | - ls - - name: Set up .env run: | - echo 'NEXT_PUBLIC_QUESTION_SERVICE_URL="http://localhost:8080/" - NEXT_PUBLIC_USER_SERVICE_URL="http://localhost:3001/" - NEXT_PUBLIC_MATCHING_SERVICE_URL="ws://localhost:8081/match" - NEXT_PUBLIC_SIGNALLING_SERVICE_URL="ws://localhost:4444/" - NEXT_PUBLIC_HISTORY_SERVICE_URL="http://localhost:8082/"' > .env - + echo ./apps/frontend/.env.example > .env - name: Set up Node.js uses: actions/setup-node@v2 @@ -46,10 +33,14 @@ jobs: run: npm i -g pnpm - name: Install dependencies - run: pnpm i + run: | + cd ./apps/frontend + pnpm i - name: Run tests - run: pnpm test + run: | + cd ./apps/frontend + pnpm test test: runs-on: ubuntu-latest From b23580aa608e2c3b09aba388baa1ae228faa8e70 Mon Sep 17 00:00:00 2001 From: solomonng2001 Date: Fri, 1 Nov 2024 22:43:02 +0800 Subject: [PATCH 104/258] Add code execution service --- apps/docker-compose.yml | 13 + apps/execution-service/.dockerignore | 9 + apps/execution-service/.gitignore | 2 + apps/execution-service/Dockerfile | 18 + apps/execution-service/README.md | 88 +++ apps/execution-service/enums/language.go | 10 + .../execution/python/python.go | 44 ++ apps/execution-service/go.mod | 53 ++ apps/execution-service/go.sum | 197 ++++++ apps/execution-service/handlers/execute.go | 68 ++ apps/execution-service/handlers/populate.go | 31 + apps/execution-service/handlers/read.go | 54 ++ apps/execution-service/handlers/server.go | 9 + apps/execution-service/main.go | 112 ++++ apps/execution-service/models/code.go | 7 + apps/execution-service/models/question.go | 6 + apps/execution-service/models/test.go | 18 + apps/execution-service/models/testResult.go | 20 + apps/execution-service/models/visibleTest.go | 6 + apps/execution-service/test.go | 59 ++ apps/execution-service/utils/decode.go | 20 + apps/execution-service/utils/executeTest.go | 179 +++++ apps/execution-service/utils/populate.go | 634 ++++++++++++++++++ apps/execution-service/utils/testCase.go | 80 +++ .../utils/validateTestCaseFormat.go | 87 +++ apps/matching-service/.dockerignore | 9 + apps/question-service/utils/populate.go | 72 +- 27 files changed, 1901 insertions(+), 4 deletions(-) create mode 100644 apps/execution-service/.dockerignore create mode 100644 apps/execution-service/.gitignore create mode 100644 apps/execution-service/Dockerfile create mode 100644 apps/execution-service/README.md create mode 100644 apps/execution-service/enums/language.go create mode 100644 apps/execution-service/execution/python/python.go create mode 100644 apps/execution-service/go.mod create mode 100644 apps/execution-service/go.sum create mode 100644 apps/execution-service/handlers/execute.go create mode 100644 apps/execution-service/handlers/populate.go create mode 100644 apps/execution-service/handlers/read.go create mode 100644 apps/execution-service/handlers/server.go create mode 100644 apps/execution-service/main.go create mode 100644 apps/execution-service/models/code.go create mode 100644 apps/execution-service/models/question.go create mode 100644 apps/execution-service/models/test.go create mode 100644 apps/execution-service/models/testResult.go create mode 100644 apps/execution-service/models/visibleTest.go create mode 100644 apps/execution-service/test.go create mode 100644 apps/execution-service/utils/decode.go create mode 100644 apps/execution-service/utils/executeTest.go create mode 100644 apps/execution-service/utils/populate.go create mode 100644 apps/execution-service/utils/testCase.go create mode 100644 apps/execution-service/utils/validateTestCaseFormat.go create mode 100644 apps/matching-service/.dockerignore diff --git a/apps/docker-compose.yml b/apps/docker-compose.yml index 0a0ef34fdf..32b41aa39e 100644 --- a/apps/docker-compose.yml +++ b/apps/docker-compose.yml @@ -67,6 +67,19 @@ services: volumes: - ./history-service:/history-service + execution-service: + build: + context: ./execution-service + dockerfile: Dockerfile + ports: + - 8083:8083 + env_file: + - ./execution-service/.env + networks: + - apps_network + volumes: + - ./execution-service:/execution-service + redis: image: redis:latest networks: diff --git a/apps/execution-service/.dockerignore b/apps/execution-service/.dockerignore new file mode 100644 index 0000000000..c6228e8d6c --- /dev/null +++ b/apps/execution-service/.dockerignore @@ -0,0 +1,9 @@ +.env.example + +.git +.gitignore + +.dockerignore +Dockerfile + +README.md diff --git a/apps/execution-service/.gitignore b/apps/execution-service/.gitignore new file mode 100644 index 0000000000..ef986d267e --- /dev/null +++ b/apps/execution-service/.gitignore @@ -0,0 +1,2 @@ +.env +cs3219-staging-codeexecution-firebase-adminsdk-ce48j-00ab09514c.json diff --git a/apps/execution-service/Dockerfile b/apps/execution-service/Dockerfile new file mode 100644 index 0000000000..0cabe00edd --- /dev/null +++ b/apps/execution-service/Dockerfile @@ -0,0 +1,18 @@ +FROM golang:1.23 + +WORKDIR /usr/src/app + +# pre-copy/cache go.mod for pre-downloading dependencies and only redownloading them in subsequent builds if they change +COPY go.mod go.sum ./ + +RUN go mod tidy && go mod download && go mod verify + +COPY .env /usr/src/app/.env + +COPY . . + +RUN go build -v -o /usr/local/bin/app ./main.go + +EXPOSE 8083 8083 + +CMD ["app"] diff --git a/apps/execution-service/README.md b/apps/execution-service/README.md new file mode 100644 index 0000000000..eaa740b179 --- /dev/null +++ b/apps/execution-service/README.md @@ -0,0 +1,88 @@ +# Execution Service + +## Overview + +The Execution Service is built with Go, utilizing Firestore as the database and Chi as the HTTP router. It provides an API to manage test cases, such as populating test cases (via question-service), reading visible test cases and executing visible, hidden and custom test cases. + +## Features + +- Populate test cases (via populate questins in question-service) +- Read visible test cases via a question ID +- Execute visible test cases via a question ID + +## Technologies Used + +- Go (Golang) +- Firestore (Google Cloud Firestore) +- Chi (HTTP router) +- Yaegi (Go interpreter) + +## Getting Started + +### Prerequisites + +- Go 1.16 or later +- Google Cloud SDK +- Firestore database setup in your Google Cloud project + +### Installation + +1. Clone the repository + +2. Set up your Firestore client + +3. Install dependencies: + +```bash +go mod tidy +``` + +4. Create the `.env` file from copying the `.env.example`, and copy the firebase JSON file into execution-service/ fill in the `FIREBASE_CREDENTIAL_PATH` with the path of the firebase credential JSON file. + +### Running the Application + +To start the server, run the following command: + +```bash +go run main.go +``` + +The server will be available at http://localhost:8083. + +## Running the Application via Docker + +To run the application via Docker, run the following command: + +```bash +docker build -t question-service . +``` + +```bash +docker run -p 8083:8083 --env-file .env -d execution-service +``` + +The server will be available at http://localhost:8083. + +## API Endpoints + +- `POST /tests/populate` +- `GET /tests/{questionDocRefId}/` +- `GET /tests/{questionDocRefId}/execute` + +## Managing Firebase + +To reset and repopulate the database, run the following command: + +```bash +go run main.go +``` + +## Repopulate test cases + +To repopulate test cases, you need to repopulate the questions in the question-service, which will automatically call the execution-service to populate the test cases. + +In question-service, run the following command: + +```bash +go run main.go -populate +``` diff --git a/apps/execution-service/enums/language.go b/apps/execution-service/enums/language.go new file mode 100644 index 0000000000..7f40b81891 --- /dev/null +++ b/apps/execution-service/enums/language.go @@ -0,0 +1,10 @@ +package enums + +// Create enums of languages +const ( + JAVA = "Java" + PYTHON = "Python" + GOLANG = "Golang" + JAVASCRIPT = "Javascript" + CPP = "C++" +) diff --git a/apps/execution-service/execution/python/python.go b/apps/execution-service/execution/python/python.go new file mode 100644 index 0000000000..a8f89316fc --- /dev/null +++ b/apps/execution-service/execution/python/python.go @@ -0,0 +1,44 @@ +package python + +import ( + "bytes" + "fmt" + "os" + "os/exec" + "strings" +) + +// RunPythonCode executes the provided Python code with the given input +func RunPythonCode(code string, input string) (string, string, error) { + // Create a temporary Python file to execute + tmpFile, err := os.CreateTemp("", "*.py") + if err != nil { + return "", "", fmt.Errorf("failed to create temporary file: %w", err) + } + defer os.Remove(tmpFile.Name()) // Clean up the temporary file afterwards + + // Write the provided code to the temporary file + if _, err := tmpFile.WriteString(code); err != nil { + return "", "", fmt.Errorf("failed to write code to temporary file: %w", err) + } + if err := tmpFile.Close(); err != nil { + return "", "", fmt.Errorf("failed to close temporary file: %w", err) + } + + // Prepare the command to execute the Python script + cmd := exec.Command("python3", tmpFile.Name()) + cmd.Stdin = bytes.NewBufferString(input) + + // Capture the output and error + var output bytes.Buffer + var errorOutput bytes.Buffer + cmd.Stdout = &output + cmd.Stderr = &errorOutput + + // Run the command + if err := cmd.Run(); err != nil { + return "", fmt.Sprintf("Command execution failed: %s: %w", errorOutput.String(), err), nil + } + + return strings.TrimSuffix(output.String(), "\n"), strings.TrimSuffix(errorOutput.String(), "\n"), nil +} diff --git a/apps/execution-service/go.mod b/apps/execution-service/go.mod new file mode 100644 index 0000000000..32a516cf23 --- /dev/null +++ b/apps/execution-service/go.mod @@ -0,0 +1,53 @@ +module execution-service + +go 1.23.1 + +require ( + cloud.google.com/go/firestore v1.17.0 + firebase.google.com/go/v4 v4.15.0 + github.com/go-chi/chi/v5 v5.1.0 + github.com/go-chi/cors v1.2.1 + github.com/joho/godotenv v1.5.1 + github.com/traefik/yaegi v0.16.1 + google.golang.org/api v0.203.0 +) + +require ( + cloud.google.com/go v0.116.0 // indirect + cloud.google.com/go/auth v0.9.9 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect + cloud.google.com/go/compute/metadata v0.5.2 // indirect + cloud.google.com/go/iam v1.2.1 // indirect + cloud.google.com/go/longrunning v0.6.1 // indirect + cloud.google.com/go/storage v1.43.0 // indirect + github.com/MicahParks/keyfunc v1.9.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/s2a-go v0.1.8 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect + github.com/googleapis/gax-go/v2 v2.13.0 // indirect + go.opencensus.io v0.24.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect + go.opentelemetry.io/otel v1.29.0 // indirect + go.opentelemetry.io/otel/metric v1.29.0 // indirect + go.opentelemetry.io/otel/trace v1.29.0 // indirect + golang.org/x/crypto v0.28.0 // indirect + golang.org/x/net v0.30.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/text v0.19.0 // indirect + golang.org/x/time v0.7.0 // indirect + google.golang.org/appengine/v2 v2.0.2 // indirect + google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect + google.golang.org/grpc v1.67.1 // indirect + google.golang.org/protobuf v1.35.1 // indirect +) diff --git a/apps/execution-service/go.sum b/apps/execution-service/go.sum new file mode 100644 index 0000000000..7d3c75e147 --- /dev/null +++ b/apps/execution-service/go.sum @@ -0,0 +1,197 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= +cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= +cloud.google.com/go/auth v0.9.9 h1:BmtbpNQozo8ZwW2t7QJjnrQtdganSdmqeIBxHxNkEZQ= +cloud.google.com/go/auth v0.9.9/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= +cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= +cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= +cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= +cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= +cloud.google.com/go/firestore v1.17.0 h1:iEd1LBbkDZTFsLw3sTH50eyg4qe8eoG6CjocmEXO9aQ= +cloud.google.com/go/firestore v1.17.0/go.mod h1:69uPx1papBsY8ZETooc71fOhoKkD70Q1DwMrtKuOT/Y= +cloud.google.com/go/iam v1.2.1 h1:QFct02HRb7H12J/3utj0qf5tobFh9V4vR6h9eX5EBRU= +cloud.google.com/go/iam v1.2.1/go.mod h1:3VUIJDPpwT6p/amXRC5GY8fCCh70lxPygguVtI0Z4/g= +cloud.google.com/go/longrunning v0.6.1 h1:lOLTFxYpr8hcRtcwWir5ITh1PAKUD/sG2lKrTSYjyMc= +cloud.google.com/go/longrunning v0.6.1/go.mod h1:nHISoOZpBcmlwbJmiVk5oDRz0qG/ZxPynEGs1iZ79s0= +cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs= +cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= +firebase.google.com/go/v4 v4.15.0 h1:k27M+cHbyN1YpBI2Cf4NSjeHnnYRB9ldXwpqA5KikN0= +firebase.google.com/go/v4 v4.15.0/go.mod h1:S/4MJqVZn1robtXkHhpRUbwOC4gdYtgsiMMJQ4x+xmQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/MicahParks/keyfunc v1.9.0 h1:lhKd5xrFHLNOWrDc4Tyb/Q1AJ4LCzQ48GVJyVIID3+o= +github.com/MicahParks/keyfunc v1.9.0/go.mod h1:IdnCilugA0O/99dW+/MkvlyrsX8+L8+x95xuVNtM5jw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= +github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= +github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= +github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= +github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= +github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= +github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= +github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= +github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/traefik/yaegi v0.16.1 h1:f1De3DVJqIDKmnasUF6MwmWv1dSEEat0wcpXhD2On3E= +github.com/traefik/yaegi v0.16.1/go.mod h1:4eVhbPb3LnD2VigQjhYbEJ69vDRFdT2HQNrXx8eEwUY= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= +go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= +go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= +go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20220708220712-1185a9018129/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= +golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.203.0 h1:SrEeuwU3S11Wlscsn+LA1kb/Y5xT8uggJSkIhD08NAU= +google.golang.org/api v0.203.0/go.mod h1:BuOVyCSYEPwJb3npWvDnNmFI92f3GeRnHNkETneT3SI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine/v2 v2.0.2 h1:MSqyWy2shDLwG7chbwBJ5uMyw6SNqJzhJHNDwYB0Akk= +google.golang.org/appengine/v2 v2.0.2/go.mod h1:PkgRUWz4o1XOvbqtWTkBtCitEJ5Tp4HoVEdMMYQR/8E= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53 h1:Df6WuGvthPzc+JiQ/G+m+sNX24kc0aTBqoDN/0yyykE= +google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53/go.mod h1:fheguH3Am2dGp1LfXkrvwqC/KlFq8F0nLq3LryOMrrE= +google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 h1:T6rh4haD3GVYsgEfWExoCZA2o2FmbNyKpTuAxbEFPTg= +google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:wp2WsuBYj6j8wUdo3ToZsdxxixbvQNAHqVJrTgi5E5M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/apps/execution-service/handlers/execute.go b/apps/execution-service/handlers/execute.go new file mode 100644 index 0000000000..e6cad62229 --- /dev/null +++ b/apps/execution-service/handlers/execute.go @@ -0,0 +1,68 @@ +package handlers + +import ( + "encoding/json" + "execution-service/models" + "execution-service/utils" + "github.com/go-chi/chi/v5" + "google.golang.org/api/iterator" + "net/http" +) + +func (s *Service) ExecuteTest(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + questionDocRefId := chi.URLParam(r, "questionDocRefId") + if questionDocRefId == "" { + http.Error(w, "questionDocRefId is required", http.StatusBadRequest) + return + } + + var code models.Code + if err := utils.DecodeJSONBody(w, r, &code); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + iter := s.Client.Collection("tests").Where("questionDocRefId", "==", questionDocRefId).Limit(1).Documents(ctx) + doc, err := iter.Next() + if err != nil { + if err == iterator.Done { + http.Error(w, "Test not found", http.StatusNotFound) + return + } + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + var test models.Test + if err := doc.DataTo(&test); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + testResults, err := utils.ExecuteTest(code, test) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(testResults) +} + +//curl -X POST http://localhost:8083/tests/bmzFyLMeSOoYU99pi4yZ/execute \ +//-H "Content-Type: application/json" \ +//-d '{ +//"code": "name = input()\nprint(name[::-1])", +//"language": "Python" +//}' + +//curl -X POST http://localhost:8083/tests/bmzFyLMeSOoYU99pi4yZ/execute \ +//-H "Content-Type: application/json" \ +//-d '{ +//"code": "name = input()\nprint(name[::-1])", +//"language": "Python", +//"customTestCases": "2\nHannah\nhannaH\nabcdefg\ngfedcba\n" +//}' diff --git a/apps/execution-service/handlers/populate.go b/apps/execution-service/handlers/populate.go new file mode 100644 index 0000000000..014b4fe760 --- /dev/null +++ b/apps/execution-service/handlers/populate.go @@ -0,0 +1,31 @@ +package handlers + +import ( + "execution-service/models" + "execution-service/utils" + "net/http" +) + +func (s *Service) PopulateTests(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + var questions []models.Question + if err := utils.DecodeJSONBody(w, r, &questions); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + questionTitleToDocRefIdMap := make(map[string]string) + for _, question := range questions { + questionTitleToDocRefIdMap[question.Title] = question.QuestionDocRefId + } + + err := utils.RepopulateTests(ctx, s.Client, questionTitleToDocRefIdMap) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) +} diff --git a/apps/execution-service/handlers/read.go b/apps/execution-service/handlers/read.go new file mode 100644 index 0000000000..db7fd4a21a --- /dev/null +++ b/apps/execution-service/handlers/read.go @@ -0,0 +1,54 @@ +package handlers + +import ( + "encoding/json" + "execution-service/models" + "execution-service/utils" + "github.com/go-chi/chi/v5" + "google.golang.org/api/iterator" + "net/http" +) + +func (s *Service) ReadTest(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + questionDocRefId := chi.URLParam(r, "questionDocRefId") + if questionDocRefId == "" { + http.Error(w, "questionDocRefId is required", http.StatusBadRequest) + return + } + + iter := s.Client.Collection("tests").Where("questionDocRefId", "==", questionDocRefId).Limit(1).Documents(ctx) + doc, err := iter.Next() + if err != nil { + if err == iterator.Done { + http.Error(w, "Test not found", http.StatusNotFound) + return + } + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + var test models.Test + if err := doc.DataTo(&test); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + _, visibleTestCases, err := utils.GetTestLengthAndUnexecutedCases(test.VisibleTestCases) + + var visibleTests []models.VisibleTest + for _, visibleTestCase := range visibleTestCases { + visibleTests = append(visibleTests, models.VisibleTest{ + Input: visibleTestCase.Input, + Expected: visibleTestCase.Expected, + }) + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(visibleTests) +} + +//curl -X GET http://localhost:8083/tests/bmzFyLMeSOoYU99pi4yZ/ \ +//-H "Content-Type: application/json" diff --git a/apps/execution-service/handlers/server.go b/apps/execution-service/handlers/server.go new file mode 100644 index 0000000000..2d237dc025 --- /dev/null +++ b/apps/execution-service/handlers/server.go @@ -0,0 +1,9 @@ +package handlers + +import ( + "cloud.google.com/go/firestore" +) + +type Service struct { + Client *firestore.Client +} diff --git a/apps/execution-service/main.go b/apps/execution-service/main.go new file mode 100644 index 0000000000..e9991c5f82 --- /dev/null +++ b/apps/execution-service/main.go @@ -0,0 +1,112 @@ +package main + +import ( + "context" + "execution-service/handlers" + "fmt" + "log" + "net/http" + "os" + "time" + + "cloud.google.com/go/firestore" + firebase "firebase.google.com/go/v4" + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" + "github.com/go-chi/cors" + "github.com/joho/godotenv" + "google.golang.org/api/option" +) + +func main() { + // Load .env file + err := godotenv.Load() + if err != nil { + log.Fatal("Error loading .env file") + } + + // Initialize Firestore client + ctx := context.Background() + client, err := initFirestore(ctx) + if err != nil { + log.Fatalf("Failed to initialize Firestore client: %v", err) + } + defer client.Close() + + service := &handlers.Service{Client: client} + + r := initChiRouter(service) + initRestServer(r) +} + +// initFirestore initializes the Firestore client +func initFirestore(ctx context.Context) (*firestore.Client, error) { + credentialsPath := os.Getenv("FIREBASE_CREDENTIAL_PATH") + opt := option.WithCredentialsFile(credentialsPath) + app, err := firebase.NewApp(ctx, nil, opt) + if err != nil { + return nil, fmt.Errorf("failed to initialize Firebase App: %v", err) + } + + client, err := app.Firestore(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get Firestore client: %v", err) + } + return client, nil +} + +func initChiRouter(service *handlers.Service) *chi.Mux { + r := chi.NewRouter() + r.Use(middleware.Logger) + r.Use(middleware.Timeout(60 * time.Second)) + + r.Use(cors.Handler(cors.Options{ + // AllowedOrigins: []string{"http://localhost:3000"}, // Use this to allow specific origin hosts + AllowedOrigins: []string{"https://*", "http://*"}, + // AllowOriginFunc: func(r *http.Request, origin string) bool { return true }, + AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, + AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"}, + ExposedHeaders: []string{"Link"}, + AllowCredentials: false, + MaxAge: 300, // Maximum value not ignored by any of major browsers + })) + + registerRoutes(r, service) + + return r +} + +func registerRoutes(r *chi.Mux, service *handlers.Service) { + r.Route("/tests", func(r chi.Router) { + // Re: CreateTest + // Current: Unused, since testcases are populated via script + // Future extension: can be created by admin + //r.Post("/", service.CreateTest) + r.Post("/populate", service.PopulateTests) + + r.Route("/{questionDocRefId}", func(r chi.Router) { + // Re: UpdateTest, DeleteTest + // Current: Unused, since testcases are executed within service and not exposed + // Future extension: can be read by admin to view testcases + //r.Put("/", service.UpdateTest) + //r.Delete("/", service.DeleteTest) + r.Get("/", service.ReadTest) + r.Post("/execute", service.ExecuteTest) + }) + }) +} + +func initRestServer(r *chi.Mux) { + // Serve on port 8080 + port := os.Getenv("PORT") + if port == "" { + port = "8083" + } + + // Start the server + log.Printf("Starting REST server on http://localhost:%s", port) + err := http.ListenAndServe(fmt.Sprintf(":%s", port), r) + if err != nil { + log.Fatalf("Failed to start server: %v", err) + } +} diff --git a/apps/execution-service/models/code.go b/apps/execution-service/models/code.go new file mode 100644 index 0000000000..bd8ab16f84 --- /dev/null +++ b/apps/execution-service/models/code.go @@ -0,0 +1,7 @@ +package models + +type Code struct { + Code string `json:"code"` + Language string `json:"language"` + CustomTestCases string `json:"customTestCases"` +} diff --git a/apps/execution-service/models/question.go b/apps/execution-service/models/question.go new file mode 100644 index 0000000000..1a470c1839 --- /dev/null +++ b/apps/execution-service/models/question.go @@ -0,0 +1,6 @@ +package models + +type Question struct { + QuestionDocRefId string `json:"docRefId"` + Title string `json:"title"` +} diff --git a/apps/execution-service/models/test.go b/apps/execution-service/models/test.go new file mode 100644 index 0000000000..9b6c6d80ac --- /dev/null +++ b/apps/execution-service/models/test.go @@ -0,0 +1,18 @@ +package models + +import "time" + +type Test struct { + QuestionDocRefId string `json:"questionDocRefId" firestore:"questionDocRefId"` + VisibleTestCases string `json:"visibleTestCases" firestore:"visibleTestCases"` + HiddenTestCases string `json:"hiddenTestCases" firestore:"hiddenTestCases"` + InputValidation string `json:"inputValidation" firestore:"inputValidation"` + OutputValidation string `json:"outputValidation" firestore:"outputValidation"` + + // Special DB fields + CreatedAt time.Time `json:"createdAt" firestore:"createdAt"` + UpdatedAt time.Time `json:"updatedAt" firestore:"updatedAt"` + + // Not stored in DB but used by json decoder + QuestionTitle string `json:"questionTitle" firestore:"questionTitle"` +} diff --git a/apps/execution-service/models/testResult.go b/apps/execution-service/models/testResult.go new file mode 100644 index 0000000000..df60799cd1 --- /dev/null +++ b/apps/execution-service/models/testResult.go @@ -0,0 +1,20 @@ +package models + +type TestResults struct { + VisibleTestResults []IndividualTestResult `json:"visibleTestResults"` + HiddenTestResults GeneralTestResults `json:"hiddenTestResults"` + CustomTestResults []IndividualTestResult `json:"customTestResults"` +} + +type IndividualTestResult struct { + Input string `json:"input"` + Expected string `json:"expected"` + Actual string `json:"actual"` + Passed bool `json:"passed"` + Error string `json:"error,omitempty"` +} + +type GeneralTestResults struct { + Passed int `json:"passed"` + Total int `json:"total"` +} diff --git a/apps/execution-service/models/visibleTest.go b/apps/execution-service/models/visibleTest.go new file mode 100644 index 0000000000..39c2bf48cb --- /dev/null +++ b/apps/execution-service/models/visibleTest.go @@ -0,0 +1,6 @@ +package models + +type VisibleTest struct { + Input string `json:"input"` + Expected string `json:"expected"` +} diff --git a/apps/execution-service/test.go b/apps/execution-service/test.go new file mode 100644 index 0000000000..8af33b0676 --- /dev/null +++ b/apps/execution-service/test.go @@ -0,0 +1,59 @@ +package main + +import ( + "execution-service/execution/python" +) + +func main() { + println("testing: ") + output, errorOutput, _ := test() + println("output: ", output) + println("errorOutput: ", errorOutput) +} + +//func test() bool { +// inputOrOutput := `[]` +// +// output := inputOrOutput +// +// if output == "[]" { +// return true +// } +// +// // Check that the output is enclosed in square brackets +// if len(output) < 2 || output[0] != '[' || output[len(output)-1] != ']' { +// return false +// } +// +// // Extract the content between square brackets +// content := output[1 : len(output)-1] +// +// // Split by commas without trimming spaces +// sequences := strings.Split(content, ", ") +// for _, seq := range sequences { +// // Check if each sequence is properly enclosed in double quotes and is exactly 10 characters +// if len(seq) != 12 || seq[0] != '"' || seq[11] != '"' { +// return false +// } +// +// // Check that the sequence only contains valid DNA characters between the quotes +// for i := 1; i < 11; i++ { +// ch := seq[i] +// if ch != 'A' && ch != 'C' && ch != 'G' && ch != 'T' { +// return false +// } +// } +// } +// return true +//} + +func test() (string, string, error) { + code := ` +nam = input() +print(name[::-1]) +` + + input := "hello" + + return python.RunPythonCode(code, input) +} diff --git a/apps/execution-service/utils/decode.go b/apps/execution-service/utils/decode.go new file mode 100644 index 0000000000..981df9a617 --- /dev/null +++ b/apps/execution-service/utils/decode.go @@ -0,0 +1,20 @@ +package utils + +import ( + "encoding/json" + "fmt" + "net/http" +) + +// DecodeJSONBody decodes the request body into the given destination +func DecodeJSONBody(w http.ResponseWriter, r *http.Request, dst interface{}) error { + decoder := json.NewDecoder(r.Body) + decoder.DisallowUnknownFields() + + err := decoder.Decode(&dst) + if err != nil { + return fmt.Errorf("Invalid request payload: " + err.Error()) + } + + return nil +} diff --git a/apps/execution-service/utils/executeTest.go b/apps/execution-service/utils/executeTest.go new file mode 100644 index 0000000000..cdc3853777 --- /dev/null +++ b/apps/execution-service/utils/executeTest.go @@ -0,0 +1,179 @@ +package utils + +import ( + "execution-service/enums" + "execution-service/execution/python" + "execution-service/models" + "fmt" +) + +func ExecuteTest(code models.Code, test models.Test) (models.TestResults, error) { + var err error + var testResults models.TestResults + + switch code.Language { + case enums.PYTHON: + testResults, err = getTestResultFromTest(code, test, python.RunPythonCode) + break + default: + return models.TestResults{}, fmt.Errorf("unsupported language: %s", code.Language) + } + if err != nil { + return models.TestResults{}, err + } + + return testResults, nil +} + +//func getVisibleTestResultsWithCompilationError(test models.Test, +// testCaseErrorStr string) ([]models.IndividualTestResult, error) { +// _, visibleTestResults, err := GetTestLengthAndUnexecutedCases(test.VisibleTestCases) +// if err != nil { +// return nil, err +// } +// +// for _, visibleTestResult := range visibleTestResults { +// visibleTestResult.Actual = "" +// visibleTestResult.Passed = false +// visibleTestResult.Error = testCaseErrorStr +// } +// +// return visibleTestResults, nil +//} +// +//func getHiddenTestResultsWithCompilationError(test models.Test) (models.GeneralTestResults, error) { +// numHiddenTests, err := GetTestLength(test.HiddenTestCases) +// if err != nil { +// return models.GeneralTestResults{}, err +// } +// +// return models.GeneralTestResults{ +// Passed: 0, +// Total: numHiddenTests, +// }, nil +//} + +func getIndividualTestResultFromCodeExecutor(code string, unexecutedTestResult models.IndividualTestResult, + executor func(string, string) (string, string, error)) (models.IndividualTestResult, error) { + output, outputErr, err := executor(code, unexecutedTestResult.Input) + if err != nil { + return models.IndividualTestResult{}, err + } + return models.IndividualTestResult{ + Input: unexecutedTestResult.Input, + Expected: unexecutedTestResult.Expected, + Actual: output, + Passed: output == unexecutedTestResult.Expected, + Error: outputErr, + }, nil +} + +func getAllTestResultsFromFormattedTestCase(code string, testCase string, + executor func(string, string) (string, string, error)) ([]models.IndividualTestResult, error) { + _, testResults, err := GetTestLengthAndUnexecutedCases(testCase) + if err != nil { + return nil, err + } + + for i := range testResults { + currTestResult, err := getIndividualTestResultFromCodeExecutor(code, testResults[i], executor) + if err != nil { + return nil, err + } + testResults[i].Actual = currTestResult.Actual + testResults[i].Passed = currTestResult.Passed + testResults[i].Error = currTestResult.Error + } + + return testResults, nil +} + +func getGenericTestResultsFromFormattedTestCase(code string, testCase string, + executor func(string, string) (string, string, error)) (models.GeneralTestResults, error) { + testResults, err := getAllTestResultsFromFormattedTestCase(code, testCase, executor) + if err != nil { + return models.GeneralTestResults{}, err + } + + var passed int + for _, testResult := range testResults { + if testResult.Passed { + passed++ + } + } + + return models.GeneralTestResults{ + Passed: passed, + Total: len(testResults), + }, nil +} + +func getTestResultFromTest(code models.Code, test models.Test, + executor func(string, string) (string, string, error)) (models.TestResults, error) { + visibleTestResults, err := getAllTestResultsFromFormattedTestCase(code.Code, test.VisibleTestCases, executor) + if err != nil { + return models.TestResults{}, err + } + + hiddenTestResults, err := getGenericTestResultsFromFormattedTestCase(code.Code, test.HiddenTestCases, executor) + if err != nil { + return models.TestResults{}, err + } + + var customTestResults []models.IndividualTestResult + if code.CustomTestCases != "" { + customTestResults, err = getAllTestResultsFromFormattedTestCase(code.Code, code.CustomTestCases, executor) + if err != nil { + return models.TestResults{}, err + } + } + + return models.TestResults{ + VisibleTestResults: visibleTestResults, + HiddenTestResults: hiddenTestResults, + CustomTestResults: customTestResults, + }, nil +} + +//func getVisibleTestResults(code string, test models.Test) ([]models.IndividualTestResult, error) { +// _, visibleTestResults, err := GetTestLengthAndUnexecutedCases(test.VisibleTestCases) +// if err != nil { +// return nil, err +// } +// +// // Initialize Yaegi interpreter +// i := interp.New(interp.Options{}) +// i.Use(stdlib.Symbols) +// +// _, err = i.Eval(code) +// if err != nil { +// return nil, fmt.Errorf("error evaluating code: %v", err) +// } +// +// // Execute each test case +// for _, visibleTestResult := range visibleTestResults { +// // Create an output buffer to capture stdout +// var stdout bytes.Buffer +// i.Stdout = &stdout +// +// // Set up the input for the test case +// input := strings.NewReader(visibleTestResult.Input + "\n") +// i.Stdin = input +// +// // Run the code +// _, err := i.Eval("main.main()") +// if err != nil { +// visibleTestResult.Actual = "" +// visibleTestResult.Passed = false +// visibleTestResult.Error = err.Error() +// continue +// } +// +// actualOutput := strings.TrimSpace(stdout.String()) +// +// visibleTestResult.Actual = actualOutput +// visibleTestResult.Passed = actualOutput == visibleTestResult.Expected +// } +// +// return visibleTestResults, nil +//} diff --git a/apps/execution-service/utils/populate.go b/apps/execution-service/utils/populate.go new file mode 100644 index 0000000000..df1c386a5e --- /dev/null +++ b/apps/execution-service/utils/populate.go @@ -0,0 +1,634 @@ +package utils + +import ( + "cloud.google.com/go/firestore" + "context" + "execution-service/models" + "fmt" + "google.golang.org/api/iterator" + "log" + "strings" +) + +// RepopulateTests Populate deletes all testcases and repopulates testcases +func RepopulateTests(ctx context.Context, client *firestore.Client, + questionTitleToDocRefIdMap map[string]string) error { + + // delete all existing document in the collection + iter := client.Collection("tests").Documents(ctx) + for { + doc, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { + return fmt.Errorf("failed to iterate over tests: %v", err) + } + + if _, err := doc.Ref.Delete(ctx); err != nil { + return fmt.Errorf("failed to delete test: %v", err) + } + } + + var tests = []models.Test{ + { + QuestionTitle: "Reverse a String", + VisibleTestCases: ` +1 +hello +olleh +`, + HiddenTestCases: ` +2 +Hannah +hannaH +abcdefg +gfedcba +`, + InputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + OutputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + }, + { + QuestionTitle: "Linked List Cycle Detection", + VisibleTestCases: ` +1 +[3,2,0,-4] -> pos = 1 +true +`, + HiddenTestCases: ` +2 +[1,2] -> pos = 0 +true +[1] +false +`, + InputValidation: getPackagesAndFunction([]string{"strconv", "strings"}, ` +hasCycle := false + +// Step 1: Split by " -> pos = " +parts := strings.Split(inputOrOutput, " -> pos = ") +if len(parts) == 2 { + hasCycle = true +} else if len(parts) != 1 { + return false +} + +listPart := strings.TrimSpace(parts[0]) // Get the list part + +//Validate the list format +if len(listPart) < 2 || listPart[0] != '[' || listPart[len(listPart)-1] != ']' { + return false +} + +listContent := listPart[1 : len(listPart)-1] // Remove brackets +if listContent == "" { // Check for empty list + return false +} + +// Split the list by commas and validate each element +elements := strings.Split(listContent, ",") +for _, elem := range elements { + elem = strings.TrimSpace(elem) // Trim whitespace + if _, err := strconv.Atoi(elem); err != nil { // Check if it's an integer + return false + } +} + +if !hasCycle { + return true +} + +posPart := strings.TrimSpace(parts[1]) // Get the position part + +//Validate the position +posValue, err := strconv.Atoi(posPart) +if err != nil || posValue < 0 || posValue >= len(elements) { + return false +} + +return true +`), + OutputValidation: getPackagesAndFunction([]string{}, ` +return inputOrOutput == "true" || inputOrOutput == "false" +`), + }, + { + QuestionTitle: "Roman to Integer", + VisibleTestCases: ` +1 +III +3 +`, + HiddenTestCases: ` +2 +IV +4 +MCMXCIV +1994 +`, + InputValidation: getPackagesAndFunction([]string{"strings"}, ` +valid := "IVXLCDM" +for _, char := range inputOrOutput { + if !strings.ContainsRune(valid, char) { + return false + } +} +return true +`), + OutputValidation: getPackagesAndFunction([]string{"strconv"}, ` +_, err := strconv.Atoi(inputOrOutput) +return err == nil +`), + }, + { + QuestionTitle: "Add Binary", + VisibleTestCases: ` +1 +"11", "1" +"100" +`, + HiddenTestCases: ` +2 +"1010", "1011" +"10101" +"111", "111" +"1110" +`, + InputValidation: getPackagesAndFunction([]string{"regexp"}, ` +binaryRegex := regexp.MustCompile("^\"([01]+)\",\\s*\"([01]+)\"$") +return binaryRegex.MatchString(inputOrOutput) +`), + OutputValidation: getPackagesAndFunction([]string{"regexp"}, ` +binaryRegex := regexp.MustCompile("^\"([01]+)\"$") +return binaryRegex.MatchString(inputOrOutput) +`), + }, + { + QuestionTitle: "Fibonacci Number", + VisibleTestCases: ` +1 +0 +0 +`, + HiddenTestCases: ` +2 +1 +1 +10 +55 +`, + InputValidation: getPackagesAndFunction([]string{"strconv"}, ` +num, err := strconv.Atoi(inputOrOutput) +return err == nil && num >= 0 +`), + OutputValidation: getPackagesAndFunction([]string{"strconv"}, ` +num, err := strconv.Atoi(inputOrOutput) +return err == nil && num >= 0 +`), + }, + { + QuestionTitle: "Implement Stack using Queues", + VisibleTestCases: ` +1 +push(1), push(2), top() +2 +`, + HiddenTestCases: ` +2 +push(1), push(2), pop(), top() +1 +push(1), empty() +false +`, + InputValidation: getPackagesAndFunction([]string{"strconv", "strings"}, ` +// Split the line by commas to handle multiple operations +operations := strings.Split(inputOrOutput, ",") +for _, op := range operations { + op = strings.TrimSpace(op) // Trim whitespace + // Check if the operation is valid + if strings.HasPrefix(op, "push(") && strings.HasSuffix(op, ")") { + // Check if it's a push operation with a valid integer + numStr := op[5 : len(op)-1] // Extract the number string + if _, err := strconv.Atoi(numStr); err != nil { + return false + } + } else if op != "pop()" && op != "top()" && op != "empty()" { + // If the operation is not one of the valid ones + return false + } +} +return true +`), + OutputValidation: getPackagesAndFunction([]string{"strconv"}, ` +if inputOrOutput == "true" || inputOrOutput == "false" || inputOrOutput == "null" { + return true +} +_, err := strconv.Atoi(inputOrOutput) +return err == nil +`), + }, { + QuestionTitle: "Combine Two Tables", + VisibleTestCases: ` +1 +Person: [(1, "Smith", "John"), (2, "Doe", "Jane")], Address: [(1, 1, "NYC", "NY"), (2, 3, "LA", "CA")] +[("John", "Smith", "NYC", "NY"), ("Jane", "Doe", null, null)] +`, + HiddenTestCases: ` +2 +Person: [(1, "Black", "Jim")], Address: [(1, 1, "Miami", "FL")] +[("Jim", "Black", "Miami", "FL")] +Person: [(1, "White", "Mary")], Address: [] +[("Mary", "White", null, null)] +`, + InputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + OutputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + }, + { + QuestionTitle: "Repeated DNA Sequences", + VisibleTestCases: ` +1 +AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT +["AAAAACCCCC", "CCCCCAAAAA"] +`, + HiddenTestCases: ` +2 +AAAAAAAAAAAAA +["AAAAAAAAAA"] +ACGTACGTACGT +[] +`, + InputValidation: getPackagesAndFunction([]string{}, ` +input := inputOrOutput + +// Check that input length is at least 10 +if len(input) < 10 { + return false +} + +// Check that input contains only 'A', 'C', 'G', and 'T' +for _, ch := range input { + if ch != 'A' && ch != 'C' && ch != 'G' && ch != 'T' { + return false + } +} +return true +`), + OutputValidation: getPackagesAndFunction([]string{"strings"}, ` +output := inputOrOutput + +if output == "[]" { + return true +} + +// Check that the output is enclosed in square brackets +if len(output) < 2 || output[0] != '[' || output[len(output)-1] != ']' { + return false +} + +// Extract the content between square brackets +content := output[1 : len(output)-1] + +// Split by commas without trimming spaces +sequences := strings.Split(content, ", ") +for _, seq := range sequences { + // Check if each sequence is properly enclosed in double quotes and is exactly 10 characters + if len(seq) != 12 || seq[0] != '"' || seq[11] != '"' { + return false + } + + // Check that the sequence only contains valid DNA characters between the quotes + for i := 1; i < 11; i++ { + ch := seq[i] + if ch != 'A' && ch != 'C' && ch != 'G' && ch != 'T' { + return false + } + } +} +return true +`), + }, + { + QuestionTitle: "Course Schedule", + VisibleTestCases: ` +1 +2, [[1,0]] +true +`, + HiddenTestCases: ` +2 +2, [[1,0],[0,1]] +false +4, [[1,0],[2,0],[3,1],[3,2]] +true +`, + InputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + OutputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + }, + { + QuestionTitle: "LRU Cache Design", + VisibleTestCases: ` +1 +put(1, 1), put(2, 2), get(1) +1 +`, + HiddenTestCases: ` +2 +put(1, 1), put(2, 2), put(3, 3), get(2) +-1 +put(1, 1), put(2, 2), put(1, 10), get(1) +10 +`, + InputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + OutputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + }, + { + QuestionTitle: "Longest Common Subsequence", + VisibleTestCases: ` +1 +"abcde", "ace" +3 +`, + HiddenTestCases: ` +2 +"abc", "abc" +3 +"abc", "def" +0 +`, + InputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + OutputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + }, + { + QuestionTitle: "Rotate Image", + VisibleTestCases: ` +1 +[[1,2,3],[4,5,6],[7,8,9]] +[[7,4,1],[8,5,2],[9,6,3]] +`, + HiddenTestCases: ` +2 +[[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]] +[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]] +[[1]] +[[1]] +`, + InputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + OutputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + }, + { + QuestionTitle: "Airplane Seat Assignment Probability", + VisibleTestCases: ` +1 +1 +1.00000 +`, + HiddenTestCases: ` +2 +2 +0.50000 +3 +0.50000 +`, + InputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + OutputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + }, + { + QuestionTitle: "Validate Binary Search Tree", + VisibleTestCases: ` +1 +[2,1,3] +true +`, + HiddenTestCases: ` +2 +[5,1,4,null,null,3,6] +false +[1] +true +`, + InputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + OutputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + }, + { + QuestionTitle: "Sliding Window Maximum", + VisibleTestCases: ` +1 +[1,3,-1,-3,5,3,6,7], k=3 +[3,3,5,5,6,7] +`, + HiddenTestCases: ` +2 +[1, -1], k=1 +[1, -1] +[9, 11], k=2 +[11] +`, + InputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + OutputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + }, + { + QuestionTitle: "N-Queen Problem", + VisibleTestCases: ` +1 +4 +[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]] +`, + HiddenTestCases: ` +2 +1 +[["Q"]] +2 +[] +`, + InputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + OutputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + }, + { + QuestionTitle: "Serialize and Deserialize a Binary Tree", + VisibleTestCases: ` +1 +[1,2,3,null,null,4,5] +"1 2 null null 3 4 null null 5 null null" +`, + HiddenTestCases: ` +2 +[] +"null" +[1] +"1 null null" +`, + InputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + OutputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + }, + { + QuestionTitle: "Wildcard Matching", + VisibleTestCases: ` +1 +"aa", "a" +false +`, + HiddenTestCases: ` +2 +"aa", "*" +true +"cb", "?a" +false +`, + InputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + OutputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + }, + { + QuestionTitle: "Chalkboard XOR Game", + VisibleTestCases: ` +1 +[1,1,2] +false +`, + HiddenTestCases: ` +2 +[1,2,3] +true +[0,0,0] +true +`, + InputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + OutputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + }, + { + QuestionTitle: "Trips and Users", + VisibleTestCases: ` +1 +Trips: [(1, 1, 10, 'NYC', 'completed', '2013-10-01'), (2, 2, 11, 'NYC', 'cancelled_by_driver', '2013-10-01')],Users: [(10, 'No', 'client'), (11, 'No', 'driver')] +0.50 +`, + HiddenTestCases: ` +2 +Trips: [(1, 1, 10, 'NYC', 'completed', '2013-10-02')],Users: [(10, 'No', 'client'), (11, 'No', 'driver')] +0.00 +Trips: [(1, 1, 10, 'NYC', 'completed', '2013-10-03'), (2, 2, 11, 'NYC', 'cancelled_by_client', '2013-10-03')],Users: [(10, 'No', 'client'), (11, 'Yes', 'driver')] +0.00 +`, + InputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + OutputValidation: getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`), + }, + } + + for _, test := range tests { + if _, exists := questionTitleToDocRefIdMap[test.QuestionTitle]; !exists { + return fmt.Errorf("testcase's question title %s not found in questionTitleToDocRefIdMap", + test.QuestionTitle) + } + } + + for _, test := range tests { + _, err := ValidateTestCaseFormat(test.VisibleTestCases, test.InputValidation, test.OutputValidation) + if err != nil { + return fmt.Errorf("failed to validate visible test case format: %v", err) + } + _, err = ValidateTestCaseFormat(test.HiddenTestCases, test.InputValidation, test.OutputValidation) + if err != nil { + return fmt.Errorf("failed to validate hidden test case format: %v", err) + } + } + + for _, test := range tests { + _, _, err := client.Collection("tests").Add(ctx, map[string]interface{}{ + "questionDocRefId": questionTitleToDocRefIdMap[test.QuestionTitle], + "visibleTestCases": test.VisibleTestCases, + "hiddenTestCases": test.HiddenTestCases, + "createdAt": firestore.ServerTimestamp, + "updatedAt": firestore.ServerTimestamp, + }) + if err != nil { + return fmt.Errorf("failed to add test: %v", err) + } + } + + log.Println("Cleaned tests collection and repopulated tests.") + return nil +} + +func getPackagesAndFunction(imports []string, functionBody string) string { + // Use a string builder for efficient string concatenation + var importCode strings.Builder + + if len(imports) > 0 { + // Start the import block + importCode.WriteString("import (\n") + + // Iterate over the imports and add them to the builder + for _, imp := range imports { + importCode.WriteString(fmt.Sprintf("\t%q\n", imp)) + } + + // Close the import block + importCode.WriteString(")") + } + + // add tab before every line in functionBody including first line + functionBody = strings.ReplaceAll(functionBody, "\n", "\n\t") + + return fmt.Sprintf(` +%s + +func validateInputOrOutput(inputOrOutput string) bool { +%s +} +`, importCode.String(), functionBody) +} diff --git a/apps/execution-service/utils/testCase.go b/apps/execution-service/utils/testCase.go new file mode 100644 index 0000000000..919365256f --- /dev/null +++ b/apps/execution-service/utils/testCase.go @@ -0,0 +1,80 @@ +package utils + +import ( + "execution-service/models" + "fmt" + "strconv" + "strings" +) + +func GetTestLength(testCase string) (int, error) { + lines := strings.Split(strings.TrimSpace(testCase), "\n") + if len(lines) < 1 { + return 0, fmt.Errorf("test case format is incorrect, no lines found") + } + numCases, err := strconv.Atoi(lines[0]) + if err != nil { + return 0, fmt.Errorf("test case format is incorrect, first line must be an integer") + } + return numCases, nil +} + +func GetTestLengthAndUnexecutedCases(testCase string) (int, []models.IndividualTestResult, error) { + lines := strings.Split(strings.TrimSpace(testCase), "\n") + if len(lines) < 1 { + return 0, nil, fmt.Errorf("test case format is incorrect, no lines found") + } + + numCases, err := strconv.Atoi(lines[0]) + if err != nil { + return 0, nil, fmt.Errorf("test case format is incorrect, first line must be an integer") + } + + if len(lines) != 1+2*numCases { + return 0, nil, fmt.Errorf("test case format is incorrect, expected %d lines but got %d", 1+2*numCases, len(lines)) + } + + var testResults []models.IndividualTestResult + for i := 1; i < len(lines); i += 2 { + testResults = append(testResults, models.IndividualTestResult{ + Input: lines[i], + Expected: lines[i+1], + }) + } + return numCases, testResults, nil +} + +//func GetTestLengthAndExecutedCases(code string, testCase string) (int, []models.IndividualTestResult, error) { +// lines := strings.Split(strings.TrimSpace(testCase), "\n") +// if len(lines) < 1 { +// return 0, nil, fmt.Errorf("test case format is incorrect, no lines found") +// } +// +// numCases, err := strconv.Atoi(lines[0]) +// if err != nil { +// return 0, nil, fmt.Errorf("test case format is incorrect, first line must be an integer") +// } +// +// if len(lines) != 1+2*numCases { +// return 0, nil, fmt.Errorf("test case format is incorrect, expected %d lines but got %d", 1+2*numCases, len(lines)) +// } +// +// var testResults []models.IndividualTestResult +// for i := 1; i < len(lines); i += 2 { +// // execute code dynamically with input, and compare output with expected +// +// } +// +// numCases, testResults, err := GetTestLengthAndUnexecutedCases(testCase) +// if err != nil { +// return 0, nil, err +// } +// +// for i := range testCases { +// testCases[i].Actual = "" +// testCases[i].Passed = false +// testCases[i].Error = "" +// } +// +// return numCases, testCases, nil +//} diff --git a/apps/execution-service/utils/validateTestCaseFormat.go b/apps/execution-service/utils/validateTestCaseFormat.go new file mode 100644 index 0000000000..ef03752a1b --- /dev/null +++ b/apps/execution-service/utils/validateTestCaseFormat.go @@ -0,0 +1,87 @@ +package utils + +import ( + "fmt" + "strconv" + "strings" + + "github.com/traefik/yaegi/interp" + "github.com/traefik/yaegi/stdlib" +) + +func ValidateTestCaseFormat(testCase string, validateInputCode string, validateOutputCode string) (bool, error) { + lines := strings.Split(strings.TrimSpace(testCase), "\n") + + // Check if there is at least one line (the number of test cases line) + if len(lines) < 1 { + return false, fmt.Errorf("test case format is incorrect, no lines found") + } + + // Parse the first line to get the expected number of test cases + numCases, err := strconv.Atoi(lines[0]) + if err != nil { + return false, fmt.Errorf("test case format is incorrect, first line must be an integer") + } + + // Calculate the required number of lines: 1 for count + 2 lines per test case + expectedLines := 1 + 2*numCases + if len(lines) != expectedLines { + return false, fmt.Errorf("test case format is incorrect, expected %d lines but got %d", expectedLines, + len(lines)) + } + + println("test1") + + for i := 1; i < len(lines); i += 2 { + println("test2") + ok, err := validateInputOrOutputFormat(validateInputCode, lines[i]) + if err != nil { + return false, fmt.Errorf("error validating input: %v", err) + } + if !ok { + return false, fmt.Errorf("test case format is incorrect, input format is invalid") + } + println("test3") + ok, err = validateInputOrOutputFormat(validateOutputCode, lines[i+1]) + if err != nil { + return false, fmt.Errorf("error validating output: %v", err) + } + if !ok { + return false, fmt.Errorf("test case format is incorrect, output format is invalid") + } + println("test4") + } + println("test5") + + return true, nil +} + +func validateInputOrOutputFormat(validateInputOrOutputCode string, inputOrOutput string) (bool, error) { + // Initialize the yaegi interpreter + i := interp.New(interp.Options{}) + i.Use(stdlib.Symbols) + + // Create a Go function as a string and include the provided validation code + fullCode := fmt.Sprintf(` +package main +%s +`, validateInputOrOutputCode) + + println(fullCode) + + // Evaluate the function code + _, err := i.Eval(fullCode) + if err != nil { + return false, fmt.Errorf("error evaluating code: %v", err) + } + + // Retrieve the validateInput function from the interpreter + validateFunc, err := i.Eval("main.validateInputOrOutput") + if err != nil { + return false, fmt.Errorf("validateInputOrOutput function not found") + } + + // Call the function with the provided input + result := validateFunc.Interface().(func(string) bool)(inputOrOutput) + return result, nil +} diff --git a/apps/matching-service/.dockerignore b/apps/matching-service/.dockerignore new file mode 100644 index 0000000000..c6228e8d6c --- /dev/null +++ b/apps/matching-service/.dockerignore @@ -0,0 +1,9 @@ +.env.example + +.git +.gitignore + +.dockerignore +Dockerfile + +README.md diff --git a/apps/question-service/utils/populate.go b/apps/question-service/utils/populate.go index 140ee8393d..7aee788e7a 100644 --- a/apps/question-service/utils/populate.go +++ b/apps/question-service/utils/populate.go @@ -1,8 +1,13 @@ package utils import ( + "bytes" "context" + "encoding/json" + "fmt" "log" + "net/http" + "os" "question-service/models" "time" @@ -12,8 +17,9 @@ import ( // PopulateSampleQuestionsInTransaction deletes all existing questions and then adds new ones in a single transaction func populateSampleQuestionsInTransaction(ctx context.Context, client *firestore.Client) error { + // Sample questions to be added after deletion - sampleQuestions := []models.Question{ + var sampleQuestions = []models.Question{ { Title: "Reverse a String", Categories: []string{"Strings", "Algorithms"}, @@ -90,8 +96,8 @@ And table Address with the following columns: 4. state (varchar) addressId is the primary key. -Write a solution to report the first name, last name, city, and state of each person in the Person table. -If the address of a personId is not present in the Address table, +Write a solution to report the first name, last name, city, and state of each person in the Person table. +If the address of a personId is not present in the Address table, report null instead. Return the result table in any order.`, }, { @@ -293,6 +299,57 @@ Return the result table in any order.`, }) } +func repopulateTests(dbClient *firestore.Client) error { + ctx := context.Background() + + executionServiceUrl := os.Getenv("EXECUTION_SERVICE_URL") + url := executionServiceUrl + "tests/populate" + + // get title and docRefId of all questions + var questions []map[string]string + iter := dbClient.Collection("questions").Documents(ctx) + for { + doc, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { + return fmt.Errorf("failed to fetch question: %v", err) + } + + questions = append(questions, map[string]string{ + "title": doc.Data()["title"].(string), + "docRefId": doc.Ref.ID, + }) + } + + jsonData, err := json.Marshal(questions) + if err != nil { + return fmt.Errorf("failed to marshal question titles: %v", err) + } + + req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(jsonData)) + if err != nil { + return fmt.Errorf("failed to create request to populate tests: %v", err) + } + + req.Header.Set("Content-Type", "application/json") + + httpClient := &http.Client{} + resp, err := httpClient.Do(req) + if err != nil { + return fmt.Errorf("failed to populate tests: %v", err) + } + + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("failed to populate tests: %v", resp.Status) + } + + return nil +} + func Populate(client *firestore.Client) { ctx := context.Background() @@ -302,5 +359,12 @@ func Populate(client *firestore.Client) { log.Fatalf("Failed to populate sample questions in transaction: %v", err) } - log.Println("Counter reset, all questions deleted and sample questions added successfully in a transaction.") + // Populate testcases in the execution-service + err = repopulateTests(client) + if err != nil { + log.Fatalf("Failed to populate testcases: %v", err) + } + + log.Println("Counter reset, " + + "all questions deleted and sample questions added successfully in a transaction. Testcases repopulated in execution-service.") } From aa8be69591e2432e7444138d8abc2315b5649a55 Mon Sep 17 00:00:00 2001 From: solomonng2001 Date: Fri, 1 Nov 2024 22:44:40 +0800 Subject: [PATCH 105/258] Add .env.example --- apps/execution-service/.env.example | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 apps/execution-service/.env.example diff --git a/apps/execution-service/.env.example b/apps/execution-service/.env.example new file mode 100644 index 0000000000..1cf22d0894 --- /dev/null +++ b/apps/execution-service/.env.example @@ -0,0 +1,2 @@ +FIREBASE_CREDENTIAL_PATH=cs3219-staging-codeexecution-firebase-adminsdk-ce48j-00ab09514c.json +PORT=8083 \ No newline at end of file From a1232e7ef9b8c428edda9d44d92692effb6eeacf Mon Sep 17 00:00:00 2001 From: solomonng2001 Date: Fri, 1 Nov 2024 22:50:27 +0800 Subject: [PATCH 106/258] Add api test cases and api usage examples --- apps/execution-service/README.md | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/apps/execution-service/README.md b/apps/execution-service/README.md index eaa740b179..0bfc5593f1 100644 --- a/apps/execution-service/README.md +++ b/apps/execution-service/README.md @@ -86,3 +86,39 @@ In question-service, run the following command: ```bash go run main.go -populate ``` + +## API Documentation + +`GET /tests/{questionDocRefId}/` + +To read visible test cases via a question ID, run the following command: + +```bash +curl -X GET http://localhost:8083/tests/bmzFyLMeSOoYU99pi4yZ/ \ +-H "Content-Type: application/json" +``` + +`GET /tests/{questionDocRefId}/execute` + +To execute test cases via a question ID without custom test cases, run the following command, with custom code and language: + +```bash +curl -X POST http://localhost:8083/tests/{questionDocRefId}/execute \ +-H "Content-Type: application/json" \ +-d '{ +"code": "name = input()\nprint(name[::-1])", +"language": "Python" +}' +``` + +To execute test cases via a question ID with custom test cases, run the following command, with custom code, language and custom test cases: + +```bash +curl -X POST http://localhost:8083/tests/{questionDocRefId}/execute \ +-H "Content-Type: application/json" \ +-d '{ +"code": "name = input()\nprint(name[::-1])", +"language": "Python", +"customTestCases": "2\nHannah\nhannaH\nabcdefg\ngfedcba\n" +}' +``` From 547a2a13046cefccfccae1fc590c98e246eb6a2b Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sat, 2 Nov 2024 15:10:34 +0800 Subject: [PATCH 107/258] unit testing for question api functions --- apps/frontend/__tests__/Datetime.test.ts | 1 - .../__tests__/dependencymocking.test.ts | 34 ++ apps/frontend/__tests__/question.test.ts | 308 ++++++++++++++++++ apps/frontend/jest.config.ts | 4 +- apps/frontend/package.json | 2 +- apps/frontend/pnpm-lock.yaml | 14 +- 6 files changed, 357 insertions(+), 6 deletions(-) create mode 100644 apps/frontend/__tests__/dependencymocking.test.ts create mode 100644 apps/frontend/__tests__/question.test.ts diff --git a/apps/frontend/__tests__/Datetime.test.ts b/apps/frontend/__tests__/Datetime.test.ts index 7438ff5d67..8737f9ebe3 100644 --- a/apps/frontend/__tests__/Datetime.test.ts +++ b/apps/frontend/__tests__/Datetime.test.ts @@ -1,4 +1,3 @@ -import { describe, expect, it } from "@jest/globals" import { formatTime } from "@/utils/DateTime" describe("datetime module", () => { diff --git a/apps/frontend/__tests__/dependencymocking.test.ts b/apps/frontend/__tests__/dependencymocking.test.ts new file mode 100644 index 0000000000..0f21af7f43 --- /dev/null +++ b/apps/frontend/__tests__/dependencymocking.test.ts @@ -0,0 +1,34 @@ +import { GetQuestions } from "@/app/services/question" +import { getToken } from "@/app/services/login-store"; + +const TOKEN = 'mocktoken'; + +jest.mock("@/app/services/login-store", () => { + return { + __esModule: true, + getToken: jest.fn(() => TOKEN) + }; +}) + +beforeEach(() => { + global.fetch = jest.fn().mockResolvedValue({ + async json() { + return {} + } + }); +}) + +describe("mock", () => { + + it("mocks correctly", async () => { + await GetQuestions() + expect(jest.mocked(getToken).mock.calls).toEqual([[]]) + expect(jest.mocked(fetch).mock.calls[0][1]).toEqual({ + "headers": { + "Authorization": `Bearer ${TOKEN}`, + }, + "method": "GET", + }) + }); + +}) \ No newline at end of file diff --git a/apps/frontend/__tests__/question.test.ts b/apps/frontend/__tests__/question.test.ts new file mode 100644 index 0000000000..d363124591 --- /dev/null +++ b/apps/frontend/__tests__/question.test.ts @@ -0,0 +1,308 @@ +import { CreateQuestion, DeleteQuestion, GetQuestions, GetSingleQuestion, Question } from "@/app/services/question" + +const NEXT_PUBLIC_QUESTION_SERVICE_URL = process.env.NEXT_PUBLIC_QUESTION_SERVICE_URL + +const QUESTIONS = [ + { + "id": 12345, + "docRefId": "asdfDocRef", + "title": "Asdf", + "description": "Asdf description", + "categories": ["Arrays", "Algorithms"], + "complexity": "hard" + }, + { + "id": 12346, + "docRefId": "qwerDocRef", + "title": "Qwer", + "description": "Qwer description", + "categories": ["Strings", "Data Structures"], + "complexity": "medium" + }, + { + "id": 12347, + "docRefId": "zxcvDocRef", + "title": "Zxcv", + "description": "Zxcv description", + "categories": ["Graphs", "Algorithms"], + "complexity": "easy" + }, + { + "id": 12348, + "docRefId": "tyuiDocRef", + "title": "Tyui", + "description": "Tyui description", + "categories": ["Trees", "Recursion"], + "complexity": "hard" + }, + { + "id": 12349, + "docRefId": "ghjkDocRef", + "title": "Ghjk", + "description": "Ghjk description", + "categories": ["Dynamic Programming", "Math"], + "complexity": "medium" + }, + { + "id": 12350, + "docRefId": "bnmlDocRef", + "title": "Bnml", + "description": "Bnml description", + "categories": ["Sorting", "Searching"], + "complexity": "easy" + }, + { + "id": 12351, + "docRefId": "poiuDocRef", + "title": "Poiu", + "description": "Poiu description", + "categories": ["Bit Manipulation", "Algorithms"], + "complexity": "hard" + }, + { + "id": 12352, + "docRefId": "lkjhDocRef", + "title": "Lkjh", + "description": "Lkjh description", + "categories": ["Greedy", "Data Structures"], + "complexity": "medium" + }, + { + "id": 12353, + "docRefId": "mnbvDocRef", + "title": "Mnbv", + "description": "Mnbv description", + "categories": ["Backtracking", "Recursion"], + "complexity": "easy" + }, + { + "id": 12354, + "docRefId": "vcxzDocRef", + "title": "Vcxz", + "description": "Vcxz description", + "categories": ["Graphs", "Dynamic Programming"], + "complexity": "hard" + } +] + + +function createMockResponse(obj: any): Response { + // @ts-ignore don't need the whole response + return { + json: () => Promise.resolve(obj), + ok: true, + status: 200 + } +} + +const TOKEN = "mockjwttoken" + +beforeEach(() => { + window.localStorage["TOKEN"] = TOKEN +}) + +describe("GetQuestions", () => { + beforeEach(() => { + global.fetch = jest.fn().mockResolvedValue({ + async json() { + return QUESTIONS + } + }); + }) + + it("gets all questions on the first page with () call", async () => { + + const res = await GetQuestions() + + expect(jest.mocked(fetch).mock.calls).toStrictEqual([[`${NEXT_PUBLIC_QUESTION_SERVICE_URL}questions`, { + headers: { + "Authorization": `Bearer ${TOKEN}`, + }, + method: "GET", + }]]) + expect(res).toStrictEqual(QUESTIONS) + + }); + + it("gets all questions on the 2nd page with (2) call", async () => { + + const res = await GetQuestions(2) + + expect(jest.mocked(fetch).mock.calls).toStrictEqual([[`${NEXT_PUBLIC_QUESTION_SERVICE_URL}questions?offset=10`, { + headers: { + "Authorization": `Bearer ${TOKEN}`, + }, + method: "GET", + }]]) + }); + + it("gets all questions on the 2nd page with (limit=3) call", async () => { + + await GetQuestions(undefined, 3) + + expect(jest.mocked(fetch).mock.calls).toStrictEqual([[`${NEXT_PUBLIC_QUESTION_SERVICE_URL}questions?limit=3`, { + headers: { + "Authorization": `Bearer ${TOKEN}`, + }, + method: "GET", + }]]) + }); + + it("gets all questions on the 2nd page with (limit=3) call", async () => { + + await GetQuestions(undefined, undefined, "difficulty asc") + + expect(jest.mocked(fetch).mock.calls).toStrictEqual([[`${NEXT_PUBLIC_QUESTION_SERVICE_URL}questions?sortField=difficulty&sortValue=asc`, { + headers: { + "Authorization": `Bearer ${TOKEN}`, + }, + method: "GET", + }]]) + }); + + it("gets all questions on the 2nd page with (limit=3) call", async () => { + + await GetQuestions(undefined, undefined, undefined, ["easy", "hard"]) + + expect(jest.mocked(fetch).mock.calls).toStrictEqual([[`${NEXT_PUBLIC_QUESTION_SERVICE_URL}questions?complexity=easy,hard`, { + headers: { + "Authorization": `Bearer ${TOKEN}`, + }, + method: "GET", + }]]) + }); + + it("formats urls for categories", async () => { + + await GetQuestions(undefined, undefined, undefined, undefined, ["CatA", "CatB"]) + + expect(jest.mocked(fetch).mock.calls).toStrictEqual([[ + `${NEXT_PUBLIC_QUESTION_SERVICE_URL}questions?categories=CatA,CatB`, + { + headers: { + "Authorization": `Bearer ${TOKEN}`, + }, + method: "GET", + } + ]]) + }); + + it("formats url for title", async () => { + + await GetQuestions(undefined, undefined, undefined, undefined, undefined, "The Title Name") + + expect(jest.mocked(fetch).mock.calls).toStrictEqual([[ + `${NEXT_PUBLIC_QUESTION_SERVICE_URL}questions?title=The%20Title%20Name`, + { + headers: { + "Authorization": `Bearer ${TOKEN}`, + }, + method: "GET", + } + ]]) + }); +}) + + +describe("GetSingleQuestion", () => { + const DOCREF = "mockdocref"; + beforeEach(() => { + global.fetch = jest.fn().mockResolvedValue({ + async json() { + return QUESTIONS[0] + } + }); + }); + + it("gets a question by docref", async () => { + const res = await GetSingleQuestion(DOCREF); + + expect(jest.mocked(fetch).mock.calls).toStrictEqual([[`${NEXT_PUBLIC_QUESTION_SERVICE_URL}questions/${DOCREF}`, { + headers: { + "Authorization": `Bearer ${TOKEN}`, + }, + method: "GET", + }]]) + expect(res).toStrictEqual(QUESTIONS[0]); + }) +}) + +describe("CreateQuestion", () => { + it("uploads a question", async () => { + // grabs a subset of QUESTIONS[0] + const newQuestion = (({title, description, categories, complexity}) => ({title, description, categories, complexity}))(QUESTIONS[0]) + const createdQuestion = QUESTIONS[0]; + + global.fetch = jest.fn().mockResolvedValue({ + status: 200, + statusText: "OK", + async json() { + return createdQuestion + } + }); + + const res = await CreateQuestion(newQuestion); + + expect(jest.mocked(fetch).mock.calls).toStrictEqual([[`${NEXT_PUBLIC_QUESTION_SERVICE_URL}questions`, { + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${TOKEN}`, + }, + method: "POST", + body: JSON.stringify(newQuestion) + }]]) + expect(res).toStrictEqual(createdQuestion); + }) + + it("fails uploading question", async () => { + // grabs a subset of QUESTIONS[0] + const newQuestion = (({title, description, categories, complexity}) => ({title, description, categories, complexity}))(QUESTIONS[0]) + + global.fetch = jest.fn().mockResolvedValue({ + status: 400, + statusText: "Not Found", + data: "Question title already exists" + }) + + const res = CreateQuestion(newQuestion); + + expect(jest.mocked(fetch).mock.calls).toStrictEqual([[`${NEXT_PUBLIC_QUESTION_SERVICE_URL}questions`, { + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${TOKEN}`, + }, + method: "POST", + body: JSON.stringify(newQuestion) + }]]) + await expect(res).rejects.toThrow("Error creating question: 400 Not Found") + }) + + +}) + + +describe("DeleteQuestion", () => { + const DOCREF = "mockdocref"; + beforeEach(() => { + global.fetch = jest.fn().mockResolvedValue({ + status: 200, + statusText: "OK", + data: `Question with ID ${DOCREF} deleted successfully` + }); + }); + + it("deletes successfully", async () => { + const shouldbeNothing = await DeleteQuestion(DOCREF); + + expect(jest.mocked(fetch).mock.calls).toStrictEqual([[ + `${NEXT_PUBLIC_QUESTION_SERVICE_URL}questions/${DOCREF}`, + { + headers: { + "Authorization": `Bearer ${TOKEN}`, + }, + method: "DELETE", + } + ]]) + expect(shouldbeNothing).toBeUndefined(); + }) +}) diff --git a/apps/frontend/jest.config.ts b/apps/frontend/jest.config.ts index cf78af5d8e..689403a2dc 100644 --- a/apps/frontend/jest.config.ts +++ b/apps/frontend/jest.config.ts @@ -96,7 +96,9 @@ const config: Config = { // ], // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module - // moduleNameMapper: {}, + moduleNameMapper: { + '^@/(.*)$': '/src/$1', + }, // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader // modulePathIgnorePatterns: [], diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 5cd1b9a9e7..bd64735106 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -33,10 +33,10 @@ "yjs": "^13.6.20" }, "devDependencies": { - "@jest/globals": "^29.7.0", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.0.1", + "@types/jest": "^29.5.14", "@types/node": "^20", "@types/react": "^18.3.8", "@types/react-dom": "^18.3.0", diff --git a/apps/frontend/pnpm-lock.yaml b/apps/frontend/pnpm-lock.yaml index faff30a404..e890d035f0 100644 --- a/apps/frontend/pnpm-lock.yaml +++ b/apps/frontend/pnpm-lock.yaml @@ -72,9 +72,6 @@ importers: specifier: ^13.6.20 version: 13.6.20 devDependencies: - '@jest/globals': - specifier: ^29.7.0 - version: 29.7.0 '@testing-library/dom': specifier: ^10.4.0 version: 10.4.0 @@ -84,6 +81,9 @@ importers: '@testing-library/react': specifier: ^16.0.1 version: 16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@types/jest': + specifier: ^29.5.14 + version: 29.5.14 '@types/node': specifier: ^20 version: 20.0.0 @@ -752,6 +752,9 @@ packages: '@types/istanbul-reports@3.0.4': resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + '@types/jest@29.5.14': + resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} + '@types/jsdom@20.0.1': resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==} @@ -4005,6 +4008,11 @@ snapshots: dependencies: '@types/istanbul-lib-report': 3.0.3 + '@types/jest@29.5.14': + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + '@types/jsdom@20.0.1': dependencies: '@types/node': 20.0.0 From 97d6b6c106a9a80ce9a5bc0eda59519019dc7b3b Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sat, 2 Nov 2024 15:15:23 +0800 Subject: [PATCH 108/258] mock getToken for question.test.ts --- apps/frontend/__tests__/question.test.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/frontend/__tests__/question.test.ts b/apps/frontend/__tests__/question.test.ts index d363124591..417b4cc7aa 100644 --- a/apps/frontend/__tests__/question.test.ts +++ b/apps/frontend/__tests__/question.test.ts @@ -85,6 +85,12 @@ const QUESTIONS = [ } ] +jest.mock("@/app/services/login-store", () => { + return { + __esModule: true, + getToken: jest.fn(() => TOKEN) + }; +}) function createMockResponse(obj: any): Response { // @ts-ignore don't need the whole response @@ -97,10 +103,6 @@ function createMockResponse(obj: any): Response { const TOKEN = "mockjwttoken" -beforeEach(() => { - window.localStorage["TOKEN"] = TOKEN -}) - describe("GetQuestions", () => { beforeEach(() => { global.fetch = jest.fn().mockResolvedValue({ From c7a72bf8d5e700bbe14aa238618ee035aad12434 Mon Sep 17 00:00:00 2001 From: solomonng2001 Date: Sat, 2 Nov 2024 18:10:39 +0800 Subject: [PATCH 109/258] Add accepted or attempted status and dockerise --- apps/execution-service/.env.example | 8 +- apps/execution-service/Dockerfile | 4 +- apps/execution-service/README.md | 161 ++++++++++++++---- apps/execution-service/enums/language.go | 10 -- apps/execution-service/handlers/execute.go | 8 +- apps/execution-service/handlers/read.go | 2 +- apps/execution-service/handlers/submit.go | 121 +++++++++++++ apps/execution-service/main.go | 5 +- .../execution-service/models/collaboration.go | 13 ++ .../models/collaborationHistory.go | 21 +++ apps/execution-service/models/testResult.go | 13 +- apps/execution-service/test.go | 59 ------- apps/execution-service/utils/executeTest.go | 159 ++++++++--------- apps/execution-service/utils/testCase.go | 35 ---- apps/history-service/Dockerfile | 2 +- apps/history-service/handlers/create.go | 1 + .../handlers/createOrUpdate.go | 1 + apps/history-service/handlers/update.go | 2 + apps/history-service/main.go | 4 +- .../models/{models.go => collaboration.go} | 6 + apps/question-service/.env.example | 13 +- apps/signalling-service/.env.example | 3 +- 22 files changed, 407 insertions(+), 244 deletions(-) delete mode 100644 apps/execution-service/enums/language.go create mode 100644 apps/execution-service/handlers/submit.go create mode 100644 apps/execution-service/models/collaboration.go create mode 100644 apps/execution-service/models/collaborationHistory.go delete mode 100644 apps/execution-service/test.go rename apps/history-service/models/{models.go => collaboration.go} (88%) diff --git a/apps/execution-service/.env.example b/apps/execution-service/.env.example index 1cf22d0894..6a1fb0bd86 100644 --- a/apps/execution-service/.env.example +++ b/apps/execution-service/.env.example @@ -1,2 +1,8 @@ FIREBASE_CREDENTIAL_PATH=cs3219-staging-codeexecution-firebase-adminsdk-ce48j-00ab09514c.json -PORT=8083 \ No newline at end of file +PORT=8083 + +# If you are NOT USING docker, use the below variables +# HISTORY_SERVICE_URL=http://localhost:8082/ + +# If you are USING docker, use the below variables +HISTORY_SERVICE_URL=http://history-service:8082/ diff --git a/apps/execution-service/Dockerfile b/apps/execution-service/Dockerfile index 0cabe00edd..1a0bb66e44 100644 --- a/apps/execution-service/Dockerfile +++ b/apps/execution-service/Dockerfile @@ -7,12 +7,10 @@ COPY go.mod go.sum ./ RUN go mod tidy && go mod download && go mod verify -COPY .env /usr/src/app/.env - COPY . . RUN go build -v -o /usr/local/bin/app ./main.go -EXPOSE 8083 8083 +EXPOSE 8083 CMD ["app"] diff --git a/apps/execution-service/README.md b/apps/execution-service/README.md index 0bfc5593f1..fc84f1647a 100644 --- a/apps/execution-service/README.md +++ b/apps/execution-service/README.md @@ -1,43 +1,14 @@ # Execution Service -## Overview - -The Execution Service is built with Go, utilizing Firestore as the database and Chi as the HTTP router. It provides an API to manage test cases, such as populating test cases (via question-service), reading visible test cases and executing visible, hidden and custom test cases. - -## Features - -- Populate test cases (via populate questins in question-service) -- Read visible test cases via a question ID -- Execute visible test cases via a question ID - -## Technologies Used - -- Go (Golang) -- Firestore (Google Cloud Firestore) -- Chi (HTTP router) -- Yaegi (Go interpreter) - -## Getting Started - -### Prerequisites - -- Go 1.16 or later -- Google Cloud SDK -- Firestore database setup in your Google Cloud project - ### Installation -1. Clone the repository - -2. Set up your Firestore client - -3. Install dependencies: +1. Install dependencies: ```bash go mod tidy ``` -4. Create the `.env` file from copying the `.env.example`, and copy the firebase JSON file into execution-service/ fill in the `FIREBASE_CREDENTIAL_PATH` with the path of the firebase credential JSON file. +2. Create the `.env` file from copying the `.env.example`, and copy the firebase JSON file into execution-service/ fill in the `FIREBASE_CREDENTIAL_PATH` with the path of the firebase credential JSON file. ### Running the Application @@ -94,16 +65,27 @@ go run main.go -populate To read visible test cases via a question ID, run the following command: ```bash -curl -X GET http://localhost:8083/tests/bmzFyLMeSOoYU99pi4yZ/ \ +curl -X GET http://localhost:8083/tests/{questioinDocRefId}/ \ -H "Content-Type: application/json" ``` +The following json format will be returned: + +```json +[ + { + "input":"hello", + "expected":"olleh" + } +] +``` + `GET /tests/{questionDocRefId}/execute` To execute test cases via a question ID without custom test cases, run the following command, with custom code and language: ```bash -curl -X POST http://localhost:8083/tests/{questionDocRefId}/execute \ +curl -X POST http://localhost:8083/tests/{questioinDocRefId}/execute \ -H "Content-Type: application/json" \ -d '{ "code": "name = input()\nprint(name[::-1])", @@ -111,10 +93,27 @@ curl -X POST http://localhost:8083/tests/{questionDocRefId}/execute \ }' ``` -To execute test cases via a question ID with custom test cases, run the following command, with custom code, language and custom test cases: +The following json format will be returned: + +```json +{ + "visibleTestResults":[ + { + "input":"hello", + "expected":"olleh", + "actual":"olleh", + "passed":true, + "error":"" + } + ], + "customTestResults":null +} +``` + +To execute visible and custom test cases via a question ID with custom test cases, run the following command, with custom code, language and custom test cases: ```bash -curl -X POST http://localhost:8083/tests/{questionDocRefId}/execute \ +curl -X POST http://localhost:8083/tests/{questioinDocRefId}/execute \ -H "Content-Type: application/json" \ -d '{ "code": "name = input()\nprint(name[::-1])", @@ -122,3 +121,95 @@ curl -X POST http://localhost:8083/tests/{questionDocRefId}/execute \ "customTestCases": "2\nHannah\nhannaH\nabcdefg\ngfedcba\n" }' ``` + +The following json format will be returned: + +```json +{ + "visibleTestResults":[ + { + "input":"hello", + "expected":"olleh", + "actual":"olleh", + "passed":true, + "error":"" + } + ], + "customTestResults":[ + { + "input":"Hannah", + "expected":"hannaH", + "actual":"hannaH", + "passed":true, + "error":"" + }, + { + "input":"abcdefg", + "expected":"gfedcba", + "actual":"gfedcba", + "passed":true, + "error":"" + } + ] +} +``` + +To submit a solution and execute visible and hidden test cases via a question ID, run the following command, with custom code and language: + +```bash +curl -X POST http://localhost:8083/tests/{questioinDocRefId}/submit \ +-H "Content-Type: application/json" \ +-d '{ +"title": "Example Title", +"code": "name = input()\nprint(name[::-1])", +"language": "Python", +"user": "user123", +"matchedUser": "user456", +"matchId": "match123", +"matchedTopics": ["topic1", "topic2"], +"questionDifficulty": "Medium", +"questionTopics": ["Loops", "Strings"] +}' +``` + +The following json format will be returned: + +```json +{ + "visibleTestResults":[ + { + "input":"hello", + "expected":"olleh", + "actual":"olleh", + "passed":true, + "error":"" + } + ], + "hiddenTestResults":{ + "passed":2, + "total":2 + }, + "status":"Accepted" +} +``` + +If compilation error exists or any of the tests (visible and hidden) fails, status "Attempted" will be returned: + +```json +{ + "visibleTestResults":[ + { + "input":"hello", + "expected":"olleh", + "actual":"", + "passed":false, + "error":"Command execution failed: Traceback (most recent call last):\n File \"/tmp/4149249165.py\", line 2, in \u003cmodule\u003e\n prit(name[::-1])\n ^^^^\nNameError: name 'prit' is not defined. Did you mean: 'print'?\n: %!w(*exec.ExitError=\u0026{0x4000364678 []})" + } + ], + "hiddenTestResults":{ + "passed":0, + "total":2 + }, + "status":"Attempted" +} +``` diff --git a/apps/execution-service/enums/language.go b/apps/execution-service/enums/language.go deleted file mode 100644 index 7f40b81891..0000000000 --- a/apps/execution-service/enums/language.go +++ /dev/null @@ -1,10 +0,0 @@ -package enums - -// Create enums of languages -const ( - JAVA = "Java" - PYTHON = "Python" - GOLANG = "Golang" - JAVASCRIPT = "Javascript" - CPP = "C++" -) diff --git a/apps/execution-service/handlers/execute.go b/apps/execution-service/handlers/execute.go index e6cad62229..eda0d6ab60 100644 --- a/apps/execution-service/handlers/execute.go +++ b/apps/execution-service/handlers/execute.go @@ -9,7 +9,7 @@ import ( "net/http" ) -func (s *Service) ExecuteTest(w http.ResponseWriter, r *http.Request) { +func (s *Service) ExecuteVisibleAndCustomTests(w http.ResponseWriter, r *http.Request) { ctx := r.Context() questionDocRefId := chi.URLParam(r, "questionDocRefId") @@ -41,7 +41,7 @@ func (s *Service) ExecuteTest(w http.ResponseWriter, r *http.Request) { return } - testResults, err := utils.ExecuteTest(code, test) + testResults, err := utils.ExecuteVisibleAndCustomTests(code, test) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -52,14 +52,14 @@ func (s *Service) ExecuteTest(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(testResults) } -//curl -X POST http://localhost:8083/tests/bmzFyLMeSOoYU99pi4yZ/execute \ +//curl -X POST http://localhost:8083/tests/Yt29JjnIDpRwIlYAX8OF/execute \ //-H "Content-Type: application/json" \ //-d '{ //"code": "name = input()\nprint(name[::-1])", //"language": "Python" //}' -//curl -X POST http://localhost:8083/tests/bmzFyLMeSOoYU99pi4yZ/execute \ +//curl -X POST http://localhost:8083/tests/Yt29JjnIDpRwIlYAX8OF/execute \ //-H "Content-Type: application/json" \ //-d '{ //"code": "name = input()\nprint(name[::-1])", diff --git a/apps/execution-service/handlers/read.go b/apps/execution-service/handlers/read.go index db7fd4a21a..d8193c7b5a 100644 --- a/apps/execution-service/handlers/read.go +++ b/apps/execution-service/handlers/read.go @@ -9,7 +9,7 @@ import ( "net/http" ) -func (s *Service) ReadTest(w http.ResponseWriter, r *http.Request) { +func (s *Service) ReadVisibleTests(w http.ResponseWriter, r *http.Request) { ctx := r.Context() questionDocRefId := chi.URLParam(r, "questionDocRefId") diff --git a/apps/execution-service/handlers/submit.go b/apps/execution-service/handlers/submit.go new file mode 100644 index 0000000000..c38c0fb094 --- /dev/null +++ b/apps/execution-service/handlers/submit.go @@ -0,0 +1,121 @@ +package handlers + +import ( + "bytes" + "encoding/json" + "execution-service/models" + "execution-service/utils" + "github.com/go-chi/chi/v5" + "google.golang.org/api/iterator" + "net/http" + "os" +) + +func (s *Service) ExecuteVisibleAndHiddenTestsAndSubmit(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + questionDocRefId := chi.URLParam(r, "questionDocRefId") + if questionDocRefId == "" { + http.Error(w, "questionDocRefId is required", http.StatusBadRequest) + return + } + + var collab models.Collaboration + if err := utils.DecodeJSONBody(w, r, &collab); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + iter := s.Client.Collection("tests").Where("questionDocRefId", "==", questionDocRefId).Limit(1).Documents(ctx) + doc, err := iter.Next() + if err != nil { + if err == iterator.Done { + http.Error(w, "Test not found", http.StatusNotFound) + return + } + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + var test models.Test + if err := doc.DataTo(&test); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + testResults, err := utils.ExecuteVisibleAndHiddenTests(models.Code{ + Code: collab.Code, + Language: collab.Language, + }, test) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Save the collaboration history via the history-service + // TODO: convert to message queue + collabHistory := models.CollaborationHistory{ + Title: collab.Title, + Code: collab.Code, + Language: collab.Language, + User: collab.User, + MatchedUser: collab.MatchedUser, + MatchID: collab.MatchID, + MatchedTopics: collab.MatchedTopics, + QuestionDocRefID: questionDocRefId, + QuestionDifficulty: collab.QuestionDifficulty, + QuestionTopics: collab.QuestionTopics, + } + + jsonData, err := json.Marshal(collabHistory) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // get history-service url from os env + historyServiceUrl := os.Getenv("HISTORY_SERVICE_URL") + if historyServiceUrl == "" { + http.Error(w, "HISTORY_SERVICE_URL is not set", http.StatusInternalServerError) + return + } + + req, err := http.NewRequest(http.MethodPut, historyServiceUrl+"histories/match/"+collabHistory.MatchID, + bytes.NewBuffer(jsonData)) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + http.Error(w, "Failed to save collaboration history", http.StatusInternalServerError) + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(testResults) +} + +//curl -X POST http://localhost:8083/tests/Yt29JjnIDpRwIlYAX8OF/submit \ +//-H "Content-Type: application/json" \ +//-d '{ +//"title": "Example Title", +//"code": "name = input()\nprint(name[::-1])", +//"language": "Python", +//"user": "user123", +//"matchedUser": "user456", +//"matchId": "match123", +//"matchedTopics": ["topic1", "topic2"], +//"questionDifficulty": "Medium", +//"questionTopics": ["Loops", "Strings"] +//}' diff --git a/apps/execution-service/main.go b/apps/execution-service/main.go index e9991c5f82..706d0afcd6 100644 --- a/apps/execution-service/main.go +++ b/apps/execution-service/main.go @@ -90,8 +90,9 @@ func registerRoutes(r *chi.Mux, service *handlers.Service) { // Future extension: can be read by admin to view testcases //r.Put("/", service.UpdateTest) //r.Delete("/", service.DeleteTest) - r.Get("/", service.ReadTest) - r.Post("/execute", service.ExecuteTest) + r.Get("/", service.ReadVisibleTests) + r.Post("/execute", service.ExecuteVisibleAndCustomTests) + r.Post("/submit", service.ExecuteVisibleAndHiddenTestsAndSubmit) }) }) } diff --git a/apps/execution-service/models/collaboration.go b/apps/execution-service/models/collaboration.go new file mode 100644 index 0000000000..4986fbbe0e --- /dev/null +++ b/apps/execution-service/models/collaboration.go @@ -0,0 +1,13 @@ +package models + +type Collaboration struct { + Title string `json:"title" firestore:"title"` + Code string `json:"code" firestore:"code"` + Language string `json:"language" firestore:"language"` + User string `json:"user" firestore:"user"` + MatchedUser string `json:"matchedUser" firestore:"matchedUser"` + MatchID string `json:"matchId" firestore:"matchId"` + MatchedTopics []string `json:"matchedTopics" firestore:"matchedTopics"` + QuestionDifficulty string `json:"questionDifficulty" firestore:"questionDifficulty"` + QuestionTopics []string `json:"questionTopics" firestore:"questionTopics"` +} diff --git a/apps/execution-service/models/collaborationHistory.go b/apps/execution-service/models/collaborationHistory.go new file mode 100644 index 0000000000..4b6a5ced37 --- /dev/null +++ b/apps/execution-service/models/collaborationHistory.go @@ -0,0 +1,21 @@ +package models + +import "time" + +type CollaborationHistory struct { + Title string `json:"title"` + Code string `json:"code"` + Language string `json:"language"` + User string `json:"user"` + MatchedUser string `json:"matchedUser"` + MatchID string `json:"matchId"` + MatchedTopics []string `json:"matchedTopics"` + QuestionDocRefID string `json:"questionDocRefId"` + QuestionDifficulty string `json:"questionDifficulty"` + QuestionTopics []string `json:"questionTopics"` + Status string `json:"status"` + + // Special DB fields + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` +} diff --git a/apps/execution-service/models/testResult.go b/apps/execution-service/models/testResult.go index df60799cd1..e0843acb72 100644 --- a/apps/execution-service/models/testResult.go +++ b/apps/execution-service/models/testResult.go @@ -6,12 +6,23 @@ type TestResults struct { CustomTestResults []IndividualTestResult `json:"customTestResults"` } +type ExecutionResults struct { + VisibleTestResults []IndividualTestResult `json:"visibleTestResults"` + CustomTestResults []IndividualTestResult `json:"customTestResults"` +} + +type SubmissionResults struct { + VisibleTestResults []IndividualTestResult `json:"visibleTestResults"` + HiddenTestResults GeneralTestResults `json:"hiddenTestResults"` + Status string `json:"status"` +} + type IndividualTestResult struct { Input string `json:"input"` Expected string `json:"expected"` Actual string `json:"actual"` Passed bool `json:"passed"` - Error string `json:"error,omitempty"` + Error string `json:"error"` } type GeneralTestResults struct { diff --git a/apps/execution-service/test.go b/apps/execution-service/test.go deleted file mode 100644 index 8af33b0676..0000000000 --- a/apps/execution-service/test.go +++ /dev/null @@ -1,59 +0,0 @@ -package main - -import ( - "execution-service/execution/python" -) - -func main() { - println("testing: ") - output, errorOutput, _ := test() - println("output: ", output) - println("errorOutput: ", errorOutput) -} - -//func test() bool { -// inputOrOutput := `[]` -// -// output := inputOrOutput -// -// if output == "[]" { -// return true -// } -// -// // Check that the output is enclosed in square brackets -// if len(output) < 2 || output[0] != '[' || output[len(output)-1] != ']' { -// return false -// } -// -// // Extract the content between square brackets -// content := output[1 : len(output)-1] -// -// // Split by commas without trimming spaces -// sequences := strings.Split(content, ", ") -// for _, seq := range sequences { -// // Check if each sequence is properly enclosed in double quotes and is exactly 10 characters -// if len(seq) != 12 || seq[0] != '"' || seq[11] != '"' { -// return false -// } -// -// // Check that the sequence only contains valid DNA characters between the quotes -// for i := 1; i < 11; i++ { -// ch := seq[i] -// if ch != 'A' && ch != 'C' && ch != 'G' && ch != 'T' { -// return false -// } -// } -// } -// return true -//} - -func test() (string, string, error) { - code := ` -nam = input() -print(name[::-1]) -` - - input := "hello" - - return python.RunPythonCode(code, input) -} diff --git a/apps/execution-service/utils/executeTest.go b/apps/execution-service/utils/executeTest.go index cdc3853777..b51051ca3e 100644 --- a/apps/execution-service/utils/executeTest.go +++ b/apps/execution-service/utils/executeTest.go @@ -1,57 +1,59 @@ package utils import ( - "execution-service/enums" "execution-service/execution/python" "execution-service/models" "fmt" ) -func ExecuteTest(code models.Code, test models.Test) (models.TestResults, error) { +const ( + JAVA = "Java" + PYTHON = "Python" + GOLANG = "Golang" + JAVASCRIPT = "Javascript" + CPP = "C++" +) + +const ( + ACCEPTED = "Accepted" + ATTEMPTED = "Attempted" +) + +func ExecuteVisibleAndCustomTests(code models.Code, test models.Test) (models.ExecutionResults, error) { var err error - var testResults models.TestResults + var testResults models.ExecutionResults switch code.Language { - case enums.PYTHON: - testResults, err = getTestResultFromTest(code, test, python.RunPythonCode) + case PYTHON: + testResults, err = getVisibleAndCustomTestResults(code, test, python.RunPythonCode) break default: - return models.TestResults{}, fmt.Errorf("unsupported language: %s", code.Language) + return models.ExecutionResults{}, fmt.Errorf("unsupported language: %s", code.Language) } if err != nil { - return models.TestResults{}, err + return models.ExecutionResults{}, err } return testResults, nil } -//func getVisibleTestResultsWithCompilationError(test models.Test, -// testCaseErrorStr string) ([]models.IndividualTestResult, error) { -// _, visibleTestResults, err := GetTestLengthAndUnexecutedCases(test.VisibleTestCases) -// if err != nil { -// return nil, err -// } -// -// for _, visibleTestResult := range visibleTestResults { -// visibleTestResult.Actual = "" -// visibleTestResult.Passed = false -// visibleTestResult.Error = testCaseErrorStr -// } -// -// return visibleTestResults, nil -//} -// -//func getHiddenTestResultsWithCompilationError(test models.Test) (models.GeneralTestResults, error) { -// numHiddenTests, err := GetTestLength(test.HiddenTestCases) -// if err != nil { -// return models.GeneralTestResults{}, err -// } -// -// return models.GeneralTestResults{ -// Passed: 0, -// Total: numHiddenTests, -// }, nil -//} +func ExecuteVisibleAndHiddenTests(code models.Code, test models.Test) (models.SubmissionResults, error) { + var err error + var testResults models.SubmissionResults + + switch code.Language { + case PYTHON: + testResults, err = getVisibleAndHiddenTestResults(code, test, python.RunPythonCode) + break + default: + return models.SubmissionResults{}, fmt.Errorf("unsupported language: %s", code.Language) + } + if err != nil { + return models.SubmissionResults{}, err + } + + return testResults, nil +} func getIndividualTestResultFromCodeExecutor(code string, unexecutedTestResult models.IndividualTestResult, executor func(string, string) (string, string, error)) (models.IndividualTestResult, error) { @@ -108,72 +110,55 @@ func getGenericTestResultsFromFormattedTestCase(code string, testCase string, }, nil } -func getTestResultFromTest(code models.Code, test models.Test, - executor func(string, string) (string, string, error)) (models.TestResults, error) { +func getVisibleAndCustomTestResults(code models.Code, test models.Test, + executor func(string, string) (string, string, error)) (models.ExecutionResults, error) { visibleTestResults, err := getAllTestResultsFromFormattedTestCase(code.Code, test.VisibleTestCases, executor) if err != nil { - return models.TestResults{}, err - } - - hiddenTestResults, err := getGenericTestResultsFromFormattedTestCase(code.Code, test.HiddenTestCases, executor) - if err != nil { - return models.TestResults{}, err + return models.ExecutionResults{}, err } var customTestResults []models.IndividualTestResult if code.CustomTestCases != "" { customTestResults, err = getAllTestResultsFromFormattedTestCase(code.Code, code.CustomTestCases, executor) if err != nil { - return models.TestResults{}, err + return models.ExecutionResults{}, err } } - return models.TestResults{ + return models.ExecutionResults{ VisibleTestResults: visibleTestResults, - HiddenTestResults: hiddenTestResults, CustomTestResults: customTestResults, }, nil } -//func getVisibleTestResults(code string, test models.Test) ([]models.IndividualTestResult, error) { -// _, visibleTestResults, err := GetTestLengthAndUnexecutedCases(test.VisibleTestCases) -// if err != nil { -// return nil, err -// } -// -// // Initialize Yaegi interpreter -// i := interp.New(interp.Options{}) -// i.Use(stdlib.Symbols) -// -// _, err = i.Eval(code) -// if err != nil { -// return nil, fmt.Errorf("error evaluating code: %v", err) -// } -// -// // Execute each test case -// for _, visibleTestResult := range visibleTestResults { -// // Create an output buffer to capture stdout -// var stdout bytes.Buffer -// i.Stdout = &stdout -// -// // Set up the input for the test case -// input := strings.NewReader(visibleTestResult.Input + "\n") -// i.Stdin = input -// -// // Run the code -// _, err := i.Eval("main.main()") -// if err != nil { -// visibleTestResult.Actual = "" -// visibleTestResult.Passed = false -// visibleTestResult.Error = err.Error() -// continue -// } -// -// actualOutput := strings.TrimSpace(stdout.String()) -// -// visibleTestResult.Actual = actualOutput -// visibleTestResult.Passed = actualOutput == visibleTestResult.Expected -// } -// -// return visibleTestResults, nil -//} +func getVisibleAndHiddenTestResults(code models.Code, test models.Test, + executor func(string, string) (string, string, error)) (models.SubmissionResults, error) { + visibleTestResults, err := getAllTestResultsFromFormattedTestCase(code.Code, test.VisibleTestCases, executor) + if err != nil { + return models.SubmissionResults{}, err + } + + hiddenTestResults, err := getGenericTestResultsFromFormattedTestCase(code.Code, test.HiddenTestCases, executor) + if err != nil { + return models.SubmissionResults{}, err + } + + status := ACCEPTED + if hiddenTestResults.Passed != hiddenTestResults.Total { + status = ATTEMPTED + } + if status == ACCEPTED { + for _, testResult := range visibleTestResults { + if !testResult.Passed { + status = ATTEMPTED + break + } + } + } + + return models.SubmissionResults{ + VisibleTestResults: visibleTestResults, + HiddenTestResults: hiddenTestResults, + Status: status, + }, nil +} diff --git a/apps/execution-service/utils/testCase.go b/apps/execution-service/utils/testCase.go index 919365256f..c353f98220 100644 --- a/apps/execution-service/utils/testCase.go +++ b/apps/execution-service/utils/testCase.go @@ -43,38 +43,3 @@ func GetTestLengthAndUnexecutedCases(testCase string) (int, []models.IndividualT } return numCases, testResults, nil } - -//func GetTestLengthAndExecutedCases(code string, testCase string) (int, []models.IndividualTestResult, error) { -// lines := strings.Split(strings.TrimSpace(testCase), "\n") -// if len(lines) < 1 { -// return 0, nil, fmt.Errorf("test case format is incorrect, no lines found") -// } -// -// numCases, err := strconv.Atoi(lines[0]) -// if err != nil { -// return 0, nil, fmt.Errorf("test case format is incorrect, first line must be an integer") -// } -// -// if len(lines) != 1+2*numCases { -// return 0, nil, fmt.Errorf("test case format is incorrect, expected %d lines but got %d", 1+2*numCases, len(lines)) -// } -// -// var testResults []models.IndividualTestResult -// for i := 1; i < len(lines); i += 2 { -// // execute code dynamically with input, and compare output with expected -// -// } -// -// numCases, testResults, err := GetTestLengthAndUnexecutedCases(testCase) -// if err != nil { -// return 0, nil, err -// } -// -// for i := range testCases { -// testCases[i].Actual = "" -// testCases[i].Passed = false -// testCases[i].Error = "" -// } -// -// return numCases, testCases, nil -//} diff --git a/apps/history-service/Dockerfile b/apps/history-service/Dockerfile index 325d4e3751..d26f475e62 100644 --- a/apps/history-service/Dockerfile +++ b/apps/history-service/Dockerfile @@ -11,6 +11,6 @@ COPY . . RUN go build -v -o /usr/local/bin/app ./main.go -EXPOSE 8082 8082 +EXPOSE 8082 CMD ["app"] diff --git a/apps/history-service/handlers/create.go b/apps/history-service/handlers/create.go index d981fb9190..9b4681adc6 100644 --- a/apps/history-service/handlers/create.go +++ b/apps/history-service/handlers/create.go @@ -33,6 +33,7 @@ func (s *Service) CreateHistory(w http.ResponseWriter, r *http.Request) { "questionDocRefId": collaborationHistory.QuestionDocRefID, "questionDifficulty": collaborationHistory.QuestionDifficulty, "questionTopics": collaborationHistory.QuestionTopics, + "status": collaborationHistory.Status, "createdAt": firestore.ServerTimestamp, "updatedAt": firestore.ServerTimestamp, }) diff --git a/apps/history-service/handlers/createOrUpdate.go b/apps/history-service/handlers/createOrUpdate.go index f9df4bcc33..67f9195873 100644 --- a/apps/history-service/handlers/createOrUpdate.go +++ b/apps/history-service/handlers/createOrUpdate.go @@ -41,6 +41,7 @@ func (s *Service) CreateOrUpdateHistory(w http.ResponseWriter, r *http.Request) "questionDocRefId": collaborationHistory.QuestionDocRefID, "questionDifficulty": collaborationHistory.QuestionDifficulty, "questionTopics": collaborationHistory.QuestionTopics, + "status": collaborationHistory.Status, "createdAt": firestore.ServerTimestamp, "updatedAt": firestore.ServerTimestamp, }) diff --git a/apps/history-service/handlers/update.go b/apps/history-service/handlers/update.go index b6cb953709..2a79277dbb 100644 --- a/apps/history-service/handlers/update.go +++ b/apps/history-service/handlers/update.go @@ -42,6 +42,8 @@ func (s *Service) UpdateHistory(w http.ResponseWriter, r *http.Request) { // Prepare the update data. updates := []firestore.Update{ {Path: "code", Value: updatedHistory.Code}, + {Path: "language", Value: updatedHistory.Language}, + {Path: "status", Value: updatedHistory.Status}, {Path: "updatedAt", Value: firestore.ServerTimestamp}, } diff --git a/apps/history-service/main.go b/apps/history-service/main.go index cf69c934d2..e61c58fc02 100644 --- a/apps/history-service/main.go +++ b/apps/history-service/main.go @@ -75,10 +75,10 @@ func initChiRouter(service *handlers.Service) *chi.Mux { func registerRoutes(r *chi.Mux, service *handlers.Service) { r.Route("/histories", func(r chi.Router) { - r.Get("/{username}", service.ListUserHistories) + r.Get("/user/{username}", service.ListUserHistories) //r.Post("/", service.CreateHistory) - r.Route("/{matchId}", func(r chi.Router) { + r.Route("/match/{matchId}", func(r chi.Router) { r.Put("/", service.CreateOrUpdateHistory) r.Get("/", service.ReadHistory) //r.Put("/", service.UpdateHistory) diff --git a/apps/history-service/models/models.go b/apps/history-service/models/collaboration.go similarity index 88% rename from apps/history-service/models/models.go rename to apps/history-service/models/collaboration.go index 9928b8809b..da5e1f821b 100644 --- a/apps/history-service/models/models.go +++ b/apps/history-service/models/collaboration.go @@ -2,6 +2,11 @@ package models import "time" +const ( + ACCEPTED = "Accepted" + ATTEMPTED = "Attempted" +) + type CollaborationHistory struct { Title string `json:"title" firestore:"title"` Code string `json:"code" firestore:"code"` @@ -13,6 +18,7 @@ type CollaborationHistory struct { QuestionDocRefID string `json:"questionDocRefId" firestore:"questionDocRefId"` QuestionDifficulty string `json:"questionDifficulty" firestore:"questionDifficulty"` QuestionTopics []string `json:"questionTopics" firestore:"questionTopics"` + Status string `json:"status" firestore:"status"` // Special DB fields CreatedAt time.Time `json:"createdAt" firestore:"createdAt"` diff --git a/apps/question-service/.env.example b/apps/question-service/.env.example index 88d758a7be..ed0273c62c 100644 --- a/apps/question-service/.env.example +++ b/apps/question-service/.env.example @@ -1,5 +1,14 @@ # Path to the firebase credential json -FIREBASE_CREDENTIAL_PATH=cs3219-g24-firebase-adminsdk-9cm7h-b1675603ab.json +# Staging +FIREBASE_CREDENTIAL_PATH=cs3219-g24-staging-firebase-adminsdk-suafv-9c0d1b2299.json +# Production +# FIREBASE_CREDENTIAL_PATH=cs3219-g24-firebase-adminsdk-9cm7h-b1675603ab.json # Secret for creating JWT signature -JWT_SECRET=you-can-replace-this-with-your-own-secret \ No newline at end of file +JWT_SECRET=you-can-replace-this-with-your-own-secret + +# If you are NOT USING docker, use the below variables +EXECUTION_SERVICE_URL="http://localhost:8083/" + +# If you are USING docker, use the below variables +# EXECUTION_SERVICE_URL="http://execution-service:8083/" \ No newline at end of file diff --git a/apps/signalling-service/.env.example b/apps/signalling-service/.env.example index 37300b8cdf..1b5ecaa58f 100644 --- a/apps/signalling-service/.env.example +++ b/apps/signalling-service/.env.example @@ -1 +1,2 @@ -PORT=4444 \ No newline at end of file +PORT=4444 +JWT_SECRET=you-can-replace-this-with-your-own-secret \ No newline at end of file From 7994e7fce294b20c7498bb55763bc4db2847e8a0 Mon Sep 17 00:00:00 2001 From: solomonng2001 Date: Sat, 2 Nov 2024 18:27:25 +0800 Subject: [PATCH 110/258] Update test.yml --- .github/workflows/test.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 82bd2743a4..9f26302336 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -31,14 +31,17 @@ jobs: MATCHING_SERVICE_URL: ${{ vars.MATCHING_SERVICE_URL }} HISTORY_SERVICE_URL: ${{ vars.HISTORY_SERVICE_URL }} SIGNALLING_SERVICE_URL: ${{ vars.SIGNALLING_SERVICE_URL }} + EXECUTION_SERVICE_URL: ${{ vars.EXECUTION_SERVICE_URL }} JWT_SECRET: ${{ secrets.JWT_SECRET }} QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} HISTORY_FIREBASE_CREDENTIAL_PATH: ${{ vars.HISTORY_SERVICE_FIREBASE_CREDENTIAL_PATH }} + EXECUTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.EXECUTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} DB_CLOUD_URI: ${{ secrets.USER_SERVICE_DB_CLOUD_URI }} USER_SERVICE_PORT: ${{ vars.USER_SERVICE_PORT }} MATCHING_SERVICE_PORT: ${{ vars.MATCHING_SERVICE_PORT }} HISTORY_SERVICE_PORT: ${{ vars.HISTORY_SERVICE_PORT }} SIGNALLING_SERVICE_PORT: ${{ vars.SIGNALLING_SERVICE_PORT }} + EXECUTION_SERVICE_PORT: ${{ vars.EXECUTION_SERVICE_PORT }} MATCHING_SERVICE_TIMEOUT: ${{ vars.MATCHING_SERVICE_TIMEOUT }} REDIS_URL: ${{ vars.REDIS_URL }} QUESTION_SERVICE_GRPC_URL: ${{ vars.QUESTION_SERVICE_GPRC_URL }} @@ -49,6 +52,7 @@ jobs: echo "NEXT_PUBLIC_MATCHING_SERVICE_URL=$MATCHING_SERVICE_URL" >> .env echo "NEXT_PUBLIC_HISTORY_SERVICE_URL=$HISTORY_SERVICE_URL" >> .env echo "NEXT_PUBLIC_SIGNALLING_SERVICE_URL=$SIGNALLING_SERVICE_URL" >> .env + echo "NEXT_PUBLIC_EXECUTION_SERVICE_URL=$SIGNALLING_SERVICE_URL" >> .env cd ../question-service echo "FIREBASE_CREDENTIAL_PATH=$QUESTION_FIREBASE_CREDENTIAL_PATH" >> .env @@ -69,6 +73,11 @@ jobs: cd ../history-service echo "FIREBASE_CREDENTIAL_PATH=$HISTORY_FIREBASE_CREDENTIAL_PATH" >> .env echo "PORT=$HISTORY_SERVICE_PORT" >> .env + + cd ../execution-service + echo "FIREBASE_CREDENTIAL_PATH=$EXECUTION_FIREBASE_CREDENTIAL_PATH" >> .env + echo "PORT=$EXECUTION_SERVICE_PORT" >> .env + echo "HISTORY_SERVICE_URL=$HISTORY_SERVICE_URL" >> .env cd ../signalling-service echo "PORT=$SIGNALLING_SERVICE_PORT" >> .env @@ -79,12 +88,17 @@ jobs: QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} HISTORY_FIREBASE_JSON: ${{ secrets.HISTORY_SERVICE_FIREBASE_CREDENTIAL }} HISTORY_FIREBASE_CREDENTIAL_PATH: ${{ vars.HISTORY_SERVICE_FIREBASE_CREDENTIAL_PATH }} + EXECUTION_FIREBASE_JSON: ${{ secrets.EXECUTION_SERVICE_FIREBASE_CREDENTIAL }} + EXECUTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.EXECUTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} run: | cd ./apps/question-service echo "$QUESTION_FIREBASE_JSON" > "./$QUESTION_FIREBASE_CREDENTIAL_PATH" cd ../history-service echo "$HISTORY_FIREBASE_JSON" > "./$HISTORY_FIREBASE_CREDENTIAL_PATH" + + cd ../execution-service + echo "$EXECUTION_FIREBASE_JSON" > "./$EXECUTION_FIREBASE_CREDENTIAL_PATH" - name: Build and Run Services run: | @@ -108,6 +122,7 @@ jobs: MATCHING_SERVICE_URL: ${{ vars.MATCHING_SERVICE_URL }} HISTORY_SERVICE_URL: ${{ vars.HISTORY_SERVICE_URL }} SIGNALLING_SERVICE_URL: ${{ vars.SIGNALLING_SERVICE_URL }} + EXECUTION_SERVICE_URL: ${{ vars.EXECUTION_SERVICE_URL }} run: | echo "Testing Question Service..." curl -sSL -o /dev/null $QUESTION_SERVICE_URL && echo "Question Service is up" @@ -117,6 +132,8 @@ jobs: curl -fsSL -o /dev/null $FRONTEND_URL && echo "Frontend is up" echo "Testing History Service..." curl -fsSL -o /dev/null $HISTORY_SERVICE_URL && echo "History Service is up" + echo "Testing Execution Service..." + curl -fsSL -o /dev/null $EXECUTION_SERVICE_URL && echo "Execution Service is up" echo "Testing Matching Service..." if ! (echo "Hello" | websocat $MATCHING_SERVICE_URL); then echo "WebSocket for Matching Service is not live" From a23a7b470e0026a70f1ace7cd87d81dfee12ea01 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 3 Nov 2024 03:55:43 +0800 Subject: [PATCH 111/258] add unit test for utils/encode --- apps/question-service/utils/decode_test.go | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 apps/question-service/utils/decode_test.go diff --git a/apps/question-service/utils/decode_test.go b/apps/question-service/utils/decode_test.go new file mode 100644 index 0000000000..7ee3744359 --- /dev/null +++ b/apps/question-service/utils/decode_test.go @@ -0,0 +1,44 @@ +package utils + +import ( + "net/http" + "net/http/httptest" + "strings" + "testing" +) + +type CustomObj struct { + StrType string `json:"str"` + NumType int64 `json:"num"` +} + +func TestXd(t *testing.T) { + t.Run("parses string correctly", func(t *testing.T) { + var obj CustomObj + req := httptest.NewRequest(http.MethodGet, "/", strings.NewReader(`{"str": "asd", "num":64}`)) + err := DecodeJSONBody(nil, req, &obj) + + if err != nil { + t.Errorf("err should be nil but got %q instead", err) + } + + if (obj != CustomObj{"asd", 64}) { + t.Errorf("obj should be asd,64 but got %v instead", obj) + } + }) + t.Run("fails with incorrect object", func(t *testing.T) { + var obj CustomObj + req := httptest.NewRequest(http.MethodGet, "/", strings.NewReader(`{"str": "asd", "num":64 `)) + err := DecodeJSONBody(nil, req, &obj) + const expected = "Invalid request payload: unexpected EOF" + + if err == nil { + t.Errorf("err should be nil but got %q instead", err) + } + + if err.Error() != expected { + t.Errorf("err should be \"%s\" but got %q instead", expected, err) + } + }) + +} From 435765a495d3b410429004be140fc2e5f1184e67 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 3 Nov 2024 04:04:21 +0800 Subject: [PATCH 112/258] Add testing workflow part 1.. --- .github/workflows/test.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 82bd2743a4..20bdda516f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,7 +11,34 @@ on: - main - staging + jobs: + question-service-tests: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Set up .env + run: | + echo ./apps/question-service/.env.example > .env + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: '1.23.x' + + - name: Install dependencies + run: | + cd ./apps/question-service + go mod tidy + + - name: Run tests + run: | + cd ./apps/question-service + go test + test: runs-on: ubuntu-latest From 5a8f8ffa867b7f3b31a3f8ab917bf4a1950e256d Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 3 Nov 2024 04:13:32 +0800 Subject: [PATCH 113/258] asd --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 20bdda516f..a436f34556 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,7 +37,7 @@ jobs: - name: Run tests run: | cd ./apps/question-service - go test + go test ./... test: runs-on: ubuntu-latest From 8eb66f44d0bd4d10befcf024d1c13745ab8f32a7 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Sun, 3 Nov 2024 04:34:44 +0800 Subject: [PATCH 114/258] feat: update frontend for question page --- .../src/app/collaboration/[id]/page.tsx | 68 +---- .../src/app/collaboration/[id]/styles.scss | 33 -- apps/frontend/src/app/question/[id]/page.tsx | 234 ++++++--------- .../src/app/question/[id]/styles.scss | 284 +++++++----------- .../QuestionDetail/QuestionDetail.tsx | 42 +++ .../question/QuestionDetail/styles.scss | 30 ++ .../QuestionDetailFull/QuestionDetailFull.tsx | 35 +++ .../question/QuestionDetailFull/styles.scss | 9 + .../TestcaseDetail/TestcaseDetail.tsx | 60 ++++ .../question/TestcaseDetail/styles.scss | 24 ++ 10 files changed, 404 insertions(+), 415 deletions(-) create mode 100644 apps/frontend/src/components/question/QuestionDetail/QuestionDetail.tsx create mode 100644 apps/frontend/src/components/question/QuestionDetail/styles.scss create mode 100644 apps/frontend/src/components/question/QuestionDetailFull/QuestionDetailFull.tsx create mode 100644 apps/frontend/src/components/question/QuestionDetailFull/styles.scss create mode 100644 apps/frontend/src/components/question/TestcaseDetail/TestcaseDetail.tsx create mode 100644 apps/frontend/src/components/question/TestcaseDetail/styles.scss diff --git a/apps/frontend/src/app/collaboration/[id]/page.tsx b/apps/frontend/src/app/collaboration/[id]/page.tsx index 41c56023f0..ee538edbf2 100644 --- a/apps/frontend/src/app/collaboration/[id]/page.tsx +++ b/apps/frontend/src/app/collaboration/[id]/page.tsx @@ -8,33 +8,26 @@ import { Modal, message, Row, - Select, - Tabs, TabsProps, Tag, - Typography, } from "antd"; import { Content } from "antd/es/layout/layout"; import "./styles.scss"; -import { useRouter, useSearchParams } from "next/navigation"; +import { useRouter } from "next/navigation"; import { useEffect, useRef, useState } from "react"; import { GetSingleQuestion, Question } from "@/app/services/question"; import { ClockCircleOutlined, CodeOutlined, - FileDoneOutlined, - InfoCircleFilled, MessageOutlined, - PlayCircleOutlined, SendOutlined, } from "@ant-design/icons"; -import { ProgrammingLanguageOptions } from "@/utils/SelectOptions"; import CollaborativeEditor, { CollaborativeEditorHandle, } from "@/components/CollaborativeEditor/CollaborativeEditor"; import { CreateOrUpdateHistory } from "@/app/services/history"; -import { Language } from "@codemirror/language"; import { WebrtcProvider } from "y-webrtc"; +import { QuestionDetailFull } from "@/components/question/QuestionDetailFull/QuestionDetailFull"; interface CollaborationProps {} @@ -324,55 +317,14 @@ export default function CollaborationPage(props: CollaborationProps) { - -
-
{questionTitle}
-
- - {complexity && - complexity.charAt(0).toUpperCase() + complexity.slice(1)} - -
-
- Topics: - {categories.map((category) => ( - {category} - ))} -
-
{description}
-
-
- -
-
-
- - Test Cases -
- {/* TODO: Link to execution service for running code against test-cases */} - -
-
- -
-
-
+ diff --git a/apps/frontend/src/app/collaboration/[id]/styles.scss b/apps/frontend/src/app/collaboration/[id]/styles.scss index 4f7b068e42..116d6a3c2e 100644 --- a/apps/frontend/src/app/collaboration/[id]/styles.scss +++ b/apps/frontend/src/app/collaboration/[id]/styles.scss @@ -21,16 +21,6 @@ padding: 0rem 1rem; } -.question-row { - height: 60%; - padding: 1rem 0.25rem 0.25rem; -} - -.test-row { - height: 40%; - padding: 0.25rem; -} - .code-row { height: 100%; padding: 1rem 0.25rem 0.25rem; @@ -46,20 +36,6 @@ padding: 0.25rem; } -.question-container { - border: 2px solid #463f3a; - border-radius: 10px; - width: 100%; - padding: 1rem; -} - -.test-container { - border: 2px solid #463f3a; - border-radius: 10px; - width: 100%; - padding: 1rem; -} - .test-top-container, .code-top-container, .session-top-container { @@ -156,15 +132,6 @@ font-weight: bold; } -.question-description { - text-align: justify; - text-justify: inter-word; - line-height: 1.3; - margin-top: 1rem; - max-height: 270px; - overflow-y: scroll; -} - .title-icons { margin-right: 4px; } diff --git a/apps/frontend/src/app/question/[id]/page.tsx b/apps/frontend/src/app/question/[id]/page.tsx index 30926fb169..64fc351c85 100644 --- a/apps/frontend/src/app/question/[id]/page.tsx +++ b/apps/frontend/src/app/question/[id]/page.tsx @@ -1,25 +1,34 @@ "use client"; import Header from "@/components/Header/header"; -import { Button, Col, Layout, message, Row, Tag, Select } from "antd"; +import { + Button, + Col, + Layout, + message, + Row, + Tag, + Select, + Table, + Input, +} from "antd"; import { Content } from "antd/es/layout/layout"; import { - PlusCircleOutlined, LeftOutlined, RightOutlined, CaretRightOutlined, - ClockCircleOutlined, - CommentOutlined, - CheckCircleOutlined, + CodeOutlined, + SendOutlined, + HistoryOutlined, } from "@ant-design/icons"; import "./styles.scss"; -import { useEffect, useState, useLayoutEffect } from "react"; +import { useEffect, useState } from "react"; import { GetSingleQuestion } from "../../services/question"; import React from "react"; import TextArea from "antd/es/input/TextArea"; import { useSearchParams } from "next/navigation"; import { ProgrammingLanguageOptions } from "@/utils/SelectOptions"; -import { ValidateUser, VerifyTokenResponseType } from "../../services/user"; import { useRouter } from "next/navigation"; +import { QuestionDetailFull } from "@/components/question/QuestionDetailFull/QuestionDetailFull"; export default function QuestionPage() { const [isLoading, setIsLoading] = useState(true); // Store the states related to table's loading @@ -47,160 +56,103 @@ export default function QuestionPage() { const [categories, setCategories] = useState([]); // Store the selected filter categories const [description, setDescription] = useState(undefined); const [selectedItem, setSelectedItem] = useState("python"); // State to hold the selected language item - + // When code editor page is initialised, fetch the particular question, and display in code editor useEffect(() => { if (!isLoading) { setIsLoading(true); } - GetSingleQuestion(docRefId).then((data: any) => { - setQuestionTitle(data.title); - setComplexity(data.complexity); - setCategories(data.categories); - setDescription(data.description); - }); + GetSingleQuestion(docRefId) + .then((data: any) => { + setQuestionTitle(data.title); + setComplexity(data.complexity); + setCategories(data.categories); + setDescription(data.description); + }) + .finally(() => { + setIsLoading(false); + }); }, [docRefId]); + // TODO: retrieve history + const history: any[] = []; + + const columns = [ + { + title: "Id", + dataIndex: "id", + key: "id", + }, + { + title: "Attempted at", + dataIndex: "attemptedAt", + key: "attemptedAt", + }, + { + title: "Language", + dataIndex: "language", + key: "language", + }, + { + title: "Matched with", + dataIndex: "matchedUser", + key: "matchedUser", + }, + ]; + return (
{contextHolder} - +
- - - - -
-
-

- {questionTitle} -

- - Solved  - - -
-
- - {complexity && - complexity.charAt(0).toUpperCase() + - complexity.slice(1)} - -
-
- Topics: - {categories.map((category) => ( - {category} - ))} -
-
- {description} -
-
-
- -
-
-

Testcases

- -
-
- - - -
-
- +
+ - - - -
-
-

- -  Session Details -

- -
-
-
- Start Time: - 01:23:45 -
- - Session Duration:{" "} - - 01:23:45 -
- Matched with: - John Doe + +
+
+
+ + Submitted Code
-
-
- -
-
-

- -  Chat -

+ {/* TODO: set value of code, refactor to look like collab editor but not editable */} +
+
diff --git a/apps/frontend/src/app/question/[id]/styles.scss b/apps/frontend/src/app/question/[id]/styles.scss index 764ed1f0c3..a0692e044c 100644 --- a/apps/frontend/src/app/question/[id]/styles.scss +++ b/apps/frontend/src/app/question/[id]/styles.scss @@ -1,247 +1,165 @@ -// start of code editor classes -.code-editor-layout { - background: white !important; - height: 97vh; - overflow: hidden; -} - -.code-editor-content { +.question-layout { + background: white; display: flex; flex-direction: column; + height: 100vh; } -.entire-page { +.question-content { + background: white; flex: 1; - padding: 1rem; -} - -.problem-description { - height: 70%; -} - -.code-editor { - height: 100.5% !important; -} - -.test-cases { - height: 30%; -} - -.session-details { - height: 20%; + overflow-y: auto; } -.chat-box { - height: 80%; +.first-col, +.second-col { + height: 90vh; } -.boxes { - border-radius: 10px; - border: solid; - margin: 4px; - padding: 5px; -} - -.problem-description-info { - width: 100%; - height: 100%; - overflow: auto; - margin-left: 5px; - padding: 8px; +.question-row { + padding: 0rem 1rem; } -.problem-description-top { - display: inline-flex; - flex-wrap: nowrap; - width: 100%; +.history-row { + height: 40%; + padding: 1rem 0.25rem 0.25rem; } -.problem-description-title { - padding: 0%; - margin: 0%; +.code-row { + height: 60%; + padding: 1rem 0.25rem 0.25rem; } -.problem-solve-status { - margin-left: auto; +.session-row { + height: 20%; + padding: 1rem 0.25rem 0.25rem; } -.test-cases-div { - height: 100%; - width: 100%; +.test-top-container, +.code-top-container, +.history-top-container, +.session-top-container { display: flex; - flex-direction: column; - padding: 8px; -} - -.test-cases-top { - display: inline-flex; - flex-wrap: nowrap; - margin-bottom: 5px; -} - -.testcase-title { - padding: 0%; - padding-left: 1%; - margin: 0%; + justify-content: space-between; } -.runtestcases-button { - margin-left: auto; -} - -.testcase-buttons { +.history-container, +.code-container { + border: 2px solid #463f3a; + border-radius: 10px; width: 100%; - padding-left: 1%; - display: inline-flex; - gap: 5px; + padding: 1rem; } -.testcase-code-div { - flex: 1 1 auto; - display: flex; - flex-direction: column; - justify-content: flex-end; - margin-top: 10px; +.history-language { + margin: auto 8px auto 0px; } -.testcase-code { - // max-height: 100%; - // height: 100%; - // padding-top: 4px; - // padding-left: 1%; - // flex:1; - height: 100%; - flex: 1 1 auto; +.language-select { + width: 120px; } -// .code-editor-box { -// height: 100% !important; -// flex-direction: column; -// display: flex; -// margin-bottom: 4px !important; -// } - -.code-editor-div { - height: 100%; +.session-container { + border: 2px solid #463f3a; + border-radius: 10px; width: 100%; - display: flex; - flex-direction: column; - padding: 8px; -} - -.code-editor-title { - padding: 0%; - padding-left: 1%; - margin: 0%; -} - -.code-editor-code-div { - flex: 1 1 auto; - display: flex; - flex-direction: column; - justify-content: flex-end; - margin-top: 10px; -} - -.code-editor-code { - height: 100%; - flex: 1 1 auto; -} - -.code-editor-top { - display: inline-flex; - flex-wrap: nowrap; + padding: 1rem; } -.language-select { - display: inline-flex; - flex-wrap: nowrap; - margin-top: 4px; +.chat-container { + border: 2px solid #463f3a; + border-radius: 10px; + width: 100%; + padding: 1rem; } -.submit-solution-button { - margin-left: auto; +.chat-message-box { + margin-top: 1rem; + height: 365px; + border: 1px solid #d9d9d9; + border-radius: 6px; + overflow-y: scroll; } -.select-language-button { - width: max-content; +.chat-header-message { + font-size: 14px; + color: #c6c6c6; + margin: 3px auto; + text-align: center; } -.session-details-title { - padding: 0%; - padding-left: 1%; - margin: 0%; +.chat-typing-box { + margin-top: 1rem; } -.session-details-top { - display: inline-flex; - flex-wrap: nowrap; +.question-title, +.test-title, +.code-title, +.history-title, +.session-title { + font-size: 16px; + font-weight: bold; } -.session-details-div { - height: 100%; - width: 100%; - display: flex; - flex-direction: column; - padding: 8px; +.question-difficulty, +.question-topic { + margin: 4px 0px; } -.end-session-button { - margin-left: auto; +.session-duration, +.session-matched-user-label { + margin: 4px 0px; } -.session-details-text-div { - flex: 1 1 auto; - display: flex; - flex-direction: column; - justify-content: flex-end; - margin-top: 10px; +.session-duration-timer { + font-weight: normal; + margin-left: 8px; } -.session-details-text { - height: 100%; - flex: 1 1 auto; - margin-left: 5px; +.session-matched-user-name { + color: #e0afa0; + margin-left: 8px; } -.chat-box-div { - height: 100%; - width: 100%; - display: flex; - flex-direction: column; - padding: 8px; +.topic-label, +.session-duration, +.session-matched-user-label { + font-size: 14px; + font-weight: bold; } -.chat-box-top { - display: inline-flex; - flex-wrap: nowrap; +.title-icons { + margin-right: 4px; } -.chat-box-title { - padding: 0%; - padding-left: 1%; - margin: 0%; +.session-end-button, +.test-case-button { + width: fit-content; } -.complexity-div { - margin: 4px 0; +.modal-description { + margin-bottom: 2rem; } -.topic-label, -.language-text { +.session-modal-question, +.session-modal-difficulty, +.session-modal-duration, +.session-modal-matched-user { font-weight: bold; } -.tag-container { - margin: 4px 0; +.session-modal-time, +.session-modal-title { + font-weight: normal; +} +.session-modal-matched-user-name { + color: #e0afa0; } -.description-text { - text-align: justify; - text-justify: inter-word; - line-height: 1.3; +.info-modal-icon { + color: red; } -.session-headers { - font-weight: bold; +.code-viewer { + resize: none; } diff --git a/apps/frontend/src/components/question/QuestionDetail/QuestionDetail.tsx b/apps/frontend/src/components/question/QuestionDetail/QuestionDetail.tsx new file mode 100644 index 0000000000..8d679bd53e --- /dev/null +++ b/apps/frontend/src/components/question/QuestionDetail/QuestionDetail.tsx @@ -0,0 +1,42 @@ +import { Tag } from "antd"; +import "./styles.scss"; + +interface QuestionDetailProps { + questionTitle?: string; + complexity?: string; + categories?: string[]; + description?: string; +} + +// Returns the html of question details (without testcase information) +export const QuestionDetail = (props: QuestionDetailProps) => { + return ( +
+
{props.questionTitle}
+
+ + {props.complexity && + props.complexity.charAt(0).toUpperCase() + + props.complexity.slice(1)} + +
+
+ Topics: + {props.categories?.map((category) => ( + {category} + ))} +
+
{props.description}
+
+ ); +}; diff --git a/apps/frontend/src/components/question/QuestionDetail/styles.scss b/apps/frontend/src/components/question/QuestionDetail/styles.scss new file mode 100644 index 0000000000..efcc62ee02 --- /dev/null +++ b/apps/frontend/src/components/question/QuestionDetail/styles.scss @@ -0,0 +1,30 @@ +.question-container { + border: 2px solid #463f3a; + border-radius: 10px; + width: 100%; + padding: 1rem; +} + +.question-title { + font-size: 16px; + font-weight: bold; +} + +.question-difficulty, +.question-topic { + margin: 4px 0px; +} + +.topic-label { + font-size: 14px; + font-weight: bold; +} + +.question-description { + text-align: justify; + text-justify: inter-word; + line-height: 1.3; + margin-top: 1rem; + max-height: 270px; + overflow-y: scroll; +} diff --git a/apps/frontend/src/components/question/QuestionDetailFull/QuestionDetailFull.tsx b/apps/frontend/src/components/question/QuestionDetailFull/QuestionDetailFull.tsx new file mode 100644 index 0000000000..8194cf2b40 --- /dev/null +++ b/apps/frontend/src/components/question/QuestionDetailFull/QuestionDetailFull.tsx @@ -0,0 +1,35 @@ +import { Row, TabsProps } from "antd"; +import { QuestionDetail } from "../QuestionDetail/QuestionDetail"; +import { TestcaseDetail } from "../TestcaseDetail/TestcaseDetail"; +import "./styles.scss"; + +// TODO: should add function for test case submission in props +interface QuestionDetailFullProps { + questionTitle?: string; + complexity?: string; + categories?: string[]; + description?: string; + testcaseItems?: TabsProps["items"]; + shouldShowSubmitButton?: boolean; +} + +export const QuestionDetailFull = (props: QuestionDetailFullProps) => { + return ( + <> + + + + + + + + ); +}; diff --git a/apps/frontend/src/components/question/QuestionDetailFull/styles.scss b/apps/frontend/src/components/question/QuestionDetailFull/styles.scss new file mode 100644 index 0000000000..26037db4a6 --- /dev/null +++ b/apps/frontend/src/components/question/QuestionDetailFull/styles.scss @@ -0,0 +1,9 @@ +.question-row { + height: 60%; + padding: 1rem 0.25rem 0.25rem; +} + +.test-row { + height: 40%; + padding: 1rem 0.25rem 0.25rem; +} diff --git a/apps/frontend/src/components/question/TestcaseDetail/TestcaseDetail.tsx b/apps/frontend/src/components/question/TestcaseDetail/TestcaseDetail.tsx new file mode 100644 index 0000000000..022f236e27 --- /dev/null +++ b/apps/frontend/src/components/question/TestcaseDetail/TestcaseDetail.tsx @@ -0,0 +1,60 @@ +import { FileDoneOutlined, PlayCircleOutlined } from "@ant-design/icons"; +import { Button, Input, Tabs, TabsProps } from "antd"; +import "./styles.scss"; + +interface TestcaseDetailProps { + testcaseItems?: TabsProps["items"]; + shouldShowSubmitButton?: boolean; +} + +export const TestcaseDetail = (props: TestcaseDetailProps) => { + // TODO: Tabs component items for testcases + // TODO: Setup test-cases in db for each qn and pull/paste here + const items: TabsProps["items"] = [ + { + key: "1", + label: "Case 1", + children: ( + + ), + }, + { + key: "2", + label: "Case 2", + children: ( + + ), + }, + // { + // key: "3", + // label: "Case 3", + // children: ( + // + // ), + // }, + ]; + + return ( +
+
+
+ + Test Cases +
+ {/* TODO: Link to execution service for running code against test-cases */} + {props.shouldShowSubmitButton && ( + + )} +
+
+ +
+
+ ); +}; diff --git a/apps/frontend/src/components/question/TestcaseDetail/styles.scss b/apps/frontend/src/components/question/TestcaseDetail/styles.scss new file mode 100644 index 0000000000..b3a0d26e9b --- /dev/null +++ b/apps/frontend/src/components/question/TestcaseDetail/styles.scss @@ -0,0 +1,24 @@ +.test-container { + border: 2px solid #463f3a; + border-radius: 10px; + width: 100%; + padding: 1rem; +} + +.test-title { + font-size: 16px; + font-weight: bold; +} + +.test-top-container { + display: flex; + justify-content: space-between; +} + +.test-case-button { + width: fit-content; +} + +.title-icons { + margin-right: 4px; +} From 00497c603f4d95d13020016002d3e5d1f43c9b75 Mon Sep 17 00:00:00 2001 From: bensohh Date: Sun, 3 Nov 2024 09:40:49 +0800 Subject: [PATCH 115/258] Create VideoPanel component --- .../src/components/VideoPanel/VideoPanel.tsx | 169 ++++++++++++++++++ .../src/components/VideoPanel/styles.scss | 13 ++ 2 files changed, 182 insertions(+) create mode 100644 apps/frontend/src/components/VideoPanel/VideoPanel.tsx create mode 100644 apps/frontend/src/components/VideoPanel/styles.scss diff --git a/apps/frontend/src/components/VideoPanel/VideoPanel.tsx b/apps/frontend/src/components/VideoPanel/VideoPanel.tsx new file mode 100644 index 0000000000..b8cc3983eb --- /dev/null +++ b/apps/frontend/src/components/VideoPanel/VideoPanel.tsx @@ -0,0 +1,169 @@ +import React, { useEffect, useRef, useState } from "react"; +import Peer, { MediaConnection } from "peerjs"; +import "./styles.scss"; +import { Button } from "antd"; +import { + ApiOutlined, + PhoneOutlined, + VideoCameraOutlined, +} from "@ant-design/icons"; + +const VideoPanel = () => { + const matchId = localStorage.getItem("collabId")?.toString() ?? ""; + const currentUsername = localStorage.getItem("user")?.toString(); + const matchedUsername = localStorage.getItem("matchedUser")?.toString(); + const currentId = currentUsername + "-" + matchId ?? ""; + const partnerId = matchedUsername + "-" + matchId ?? ""; + + const remoteVideoRef = useRef(null); + const currentUserVideoRef = useRef(null); + const [peerInstance, setPeerInstance] = useState(null); + const [callInstance, setCallInstance] = useState( + null + ); + const [userStream, setUserStream] = useState(null); + const [videoOn, setVideoOn] = useState(true); + + const handleCall = () => { + navigator.mediaDevices + .getUserMedia({ + video: true, + audio: true, + }) + .then((stream) => { + if (peerInstance) { + const call = peerInstance?.call(partnerId, stream); + setCallInstance(call); + if (call) { + call.on("stream", (userVideoStream: MediaStream) => { + if (remoteVideoRef.current) { + remoteVideoRef.current.srcObject = userVideoStream; + } + }); + + if (userStream) { + const videoTrack = userStream.getVideoTracks()[0]; + + const sender = call.peerConnection.getSenders().find((s) => { + if (s.track) { + return s.track.kind === "video"; + } + }); + if (sender) { + sender.replaceTrack(videoTrack); // Replace the video track in the call + } + } + } + } + }); + }; + + useEffect(() => { + if (currentId) { + let peer: Peer; + if (typeof window !== "undefined") { + peer = new Peer( + currentId + // { + // host: "localhost", + // port: 4444, + // path: "/", + // } + ); + + setPeerInstance(peer); + + navigator.mediaDevices + .getUserMedia({ + video: true, + audio: true, + }) + .then((stream) => { + setUserStream(stream); + if (currentUserVideoRef.current) { + currentUserVideoRef.current.srcObject = stream; + } + + peer.on("call", (call) => { + call.answer(stream); + call.on("stream", (userVideoStream) => { + if (remoteVideoRef.current) { + remoteVideoRef.current.srcObject = userVideoStream; + } + }); + }); + }); + } + return () => { + if (peer) { + peer.destroy(); + } + }; + } + }, []); + + const toggleVideo = () => { + if (userStream) { + console.log(userStream.getVideoTracks()); + const videoTrack = userStream.getVideoTracks()[0]; + + if (videoTrack) { + if (videoOn) { + // Stop the video track + videoTrack.enabled = false; + + setVideoOn(false); + if (callInstance) { + const sender = callInstance.peerConnection + .getSenders() + .find((s) => { + if (s.track) { + return s.track.kind === "video"; + } + }); + if (sender) { + sender.replaceTrack(videoTrack); // Replace the video track in the call + } + } + } else { + // Resume the video track + videoTrack.enabled = true; + setVideoOn(true); + } + } + } + }; + + return ( +
+

Video Feed for: {currentUsername}

+
+ ); +}; + +export default VideoPanel; diff --git a/apps/frontend/src/components/VideoPanel/styles.scss b/apps/frontend/src/components/VideoPanel/styles.scss new file mode 100644 index 0000000000..2ffe99394a --- /dev/null +++ b/apps/frontend/src/components/VideoPanel/styles.scss @@ -0,0 +1,13 @@ +.video-container { + position: relative; + width: 100%; +} + +.user-video, +.matched-user-video { + width: 100%; +} + +.header-tag { + font-weight: bold; +} From 1fc36faca766101ff3033d689d7aaf66fb63e7a6 Mon Sep 17 00:00:00 2001 From: bensohh Date: Sun, 3 Nov 2024 09:41:11 +0800 Subject: [PATCH 116/258] Integrate videopanel into existing collab page --- apps/frontend/package.json | 2 + apps/frontend/pnpm-lock.yaml | 4383 ++++++++--------- .../src/app/collaboration/[id]/page.tsx | 3 +- 3 files changed, 2001 insertions(+), 2387 deletions(-) diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 94cc9de16b..e86f00cf3e 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -21,6 +21,7 @@ "antd": "^5.20.6", "codemirror": "^6.0.1", "next": "14.2.13", + "peerjs": "^1.5.4", "react": "^18.2.0", "react-dom": "^18.2.0", "react-timer-hook": "^3.0.7", @@ -33,6 +34,7 @@ }, "devDependencies": { "@types/node": "^20", + "@types/peerjs": "^1.1.0", "@types/react": "^18.3.8", "@types/react-dom": "^18.3.0", "eslint": "^8", diff --git a/apps/frontend/pnpm-lock.yaml b/apps/frontend/pnpm-lock.yaml index c114790857..5a0bb2bea7 100644 --- a/apps/frontend/pnpm-lock.yaml +++ b/apps/frontend/pnpm-lock.yaml @@ -1,1976 +1,126 @@ -lockfileVersion: '9.0' +lockfileVersion: '6.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -importers: - - .: - dependencies: - '@ant-design/icons': - specifier: ^5.5.1 - version: 5.5.1(react-dom@18.2.0)(react@18.2.0) - '@ant-design/nextjs-registry': - specifier: ^1.0.1 - version: 1.0.1(@ant-design/cssinjs@1.21.1)(antd@5.20.6)(next@14.2.13)(react-dom@18.2.0)(react@18.2.0) - '@codemirror/lang-cpp': - specifier: ^6.0.2 - version: 6.0.2 - '@codemirror/lang-go': - specifier: ^6.0.1 - version: 6.0.1(@codemirror/view@6.34.1) - '@codemirror/lang-java': - specifier: ^6.0.1 - version: 6.0.1 - '@codemirror/lang-javascript': - specifier: ^6.2.2 - version: 6.2.2 - '@codemirror/lang-python': - specifier: ^6.1.6 - version: 6.1.6(@codemirror/view@6.34.1) - '@codemirror/language': - specifier: ^6.10.3 - version: 6.10.3 - '@codemirror/state': - specifier: ^6.4.1 - version: 6.4.1 - antd: - specifier: ^5.20.6 - version: 5.20.6(react-dom@18.2.0)(react@18.2.0) - codemirror: - specifier: ^6.0.1 - version: 6.0.1(@lezer/common@1.2.3) - next: - specifier: 14.2.13 - version: 14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2) - react: - specifier: ^18.2.0 - version: 18.2.0 - react-dom: - specifier: ^18.2.0 - version: 18.2.0(react@18.2.0) - react-timer-hook: - specifier: ^3.0.7 - version: 3.0.7(react@18.2.0) - react-use-websocket: - specifier: ^4.9.0 - version: 4.9.0 - sass: - specifier: ^1.79.2 - version: 1.79.2 - typeface-montserrat: - specifier: ^1.1.13 - version: 1.1.13 - y-codemirror.next: - specifier: ^0.3.5 - version: 0.3.5(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(yjs@13.6.20) - y-webrtc: - specifier: ^10.3.0 - version: 10.3.0(yjs@13.6.20) - yjs: - specifier: ^13.6.20 - version: 13.6.20 - devDependencies: - '@types/node': - specifier: ^20 - version: 20.0.0 - '@types/react': - specifier: ^18.3.8 - version: 18.3.8 - '@types/react-dom': - specifier: ^18.3.0 - version: 18.3.0 - eslint: - specifier: ^8 - version: 8.0.0 - eslint-config-next: - specifier: 14.2.13 - version: 14.2.13(eslint@8.0.0)(typescript@5.0.2) - typescript: - specifier: ^5 - version: 5.0.2 - -packages: - - '@ant-design/colors@7.1.0': - resolution: {integrity: sha512-MMoDGWn1y9LdQJQSHiCC20x3uZ3CwQnv9QMz6pCmJOrqdgM9YxsoVVY0wtrdXbmfSgnV0KNk6zi09NAhMR2jvg==} - - '@ant-design/cssinjs-utils@1.1.0': - resolution: {integrity: sha512-E9nOWObXx7Dy7hdyuYlOFaer/LtPO7oyZVxZphh0CYEslr5EmhJPM3WI0Q2RBHRtYg6dSNqeSK73kvZjPN3IMQ==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - '@ant-design/cssinjs@1.21.1': - resolution: {integrity: sha512-tyWnlK+XH7Bumd0byfbCiZNK43HEubMoCcu9VxwsAwiHdHTgWa+tMN0/yvxa+e8EzuFP1WdUNNPclRpVtD33lg==} - peerDependencies: - react: '>=16.0.0' - react-dom: '>=16.0.0' - - '@ant-design/fast-color@2.0.6': - resolution: {integrity: sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==} - engines: {node: '>=8.x'} - - '@ant-design/icons-svg@4.4.2': - resolution: {integrity: sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==} - - '@ant-design/icons@5.5.1': - resolution: {integrity: sha512-0UrM02MA2iDIgvLatWrj6YTCYe0F/cwXvVE0E2SqGrL7PZireQwgEKTKBisWpZyal5eXZLvuM98kju6YtYne8w==} - engines: {node: '>=8'} - peerDependencies: - react: '>=16.0.0' - react-dom: '>=16.0.0' - - '@ant-design/nextjs-registry@1.0.1': - resolution: {integrity: sha512-DaMJ1nClR1a4UfG7vXkDj89z1eARhSDgqvHoxfM0Yco1MZEbaqRj4o+bQToHb3gMb6gbFlrZ51nOBGh5xSJ7EQ==} - peerDependencies: - '@ant-design/cssinjs': ^1.18.2 - antd: ^5.0.0 - next: ^14.0.0 - react: '>=16.0.0' - react-dom: '>=16.0.0' - - '@ant-design/react-slick@1.1.2': - resolution: {integrity: sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA==} - peerDependencies: - react: '>=16.9.0' - - '@babel/runtime@7.25.7': - resolution: {integrity: sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==} - engines: {node: '>=6.9.0'} - - '@codemirror/autocomplete@6.18.1': - resolution: {integrity: sha512-iWHdj/B1ethnHRTwZj+C1obmmuCzquH29EbcKr0qIjA9NfDeBDJ7vs+WOHsFeLeflE4o+dHfYndJloMKHUkWUA==} - peerDependencies: - '@codemirror/language': ^6.0.0 - '@codemirror/state': ^6.0.0 - '@codemirror/view': ^6.0.0 - '@lezer/common': ^1.0.0 - - '@codemirror/commands@6.7.1': - resolution: {integrity: sha512-llTrboQYw5H4THfhN4U3qCnSZ1SOJ60ohhz+SzU0ADGtwlc533DtklQP0vSFaQuCPDn3BPpOd1GbbnUtwNjsrw==} - - '@codemirror/lang-cpp@6.0.2': - resolution: {integrity: sha512-6oYEYUKHvrnacXxWxYa6t4puTlbN3dgV662BDfSH8+MfjQjVmP697/KYTDOqpxgerkvoNm7q5wlFMBeX8ZMocg==} - - '@codemirror/lang-go@6.0.1': - resolution: {integrity: sha512-7fNvbyNylvqCphW9HD6WFnRpcDjr+KXX/FgqXy5H5ZS0eC5edDljukm/yNgYkwTsgp2busdod50AOTIy6Jikfg==} - - '@codemirror/lang-java@6.0.1': - resolution: {integrity: sha512-OOnmhH67h97jHzCuFaIEspbmsT98fNdhVhmA3zCxW0cn7l8rChDhZtwiwJ/JOKXgfm4J+ELxQihxaI7bj7mJRg==} - - '@codemirror/lang-javascript@6.2.2': - resolution: {integrity: sha512-VGQfY+FCc285AhWuwjYxQyUQcYurWlxdKYT4bqwr3Twnd5wP5WSeu52t4tvvuWmljT4EmgEgZCqSieokhtY8hg==} - - '@codemirror/lang-python@6.1.6': - resolution: {integrity: sha512-ai+01WfZhWqM92UqjnvorkxosZ2aq2u28kHvr+N3gu012XqY2CThD67JPMHnGceRfXPDBmn1HnyqowdpF57bNg==} - - '@codemirror/language@6.10.3': - resolution: {integrity: sha512-kDqEU5sCP55Oabl6E7m5N+vZRoc0iWqgDVhEKifcHzPzjqCegcO4amfrYVL9PmPZpl4G0yjkpTpUO/Ui8CzO8A==} - - '@codemirror/lint@6.8.2': - resolution: {integrity: sha512-PDFG5DjHxSEjOXk9TQYYVjZDqlZTFaDBfhQixHnQOEVDDNHUbEh/hstAjcQJaA6FQdZTD1hquXTK0rVBLADR1g==} - - '@codemirror/search@6.5.6': - resolution: {integrity: sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==} - - '@codemirror/state@6.4.1': - resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==} - - '@codemirror/view@6.34.1': - resolution: {integrity: sha512-t1zK/l9UiRqwUNPm+pdIT0qzJlzuVckbTEMVNFhfWkGiBQClstzg+78vedCvLSX0xJEZ6lwZbPpnljL7L6iwMQ==} - - '@ctrl/tinycolor@3.6.1': - resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} - engines: {node: '>=10'} - - '@emotion/hash@0.8.0': - resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} - - '@emotion/unitless@0.7.5': - resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==} - - '@eslint-community/eslint-utils@4.4.0': - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.11.1': - resolution: {integrity: sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/eslintrc@1.4.1': - resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@humanwhocodes/config-array@0.6.0': - resolution: {integrity: sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead - - '@humanwhocodes/object-schema@1.2.1': - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} - deprecated: Use @eslint/object-schema instead - - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} - - '@lezer/common@1.2.3': - resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==} - - '@lezer/cpp@1.1.2': - resolution: {integrity: sha512-macwKtyeUO0EW86r3xWQCzOV9/CF8imJLpJlPv3sDY57cPGeUZ8gXWOWNlJr52TVByMV3PayFQCA5SHEERDmVQ==} - - '@lezer/go@1.0.0': - resolution: {integrity: sha512-co9JfT3QqX1YkrMmourYw2Z8meGC50Ko4d54QEcQbEYpvdUvN4yb0NBZdn/9ertgvjsySxHsKzH3lbm3vqJ4Jw==} - - '@lezer/highlight@1.2.1': - resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==} - - '@lezer/java@1.1.3': - resolution: {integrity: sha512-yHquUfujwg6Yu4Fd1GNHCvidIvJwi/1Xu2DaKl/pfWIA2c1oXkVvawH3NyXhCaFx4OdlYBVX5wvz2f7Aoa/4Xw==} - - '@lezer/javascript@1.4.19': - resolution: {integrity: sha512-j44kbR1QL26l6dMunZ1uhKBFteVGLVCBGNUD2sUaMnic+rbTviVuoK0CD1l9FTW31EueWvFFswCKMH7Z+M3JRA==} - - '@lezer/lr@1.4.2': - resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==} - - '@lezer/python@1.1.14': - resolution: {integrity: sha512-ykDOb2Ti24n76PJsSa4ZoDF0zH12BSw1LGfQXCYJhJyOGiFTfGaX0Du66Ze72R+u/P35U+O6I9m8TFXov1JzsA==} - - '@next/env@14.2.13': - resolution: {integrity: sha512-s3lh6K8cbW1h5Nga7NNeXrbe0+2jIIYK9YaA9T7IufDWnZpozdFUp6Hf0d5rNWUKu4fEuSX2rCKlGjCrtylfDw==} - - '@next/eslint-plugin-next@14.2.13': - resolution: {integrity: sha512-z8Mk0VljxhIzsSiZUSdt3wp+t2lKd+jk5a9Jsvh3zDGkItgDMfjv/ZbET6HsxEl/fSihVoHGsXV6VLyDH0lfTQ==} - - '@next/swc-darwin-arm64@14.2.13': - resolution: {integrity: sha512-IkAmQEa2Htq+wHACBxOsslt+jMoV3msvxCn0WFSfJSkv/scy+i/EukBKNad36grRxywaXUYJc9mxEGkeIs8Bzg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@next/swc-darwin-x64@14.2.13': - resolution: {integrity: sha512-Dv1RBGs2TTjkwEnFMVL5XIfJEavnLqqwYSD6LXgTPdEy/u6FlSrLBSSfe1pcfqhFEXRAgVL3Wpjibe5wXJzWog==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@next/swc-linux-arm64-gnu@14.2.13': - resolution: {integrity: sha512-yB1tYEFFqo4ZNWkwrJultbsw7NPAAxlPXURXioRl9SdW6aIefOLS+0TEsKrWBtbJ9moTDgU3HRILL6QBQnMevg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-arm64-musl@14.2.13': - resolution: {integrity: sha512-v5jZ/FV/eHGoWhMKYrsAweQ7CWb8xsWGM/8m1mwwZQ/sutJjoFaXchwK4pX8NqwImILEvQmZWyb8pPTcP7htWg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-x64-gnu@14.2.13': - resolution: {integrity: sha512-aVc7m4YL7ViiRv7SOXK3RplXzOEe/qQzRA5R2vpXboHABs3w8vtFslGTz+5tKiQzWUmTmBNVW0UQdhkKRORmGA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-linux-x64-musl@14.2.13': - resolution: {integrity: sha512-4wWY7/OsSaJOOKvMsu1Teylku7vKyTuocvDLTZQq0TYv9OjiYYWt63PiE1nTuZnqQ4RPvME7Xai+9enoiN0Wrg==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-win32-arm64-msvc@14.2.13': - resolution: {integrity: sha512-uP1XkqCqV2NVH9+g2sC7qIw+w2tRbcMiXFEbMihkQ8B1+V6m28sshBwAB0SDmOe0u44ne1vFU66+gx/28RsBVQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@next/swc-win32-ia32-msvc@14.2.13': - resolution: {integrity: sha512-V26ezyjPqQpDBV4lcWIh8B/QICQ4v+M5Bo9ykLN+sqeKKBxJVDpEc6biDVyluTXTC40f5IqCU0ttth7Es2ZuMw==} - engines: {node: '>= 10'} - cpu: [ia32] - os: [win32] - - '@next/swc-win32-x64-msvc@14.2.13': - resolution: {integrity: sha512-WwzOEAFBGhlDHE5Z73mNU8CO8mqMNLqaG+AO9ETmzdCQlJhVtWZnOl2+rqgVQS+YHunjOWptdFmNfbpwcUuEsw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - - '@nolyfill/is-core-module@1.0.39': - resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} - engines: {node: '>=12.4.0'} - - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - - '@rc-component/async-validator@5.0.4': - resolution: {integrity: sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==} - engines: {node: '>=14.x'} - - '@rc-component/color-picker@2.0.1': - resolution: {integrity: sha512-WcZYwAThV/b2GISQ8F+7650r5ZZJ043E57aVBFkQ+kSY4C6wdofXgB0hBx+GPGpIU0Z81eETNoDUJMr7oy/P8Q==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - '@rc-component/context@1.4.0': - resolution: {integrity: sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - '@rc-component/mini-decimal@1.1.0': - resolution: {integrity: sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==} - engines: {node: '>=8.x'} - - '@rc-component/mutate-observer@1.1.0': - resolution: {integrity: sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - '@rc-component/portal@1.1.2': - resolution: {integrity: sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - '@rc-component/qrcode@1.0.0': - resolution: {integrity: sha512-L+rZ4HXP2sJ1gHMGHjsg9jlYBX/SLN2D6OxP9Zn3qgtpMWtO2vUfxVFwiogHpAIqs54FnALxraUy/BCO1yRIgg==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - '@rc-component/tour@1.15.1': - resolution: {integrity: sha512-Tr2t7J1DKZUpfJuDZWHxyxWpfmj8EZrqSgyMZ+BCdvKZ6r1UDsfU46M/iWAAFBy961Ssfom2kv5f3UcjIL2CmQ==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - '@rc-component/trigger@2.2.3': - resolution: {integrity: sha512-X1oFIpKoXAMXNDYCviOmTfuNuYxE4h5laBsyCqVAVMjNHxoF3/uiyA7XdegK1XbCvBbCZ6P6byWrEoDRpKL8+A==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - '@rtsao/scc@1.1.0': - resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - - '@rushstack/eslint-patch@1.10.4': - resolution: {integrity: sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==} - - '@swc/counter@0.1.3': - resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - - '@swc/helpers@0.5.5': - resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} - - '@types/json5@0.0.29': - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - - '@types/node@20.0.0': - resolution: {integrity: sha512-cD2uPTDnQQCVpmRefonO98/PPijuOnnEy5oytWJFPY1N9aJCz2wJ5kSGWO+zJoed2cY2JxQh6yBuUq4vIn61hw==} - - '@types/prop-types@15.7.13': - resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==} - - '@types/react-dom@18.3.0': - resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} - - '@types/react@18.3.8': - resolution: {integrity: sha512-syBUrW3/XpnW4WJ41Pft+I+aPoDVbrBVQGEnbD7NijDGlVC+8gV/XKRY+7vMDlfPpbwYt0l1vd/Sj8bJGMbs9Q==} - - '@typescript-eslint/eslint-plugin@8.8.0': - resolution: {integrity: sha512-wORFWjU30B2WJ/aXBfOm1LX9v9nyt9D3jsSOxC3cCaTQGCW5k4jNpmjFv3U7p/7s4yvdjHzwtv2Sd2dOyhjS0A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/parser@8.8.0': - resolution: {integrity: sha512-uEFUsgR+tl8GmzmLjRqz+VrDv4eoaMqMXW7ruXfgThaAShO9JTciKpEsB+TvnfFfbg5IpujgMXVV36gOJRLtZg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/scope-manager@8.8.0': - resolution: {integrity: sha512-EL8eaGC6gx3jDd8GwEFEV091210U97J0jeEHrAYvIYosmEGet4wJ+g0SYmLu+oRiAwbSA5AVrt6DxLHfdd+bUg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/type-utils@8.8.0': - resolution: {integrity: sha512-IKwJSS7bCqyCeG4NVGxnOP6lLT9Okc3Zj8hLO96bpMkJab+10HIfJbMouLrlpyOr3yrQ1cA413YPFiGd1mW9/Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/types@8.8.0': - resolution: {integrity: sha512-QJwc50hRCgBd/k12sTykOJbESe1RrzmX6COk8Y525C9l7oweZ+1lw9JiU56im7Amm8swlz00DRIlxMYLizr2Vw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/typescript-estree@8.8.0': - resolution: {integrity: sha512-ZaMJwc/0ckLz5DaAZ+pNLmHv8AMVGtfWxZe/x2JVEkD5LnmhWiQMMcYT7IY7gkdJuzJ9P14fRy28lUrlDSWYdw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/utils@8.8.0': - resolution: {integrity: sha512-QE2MgfOTem00qrlPgyByaCHay9yb1+9BjnMFnSFkUKQfu7adBXDTnCAivURnuPPAG/qiB+kzKkZKmKfaMT0zVg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - - '@typescript-eslint/visitor-keys@8.8.0': - resolution: {integrity: sha512-8mq51Lx6Hpmd7HnA2fcHQo3YgfX1qbccxQOgZcb4tvasu//zXRaA1j5ZRFeCw/VRAdFi4mRM9DnZw0Nu0Q2d1g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn@8.12.1: - resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} - engines: {node: '>=0.4.0'} - hasBin: true - - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - - ansi-colors@4.1.3: - resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} - engines: {node: '>=6'} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-regex@6.1.0: - resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} - engines: {node: '>=12'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} - - antd@5.20.6: - resolution: {integrity: sha512-TZFmNenHlh26DelHCJbkB+x1OVulIKsN1f/CnAd2NxZLysXqRvSuLUeHcgccqAnxTy7B03GZ6i1tocGxPCNjgA==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - aria-query@5.1.3: - resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} - - array-buffer-byte-length@1.0.1: - resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} - engines: {node: '>= 0.4'} - - array-includes@3.1.8: - resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} - engines: {node: '>= 0.4'} - - array-tree-filter@2.1.0: - resolution: {integrity: sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==} - - array.prototype.findlast@1.2.5: - resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} - engines: {node: '>= 0.4'} - - array.prototype.findlastindex@1.2.5: - resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} - engines: {node: '>= 0.4'} - - array.prototype.flat@1.3.2: - resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} - engines: {node: '>= 0.4'} - - array.prototype.flatmap@1.3.2: - resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} - engines: {node: '>= 0.4'} - - array.prototype.tosorted@1.1.4: - resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} - engines: {node: '>= 0.4'} - - arraybuffer.prototype.slice@1.0.3: - resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} - engines: {node: '>= 0.4'} - - ast-types-flow@0.0.8: - resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} - - available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} - - axe-core@4.10.0: - resolution: {integrity: sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==} - engines: {node: '>=4'} - - axobject-query@4.1.0: - resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} - engines: {node: '>= 0.4'} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - - brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - - brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - - busboy@1.6.0: - resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} - engines: {node: '>=10.16.0'} - - call-bind@1.0.7: - resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} - engines: {node: '>= 0.4'} - - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - - caniuse-lite@1.0.30001666: - resolution: {integrity: sha512-gD14ICmoV5ZZM1OdzPWmpx+q4GyefaK06zi8hmfHV5xe4/2nOQX3+Dw5o+fSqOws2xVwL9j+anOPFwHzdEdV4g==} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - chokidar@4.0.1: - resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} - engines: {node: '>= 14.16.0'} - - classnames@2.5.1: - resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} - - client-only@0.0.1: - resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - - codemirror@6.0.1: - resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - compute-scroll-into-view@3.1.0: - resolution: {integrity: sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - copy-to-clipboard@3.3.3: - resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} - - crelt@1.0.6: - resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} - - cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} - - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - - damerau-levenshtein@1.0.8: - resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} - - data-view-buffer@1.0.1: - resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} - engines: {node: '>= 0.4'} - - data-view-byte-length@1.0.1: - resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} - engines: {node: '>= 0.4'} - - data-view-byte-offset@1.0.0: - resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} - engines: {node: '>= 0.4'} - - dayjs@1.11.13: - resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} - - debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@4.3.7: - resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - deep-equal@2.2.3: - resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==} - engines: {node: '>= 0.4'} - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - - define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} - - doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} - - doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - - enhanced-resolve@5.17.1: - resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} - engines: {node: '>=10.13.0'} - - enquirer@2.4.1: - resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} - engines: {node: '>=8.6'} - - err-code@3.0.1: - resolution: {integrity: sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==} - - es-abstract@1.23.3: - resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} - engines: {node: '>= 0.4'} - - es-define-property@1.0.0: - resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-get-iterator@1.1.3: - resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} - - es-iterator-helpers@1.0.19: - resolution: {integrity: sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==} - engines: {node: '>= 0.4'} - - es-object-atoms@1.0.0: - resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.0.3: - resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} - engines: {node: '>= 0.4'} - - es-shim-unscopables@1.0.2: - resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} - - es-to-primitive@1.2.1: - resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} - engines: {node: '>= 0.4'} - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - eslint-config-next@14.2.13: - resolution: {integrity: sha512-aro1EKAoyYchnO/3Tlo91hnNBO7QO7qnv/79MAFC+4Jq8TdUVKQlht5d2F+YjrePjdpOvfL+mV9JPfyYNwkk1g==} - peerDependencies: - eslint: ^7.23.0 || ^8.0.0 - typescript: '>=3.3.1' - peerDependenciesMeta: - typescript: - optional: true - - eslint-import-resolver-node@0.3.9: - resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - - eslint-import-resolver-typescript@3.6.3: - resolution: {integrity: sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - eslint: '*' - eslint-plugin-import: '*' - eslint-plugin-import-x: '*' - peerDependenciesMeta: - eslint-plugin-import: - optional: true - eslint-plugin-import-x: - optional: true - - eslint-module-utils@2.12.0: - resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - - eslint-plugin-import@2.30.0: - resolution: {integrity: sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - - eslint-plugin-jsx-a11y@6.10.0: - resolution: {integrity: sha512-ySOHvXX8eSN6zz8Bywacm7CvGNhUtdjvqfQDVe6020TUK34Cywkw7m0KsCCk1Qtm9G1FayfTN1/7mMYnYO2Bhg==} - engines: {node: '>=4.0'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 - - eslint-plugin-react-hooks@4.6.2: - resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==} - engines: {node: '>=10'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - - eslint-plugin-react@7.37.1: - resolution: {integrity: sha512-xwTnwDqzbDRA8uJ7BMxPs/EXRB3i8ZfnOIp8BsxEQkT0nHPp+WWceqGgo6rKb9ctNi8GJLDT4Go5HAWELa/WMg==} - engines: {node: '>=4'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - - eslint-scope@6.0.0: - resolution: {integrity: sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-utils@3.0.0: - resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} - engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} - peerDependencies: - eslint: '>=5' - - eslint-visitor-keys@2.1.0: - resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} - engines: {node: '>=10'} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint@8.0.0: - resolution: {integrity: sha512-03spzPzMAO4pElm44m60Nj08nYonPGQXmw6Ceai/S4QK82IgwWO1EXx1s9namKzVlbVu3Jf81hb+N+8+v21/HQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true - - espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} - engines: {node: '>=0.10'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} - engines: {node: '>=8.6.0'} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - - fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} - - file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} - - flatted@3.3.1: - resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} - - for-each@0.3.3: - resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - - foreground-child@3.3.0: - resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} - engines: {node: '>=14'} - - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - function.prototype.name@1.1.6: - resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} - engines: {node: '>= 0.4'} - - functional-red-black-tree@1.0.1: - resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} - - functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - - get-browser-rtc@1.1.0: - resolution: {integrity: sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ==} - - get-intrinsic@1.2.4: - resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} - engines: {node: '>= 0.4'} - - get-symbol-description@1.0.2: - resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} - engines: {node: '>= 0.4'} - - get-tsconfig@4.8.1: - resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - glob@10.3.10: - resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} - engines: {node: '>=16 || 14 >=14.17'} - hasBin: true - - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported - - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} - - globalthis@1.0.4: - resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} - engines: {node: '>= 0.4'} - - gopd@1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - - has-bigints@1.0.2: - resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - - has-proto@1.0.3: - resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} - engines: {node: '>= 0.4'} - - has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - - ignore@4.0.6: - resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} - engines: {node: '>= 4'} - - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - immutable@4.3.7: - resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} - - import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - internal-slot@1.0.7: - resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} - engines: {node: '>= 0.4'} - - is-arguments@1.1.1: - resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} - engines: {node: '>= 0.4'} - - is-array-buffer@3.0.4: - resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} - engines: {node: '>= 0.4'} - - is-async-function@2.0.0: - resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} - engines: {node: '>= 0.4'} - - is-bigint@1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} - - is-boolean-object@1.1.2: - resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} - engines: {node: '>= 0.4'} - - is-bun-module@1.2.1: - resolution: {integrity: sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==} - - is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - - is-core-module@2.15.1: - resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} - engines: {node: '>= 0.4'} - - is-data-view@1.0.1: - resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} - engines: {node: '>= 0.4'} - - is-date-object@1.0.5: - resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} - engines: {node: '>= 0.4'} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-finalizationregistry@1.0.2: - resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-generator-function@1.0.10: - resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} - engines: {node: '>= 0.4'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-map@2.0.3: - resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} - engines: {node: '>= 0.4'} - - is-negative-zero@2.0.3: - resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} - engines: {node: '>= 0.4'} - - is-number-object@1.0.7: - resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} - engines: {node: '>= 0.4'} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-regex@1.1.4: - resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} - engines: {node: '>= 0.4'} - - is-set@2.0.3: - resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} - engines: {node: '>= 0.4'} - - is-shared-array-buffer@1.0.3: - resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} - engines: {node: '>= 0.4'} - - is-string@1.0.7: - resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} - engines: {node: '>= 0.4'} - - is-symbol@1.0.4: - resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} - engines: {node: '>= 0.4'} - - is-typed-array@1.1.13: - resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} - engines: {node: '>= 0.4'} - - is-weakmap@2.0.2: - resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} - engines: {node: '>= 0.4'} - - is-weakref@1.0.2: - resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} - - is-weakset@2.0.3: - resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} - engines: {node: '>= 0.4'} - - isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - isomorphic.js@0.2.5: - resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} - - iterator.prototype@1.1.2: - resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} - - jackspeak@2.3.6: - resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} - engines: {node: '>=14'} - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - json2mq@0.2.0: - resolution: {integrity: sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==} - - json5@1.0.2: - resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} - hasBin: true - - jsx-ast-utils@3.3.5: - resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} - engines: {node: '>=4.0'} - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - language-subtag-registry@0.3.23: - resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} - - language-tags@1.0.9: - resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} - engines: {node: '>=0.10'} - - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - - lib0@0.2.98: - resolution: {integrity: sha512-XteTiNO0qEXqqweWx+b21p/fBnNHUA1NwAtJNJek1oPrewEZs2uiT4gWivHKr9GqCjDPAhchz0UQO8NwU3bBNA==} - engines: {node: '>=16'} - hasBin: true - - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} - - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} - engines: {node: '>=16 || 14 >=14.17'} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - next@14.2.13: - resolution: {integrity: sha512-BseY9YNw8QJSwLYD7hlZzl6QVDoSFHL/URN5K64kVEVpCsSOWeyjbIGK+dZUaRViHTaMQX8aqmnn0PHBbGZezg==} - engines: {node: '>=18.17.0'} - hasBin: true - peerDependencies: - '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.41.2 - react: ^18.2.0 - react-dom: ^18.2.0 - sass: ^1.3.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@playwright/test': - optional: true - sass: - optional: true - - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - object-inspect@1.13.2: - resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} - engines: {node: '>= 0.4'} - - object-is@1.1.6: - resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} - engines: {node: '>= 0.4'} - - object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - - object.assign@4.1.5: - resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} - engines: {node: '>= 0.4'} - - object.entries@1.1.8: - resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} - engines: {node: '>= 0.4'} - - object.fromentries@2.0.8: - resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} - engines: {node: '>= 0.4'} - - object.groupby@1.0.3: - resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} - engines: {node: '>= 0.4'} - - object.values@1.2.0: - resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} - engines: {node: '>= 0.4'} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} - - picocolors@1.1.0: - resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} - - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - - possible-typed-array-names@1.0.0: - resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} - engines: {node: '>= 0.4'} - - postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} - engines: {node: ^10 || ^12 || >=14} - - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - - progress@2.0.3: - resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} - engines: {node: '>=0.4.0'} - - prop-types@15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - - rc-cascader@3.28.1: - resolution: {integrity: sha512-9+8oHIMWVLHxuaapDiqFNmD9KSyKN/P4bo9x/MBuDbyTqP8f2/POmmZxdXWBO3yq/uE3pKyQCXYNUxrNfHRv2A==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-checkbox@3.3.0: - resolution: {integrity: sha512-Ih3ZaAcoAiFKJjifzwsGiT/f/quIkxJoklW4yKGho14Olulwn8gN7hOBve0/WGDg5o/l/5mL0w7ff7/YGvefVw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-collapse@3.7.3: - resolution: {integrity: sha512-60FJcdTRn0X5sELF18TANwtVi7FtModq649H11mYF1jh83DniMoM4MqY627sEKRCTm4+WXfGDcB7hY5oW6xhyw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-dialog@9.5.2: - resolution: {integrity: sha512-qVUjc8JukG+j/pNaHVSRa2GO2/KbV2thm7yO4hepQ902eGdYK913sGkwg/fh9yhKYV1ql3BKIN2xnud3rEXAPw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-drawer@7.2.0: - resolution: {integrity: sha512-9lOQ7kBekEJRdEpScHvtmEtXnAsy+NGDXiRWc2ZVC7QXAazNVbeT4EraQKYwCME8BJLa8Bxqxvs5swwyOepRwg==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-dropdown@4.2.0: - resolution: {integrity: sha512-odM8Ove+gSh0zU27DUj5cG1gNKg7mLWBYzB5E4nNLrLwBmYEgYP43vHKDGOVZcJSVElQBI0+jTQgjnq0NfLjng==} - peerDependencies: - react: '>=16.11.0' - react-dom: '>=16.11.0' - - rc-field-form@2.4.0: - resolution: {integrity: sha512-XZ/lF9iqf9HXApIHQHqzJK5v2w4mkUMsVqAzOyWVzoiwwXEavY6Tpuw7HavgzIoD+huVff4JghSGcgEfX6eycg==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-image@7.9.0: - resolution: {integrity: sha512-l4zqO5E0quuLMCtdKfBgj4Suv8tIS011F5k1zBBlK25iMjjiNHxA0VeTzGFtUZERSA45gvpXDg8/P6qNLjR25g==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-input-number@9.2.0: - resolution: {integrity: sha512-5XZFhBCV5f9UQ62AZ2hFbEY8iZT/dm23Q1kAg0H8EvOgD3UDbYYJAayoVIkM3lQaCqYAW5gV0yV3vjw1XtzWHg==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-input@1.6.3: - resolution: {integrity: sha512-wI4NzuqBS8vvKr8cljsvnTUqItMfG1QbJoxovCgL+DX4eVUcHIjVwharwevIxyy7H/jbLryh+K7ysnJr23aWIA==} - peerDependencies: - react: '>=16.0.0' - react-dom: '>=16.0.0' - - rc-mentions@2.15.0: - resolution: {integrity: sha512-f5v5i7VdqvBDXbphoqcQWmXDif2Msd2arritVoWybrVDuHE6nQ7XCYsybHbV//WylooK52BFDouFvyaRDtXZEw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-menu@9.14.1: - resolution: {integrity: sha512-5wlRb3M8S4yGlWhSoEYJ7ZVRElyScdcpUHxgiLxkeig1tEdyKrnED3B2fhpN0Rrpdp9jyhnmZR/Lwq2fH5VvDQ==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-motion@2.9.3: - resolution: {integrity: sha512-rkW47ABVkic7WEB0EKJqzySpvDqwl60/tdkY7hWP7dYnh5pm0SzJpo54oW3TDUGXV5wfxXFmMkxrzRRbotQ0+w==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-notification@5.6.2: - resolution: {integrity: sha512-Id4IYMoii3zzrG0lB0gD6dPgJx4Iu95Xu0BQrhHIbp7ZnAZbLqdqQ73aIWH0d0UFcElxwaKjnzNovTjo7kXz7g==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-overflow@1.3.2: - resolution: {integrity: sha512-nsUm78jkYAoPygDAcGZeC2VwIg/IBGSodtOY3pMof4W3M9qRJgqaDYm03ZayHlde3I6ipliAxbN0RUcGf5KOzw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-pagination@4.2.0: - resolution: {integrity: sha512-V6qeANJsT6tmOcZ4XiUmj8JXjRLbkusuufpuoBw2GiAn94fIixYjFLmbruD1Sbhn8fPLDnWawPp4CN37zQorvw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-picker@4.6.15: - resolution: {integrity: sha512-OWZ1yrMie+KN2uEUfYCfS4b2Vu6RC1FWwNI0s+qypsc3wRt7g+peuZKVIzXCTaJwyyZruo80+akPg2+GmyiJjw==} - engines: {node: '>=8.x'} - peerDependencies: - date-fns: '>= 2.x' - dayjs: '>= 1.x' - luxon: '>= 3.x' - moment: '>= 2.x' - react: '>=16.9.0' - react-dom: '>=16.9.0' - peerDependenciesMeta: - date-fns: - optional: true - dayjs: - optional: true - luxon: - optional: true - moment: - optional: true - - rc-progress@4.0.0: - resolution: {integrity: sha512-oofVMMafOCokIUIBnZLNcOZFsABaUw8PPrf1/y0ZBvKZNpOiu5h4AO9vv11Sw0p4Hb3D0yGWuEattcQGtNJ/aw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-rate@2.13.0: - resolution: {integrity: sha512-oxvx1Q5k5wD30sjN5tqAyWTvJfLNNJn7Oq3IeS4HxWfAiC4BOXMITNAsw7u/fzdtO4MS8Ki8uRLOzcnEuoQiAw==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-resize-observer@1.4.0: - resolution: {integrity: sha512-PnMVyRid9JLxFavTjeDXEXo65HCRqbmLBw9xX9gfC4BZiSzbLXKzW3jPz+J0P71pLbD5tBMTT+mkstV5gD0c9Q==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-segmented@2.3.0: - resolution: {integrity: sha512-I3FtM5Smua/ESXutFfb8gJ8ZPcvFR+qUgeeGFQHBOvRiRKyAk4aBE5nfqrxXx+h8/vn60DQjOt6i4RNtrbOobg==} - peerDependencies: - react: '>=16.0.0' - react-dom: '>=16.0.0' - - rc-select@14.15.2: - resolution: {integrity: sha512-oNoXlaFmpqXYcQDzcPVLrEqS2J9c+/+oJuGrlXeVVX/gVgrbHa5YcyiRUXRydFjyuA7GP3elRuLF7Y3Tfwltlw==} - engines: {node: '>=8.x'} - peerDependencies: - react: '*' - react-dom: '*' - - rc-slider@11.1.6: - resolution: {integrity: sha512-LACAaXM0hi+4x4ErDGZLy7weIQwmBIVbIgPE+eDHiHkyzMvKjWHraCG8/B22Y/tCQUPAsP02wBhKhth7mH2PIw==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-steps@6.0.1: - resolution: {integrity: sha512-lKHL+Sny0SeHkQKKDJlAjV5oZ8DwCdS2hFhAkIjuQt1/pB81M0cA0ErVFdHq9+jmPmFw1vJB2F5NBzFXLJxV+g==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-switch@4.1.0: - resolution: {integrity: sha512-TI8ufP2Az9oEbvyCeVE4+90PDSljGyuwix3fV58p7HV2o4wBnVToEyomJRVyTaZeqNPAp+vqeo4Wnj5u0ZZQBg==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-table@7.45.7: - resolution: {integrity: sha512-wi9LetBL1t1csxyGkMB2p3mCiMt+NDexMlPbXHvQFmBBAsMxrgNSAPwUci2zDLUq9m8QdWc1Nh8suvrpy9mXrg==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-tabs@15.1.1: - resolution: {integrity: sha512-Tc7bJvpEdkWIVCUL7yQrMNBJY3j44NcyWS48jF/UKMXuUlzaXK+Z/pEL5LjGcTadtPvVmNqA40yv7hmr+tCOAw==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-textarea@1.8.2: - resolution: {integrity: sha512-UFAezAqltyR00a8Lf0IPAyTd29Jj9ee8wt8DqXyDMal7r/Cg/nDt3e1OOv3Th4W6mKaZijjgwuPXhAfVNTN8sw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-tooltip@6.2.1: - resolution: {integrity: sha512-rws0duD/3sHHsD905Nex7FvoUGy2UBQRhTkKxeEvr2FB+r21HsOxcDJI0TzyO8NHhnAA8ILr8pfbSBg5Jj5KBg==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-tree-select@5.23.0: - resolution: {integrity: sha512-aQGi2tFSRw1WbXv0UVXPzHm09E0cSvUVZMLxQtMv3rnZZpNmdRXWrnd9QkLNlVH31F+X5rgghmdSFF3yZW0N9A==} - peerDependencies: - react: '*' - react-dom: '*' - - rc-tree@5.9.0: - resolution: {integrity: sha512-CPrgOvm9d/9E+izTONKSngNzQdIEjMox2PBufWjS1wf7vxtvmCWzK1SlpHbRY6IaBfJIeZ+88RkcIevf729cRg==} - engines: {node: '>=10.x'} - peerDependencies: - react: '*' - react-dom: '*' - - rc-upload@4.7.0: - resolution: {integrity: sha512-eUwxYNHlsYe5vYhKFAUGrQG95JrnPzY+BmPi1Daq39fWNl/eOc7v4UODuWrVp2LFkQBuV3cMCG/I68iub6oBrg==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-util@5.43.0: - resolution: {integrity: sha512-AzC7KKOXFqAdIBqdGWepL9Xn7cm3vnAmjlHqUnoQaTMZYhM4VlXGLkkHHxj/BZ7Td0+SOPKB4RGPboBVKT9htw==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - rc-virtual-list@3.14.8: - resolution: {integrity: sha512-8D0KfzpRYi6YZvlOWIxiOm9BGt4Wf2hQyEaM6RXlDDiY2NhLheuYI+RA+7ZaZj1lq+XQqy3KHlaeeXQfzI5fGg==} - engines: {node: '>=8.x'} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - - react-dom@18.2.0: - resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} - peerDependencies: - react: ^18.2.0 - - react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - - react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - - react-timer-hook@3.0.7: - resolution: {integrity: sha512-ATpNcU+PQRxxfNBPVqce2+REtjGAlwmfoNQfcEBMZFxPj0r3GYdKhyPHdStvqrejejEi0QvqaJZjy2lBlFvAsA==} - peerDependencies: - react: '>=16.8.0' - - react-use-websocket@4.9.0: - resolution: {integrity: sha512-/6OaCMggQCTnryCAsw/N+/wfH7bBfIXk5WXTMPdyf0x9HWJXLGUVttAT5hqAimRytD1dkHEJCUrFHAGzOAg1eg==} - - react@18.2.0: - resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} - engines: {node: '>=0.10.0'} - - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - - readdirp@4.0.1: - resolution: {integrity: sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw==} - engines: {node: '>= 14.16.0'} - - reflect.getprototypeof@1.0.6: - resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} - engines: {node: '>= 0.4'} - - regenerator-runtime@0.14.1: - resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - - regexp.prototype.flags@1.5.3: - resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} - engines: {node: '>= 0.4'} - - regexpp@3.2.0: - resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} - engines: {node: '>=8'} - - resize-observer-polyfill@1.5.1: - resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} - - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - - resolve@1.22.8: - resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} - hasBin: true - - resolve@2.0.0-next.5: - resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} - hasBin: true - - reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - - safe-array-concat@1.1.2: - resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} - engines: {node: '>=0.4'} - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - safe-regex-test@1.0.3: - resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} - engines: {node: '>= 0.4'} - - sass@1.79.2: - resolution: {integrity: sha512-YmT1aoF1MwHsZEu/eXhbAJNsPGAhNP4UixW9ckEwWCvPcVdVF0/C104OGDVEqtoctKq0N+wM20O/rj+sSPsWeg==} - engines: {node: '>=14.0.0'} - hasBin: true - - scheduler@0.23.2: - resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} - - scroll-into-view-if-needed@3.1.0: - resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.6.3: - resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} - engines: {node: '>=10'} - hasBin: true - - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - - set-function-name@2.0.2: - resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} - engines: {node: '>= 0.4'} - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - side-channel@1.0.6: - resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} - engines: {node: '>= 0.4'} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - simple-peer@9.11.1: - resolution: {integrity: sha512-D1SaWpOW8afq1CZGWB8xTfrT3FekjQmPValrqncJMX7QFl8YwhrPTZvMCANLtgBwwdS+7zURyqxDDEmY558tTw==} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - stop-iteration-iterator@1.0.0: - resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} - engines: {node: '>= 0.4'} - - streamsearch@1.1.0: - resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} - engines: {node: '>=10.0.0'} - - string-convert@0.2.1: - resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - - string.prototype.includes@2.0.0: - resolution: {integrity: sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==} - - string.prototype.matchall@4.0.11: - resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} - engines: {node: '>= 0.4'} - - string.prototype.repeat@1.0.0: - resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} - - string.prototype.trim@1.2.9: - resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} - engines: {node: '>= 0.4'} - - string.prototype.trimend@1.0.8: - resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} - - string.prototype.trimstart@1.0.8: - resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} - engines: {node: '>= 0.4'} - - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: '>=12'} - - strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - style-mod@4.1.2: - resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} - - styled-jsx@5.1.1: - resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} - engines: {node: '>= 12.0.0'} - peerDependencies: - '@babel/core': '*' - babel-plugin-macros: '*' - react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' - peerDependenciesMeta: - '@babel/core': - optional: true - babel-plugin-macros: - optional: true - - stylis@4.3.4: - resolution: {integrity: sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - tapable@2.2.1: - resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} - engines: {node: '>=6'} - - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - - throttle-debounce@5.0.2: - resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} - engines: {node: '>=12.22'} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - toggle-selection@1.0.6: - resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} - - ts-api-utils@1.3.0: - resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} - engines: {node: '>=16'} - peerDependencies: - typescript: '>=4.2.0' - - tsconfig-paths@3.15.0: - resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} - - tslib@2.7.0: - resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - - typed-array-buffer@1.0.2: - resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} - engines: {node: '>= 0.4'} - - typed-array-byte-length@1.0.1: - resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} - engines: {node: '>= 0.4'} - - typed-array-byte-offset@1.0.2: - resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} - engines: {node: '>= 0.4'} - - typed-array-length@1.0.6: - resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} - engines: {node: '>= 0.4'} - - typeface-montserrat@1.1.13: - resolution: {integrity: sha512-Pklkyj0e+K+6I/t0M6JBDBphpfJkF1k+3qd8qDnp9aVtCC7oGBQWTAcL6+5eArfGe7h73uPwyal73hEkf9YCUA==} - - typescript@5.0.2: - resolution: {integrity: sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==} - engines: {node: '>=12.20'} - hasBin: true - - unbox-primitive@1.0.2: - resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - v8-compile-cache@2.4.0: - resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==} - - w3c-keyname@2.2.8: - resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} - - which-boxed-primitive@1.0.2: - resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} - - which-builtin-type@1.1.4: - resolution: {integrity: sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==} - engines: {node: '>= 0.4'} - - which-collection@1.0.2: - resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} - engines: {node: '>= 0.4'} - - which-typed-array@1.1.15: - resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} - engines: {node: '>= 0.4'} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - ws@8.18.0: - resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - y-codemirror.next@0.3.5: - resolution: {integrity: sha512-VluNu3e5HfEXybnypnsGwKAj+fKLd4iAnR7JuX1Sfyydmn1jCBS5wwEL/uS04Ch2ib0DnMAOF6ZRR/8kK3wyGw==} - peerDependencies: - '@codemirror/state': ^6.0.0 - '@codemirror/view': ^6.0.0 - yjs: ^13.5.6 - - y-protocols@1.0.6: - resolution: {integrity: sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==} - engines: {node: '>=16.0.0', npm: '>=8.0.0'} - peerDependencies: - yjs: ^13.0.0 +dependencies: + '@ant-design/icons': + specifier: ^5.5.1 + version: 5.5.1(react-dom@18.2.0)(react@18.2.0) + '@ant-design/nextjs-registry': + specifier: ^1.0.1 + version: 1.0.1(@ant-design/cssinjs@1.21.1)(antd@5.20.6)(next@14.2.13)(react-dom@18.2.0)(react@18.2.0) + '@codemirror/lang-cpp': + specifier: ^6.0.2 + version: 6.0.2 + '@codemirror/lang-go': + specifier: ^6.0.1 + version: 6.0.1(@codemirror/view@6.34.1) + '@codemirror/lang-java': + specifier: ^6.0.1 + version: 6.0.1 + '@codemirror/lang-javascript': + specifier: ^6.2.2 + version: 6.2.2 + '@codemirror/lang-python': + specifier: ^6.1.6 + version: 6.1.6(@codemirror/view@6.34.1) + '@codemirror/language': + specifier: ^6.10.3 + version: 6.10.3 + '@codemirror/state': + specifier: ^6.4.1 + version: 6.4.1 + antd: + specifier: ^5.20.6 + version: 5.20.6(react-dom@18.2.0)(react@18.2.0) + codemirror: + specifier: ^6.0.1 + version: 6.0.1(@lezer/common@1.2.3) + next: + specifier: 14.2.13 + version: 14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2) + peerjs: + specifier: ^1.5.4 + version: 1.5.4 + react: + specifier: ^18.2.0 + version: 18.2.0 + react-dom: + specifier: ^18.2.0 + version: 18.2.0(react@18.2.0) + react-timer-hook: + specifier: ^3.0.7 + version: 3.0.7(react@18.2.0) + react-use-websocket: + specifier: ^4.9.0 + version: 4.9.0 + sass: + specifier: ^1.79.2 + version: 1.79.2 + typeface-montserrat: + specifier: ^1.1.13 + version: 1.1.13 + y-codemirror.next: + specifier: ^0.3.5 + version: 0.3.5(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(yjs@13.6.20) + y-webrtc: + specifier: ^10.3.0 + version: 10.3.0(yjs@13.6.20) + yjs: + specifier: ^13.6.20 + version: 13.6.20 + +devDependencies: + '@types/node': + specifier: ^20 + version: 20.0.0 + '@types/peerjs': + specifier: ^1.1.0 + version: 1.1.0 + '@types/react': + specifier: ^18.3.8 + version: 18.3.8 + '@types/react-dom': + specifier: ^18.3.0 + version: 18.3.0 + eslint: + specifier: ^8 + version: 8.0.0 + eslint-config-next: + specifier: 14.2.13 + version: 14.2.13(eslint@8.0.0)(typescript@5.0.2) + typescript: + specifier: ^5 + version: 5.0.2 - y-webrtc@10.3.0: - resolution: {integrity: sha512-KalJr7dCgUgyVFxoG3CQYbpS0O2qybegD0vI4bYnYHI0MOwoVbucED3RZ5f2o1a5HZb1qEssUKS0H/Upc6p1lA==} - engines: {node: '>=12'} - hasBin: true - peerDependencies: - yjs: ^13.6.8 - - yjs@13.6.20: - resolution: {integrity: sha512-Z2YZI+SYqK7XdWlloI3lhMiKnCdFCVC4PchpdO+mCYwtiTwncjUbnRK9R1JmkNfdmHyDXuWN3ibJAt0wsqTbLQ==} - engines: {node: '>=16.0.0', npm: '>=8.0.0'} - -snapshots: +packages: - '@ant-design/colors@7.1.0': + /@ant-design/colors@7.1.0: + resolution: {integrity: sha512-MMoDGWn1y9LdQJQSHiCC20x3uZ3CwQnv9QMz6pCmJOrqdgM9YxsoVVY0wtrdXbmfSgnV0KNk6zi09NAhMR2jvg==} dependencies: '@ctrl/tinycolor': 3.6.1 + dev: false - '@ant-design/cssinjs-utils@1.1.0(react-dom@18.2.0)(react@18.2.0)': + /@ant-design/cssinjs-utils@1.1.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-E9nOWObXx7Dy7hdyuYlOFaer/LtPO7oyZVxZphh0CYEslr5EmhJPM3WI0Q2RBHRtYg6dSNqeSK73kvZjPN3IMQ==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0)(react@18.2.0) '@babel/runtime': 7.25.7 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - '@ant-design/cssinjs@1.21.1(react-dom@18.2.0)(react@18.2.0)': + /@ant-design/cssinjs@1.21.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-tyWnlK+XH7Bumd0byfbCiZNK43HEubMoCcu9VxwsAwiHdHTgWa+tMN0/yvxa+e8EzuFP1WdUNNPclRpVtD33lg==} + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' dependencies: '@babel/runtime': 7.25.7 '@emotion/hash': 0.8.0 @@ -1981,14 +131,25 @@ snapshots: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) stylis: 4.3.4 + dev: false - '@ant-design/fast-color@2.0.6': + /@ant-design/fast-color@2.0.6: + resolution: {integrity: sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==} + engines: {node: '>=8.x'} dependencies: '@babel/runtime': 7.25.7 + dev: false - '@ant-design/icons-svg@4.4.2': {} + /@ant-design/icons-svg@4.4.2: + resolution: {integrity: sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==} + dev: false - '@ant-design/icons@5.5.1(react-dom@18.2.0)(react@18.2.0)': + /@ant-design/icons@5.5.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-0UrM02MA2iDIgvLatWrj6YTCYe0F/cwXvVE0E2SqGrL7PZireQwgEKTKBisWpZyal5eXZLvuM98kju6YtYne8w==} + engines: {node: '>=8'} + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' dependencies: '@ant-design/colors': 7.1.0 '@ant-design/icons-svg': 4.4.2 @@ -1997,16 +158,28 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - '@ant-design/nextjs-registry@1.0.1(@ant-design/cssinjs@1.21.1)(antd@5.20.6)(next@14.2.13)(react-dom@18.2.0)(react@18.2.0)': + /@ant-design/nextjs-registry@1.0.1(@ant-design/cssinjs@1.21.1)(antd@5.20.6)(next@14.2.13)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-DaMJ1nClR1a4UfG7vXkDj89z1eARhSDgqvHoxfM0Yco1MZEbaqRj4o+bQToHb3gMb6gbFlrZ51nOBGh5xSJ7EQ==} + peerDependencies: + '@ant-design/cssinjs': ^1.18.2 + antd: ^5.0.0 + next: ^14.0.0 + react: '>=16.0.0' + react-dom: '>=16.0.0' dependencies: '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0)(react@18.2.0) antd: 5.20.6(react-dom@18.2.0)(react@18.2.0) next: 14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - '@ant-design/react-slick@1.1.2(react@18.2.0)': + /@ant-design/react-slick@1.1.2(react@18.2.0): + resolution: {integrity: sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA==} + peerDependencies: + react: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -2014,31 +187,47 @@ snapshots: react: 18.2.0 resize-observer-polyfill: 1.5.1 throttle-debounce: 5.0.2 + dev: false - '@babel/runtime@7.25.7': + /@babel/runtime@7.25.7: + resolution: {integrity: sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==} + engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.1 + dev: false - '@codemirror/autocomplete@6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3)': + /@codemirror/autocomplete@6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3): + resolution: {integrity: sha512-iWHdj/B1ethnHRTwZj+C1obmmuCzquH29EbcKr0qIjA9NfDeBDJ7vs+WOHsFeLeflE4o+dHfYndJloMKHUkWUA==} + peerDependencies: + '@codemirror/language': ^6.0.0 + '@codemirror/state': ^6.0.0 + '@codemirror/view': ^6.0.0 + '@lezer/common': ^1.0.0 dependencies: '@codemirror/language': 6.10.3 '@codemirror/state': 6.4.1 '@codemirror/view': 6.34.1 '@lezer/common': 1.2.3 + dev: false - '@codemirror/commands@6.7.1': + /@codemirror/commands@6.7.1: + resolution: {integrity: sha512-llTrboQYw5H4THfhN4U3qCnSZ1SOJ60ohhz+SzU0ADGtwlc533DtklQP0vSFaQuCPDn3BPpOd1GbbnUtwNjsrw==} dependencies: '@codemirror/language': 6.10.3 '@codemirror/state': 6.4.1 '@codemirror/view': 6.34.1 '@lezer/common': 1.2.3 + dev: false - '@codemirror/lang-cpp@6.0.2': + /@codemirror/lang-cpp@6.0.2: + resolution: {integrity: sha512-6oYEYUKHvrnacXxWxYa6t4puTlbN3dgV662BDfSH8+MfjQjVmP697/KYTDOqpxgerkvoNm7q5wlFMBeX8ZMocg==} dependencies: '@codemirror/language': 6.10.3 '@lezer/cpp': 1.1.2 + dev: false - '@codemirror/lang-go@6.0.1(@codemirror/view@6.34.1)': + /@codemirror/lang-go@6.0.1(@codemirror/view@6.34.1): + resolution: {integrity: sha512-7fNvbyNylvqCphW9HD6WFnRpcDjr+KXX/FgqXy5H5ZS0eC5edDljukm/yNgYkwTsgp2busdod50AOTIy6Jikfg==} dependencies: '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3) '@codemirror/language': 6.10.3 @@ -2047,13 +236,17 @@ snapshots: '@lezer/go': 1.0.0 transitivePeerDependencies: - '@codemirror/view' + dev: false - '@codemirror/lang-java@6.0.1': + /@codemirror/lang-java@6.0.1: + resolution: {integrity: sha512-OOnmhH67h97jHzCuFaIEspbmsT98fNdhVhmA3zCxW0cn7l8rChDhZtwiwJ/JOKXgfm4J+ELxQihxaI7bj7mJRg==} dependencies: '@codemirror/language': 6.10.3 '@lezer/java': 1.1.3 + dev: false - '@codemirror/lang-javascript@6.2.2': + /@codemirror/lang-javascript@6.2.2: + resolution: {integrity: sha512-VGQfY+FCc285AhWuwjYxQyUQcYurWlxdKYT4bqwr3Twnd5wP5WSeu52t4tvvuWmljT4EmgEgZCqSieokhtY8hg==} dependencies: '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3) '@codemirror/language': 6.10.3 @@ -2062,8 +255,10 @@ snapshots: '@codemirror/view': 6.34.1 '@lezer/common': 1.2.3 '@lezer/javascript': 1.4.19 + dev: false - '@codemirror/lang-python@6.1.6(@codemirror/view@6.34.1)': + /@codemirror/lang-python@6.1.6(@codemirror/view@6.34.1): + resolution: {integrity: sha512-ai+01WfZhWqM92UqjnvorkxosZ2aq2u28kHvr+N3gu012XqY2CThD67JPMHnGceRfXPDBmn1HnyqowdpF57bNg==} dependencies: '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3) '@codemirror/language': 6.10.3 @@ -2072,8 +267,10 @@ snapshots: '@lezer/python': 1.1.14 transitivePeerDependencies: - '@codemirror/view' + dev: false - '@codemirror/language@6.10.3': + /@codemirror/language@6.10.3: + resolution: {integrity: sha512-kDqEU5sCP55Oabl6E7m5N+vZRoc0iWqgDVhEKifcHzPzjqCegcO4amfrYVL9PmPZpl4G0yjkpTpUO/Ui8CzO8A==} dependencies: '@codemirror/state': 6.4.1 '@codemirror/view': 6.34.1 @@ -2081,41 +278,67 @@ snapshots: '@lezer/highlight': 1.2.1 '@lezer/lr': 1.4.2 style-mod: 4.1.2 + dev: false - '@codemirror/lint@6.8.2': + /@codemirror/lint@6.8.2: + resolution: {integrity: sha512-PDFG5DjHxSEjOXk9TQYYVjZDqlZTFaDBfhQixHnQOEVDDNHUbEh/hstAjcQJaA6FQdZTD1hquXTK0rVBLADR1g==} dependencies: '@codemirror/state': 6.4.1 '@codemirror/view': 6.34.1 crelt: 1.0.6 + dev: false - '@codemirror/search@6.5.6': + /@codemirror/search@6.5.6: + resolution: {integrity: sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==} dependencies: '@codemirror/state': 6.4.1 '@codemirror/view': 6.34.1 crelt: 1.0.6 + dev: false - '@codemirror/state@6.4.1': {} + /@codemirror/state@6.4.1: + resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==} + dev: false - '@codemirror/view@6.34.1': + /@codemirror/view@6.34.1: + resolution: {integrity: sha512-t1zK/l9UiRqwUNPm+pdIT0qzJlzuVckbTEMVNFhfWkGiBQClstzg+78vedCvLSX0xJEZ6lwZbPpnljL7L6iwMQ==} dependencies: '@codemirror/state': 6.4.1 style-mod: 4.1.2 w3c-keyname: 2.2.8 + dev: false - '@ctrl/tinycolor@3.6.1': {} + /@ctrl/tinycolor@3.6.1: + resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} + engines: {node: '>=10'} + dev: false - '@emotion/hash@0.8.0': {} + /@emotion/hash@0.8.0: + resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} + dev: false - '@emotion/unitless@0.7.5': {} + /@emotion/unitless@0.7.5: + resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==} + dev: false - '@eslint-community/eslint-utils@4.4.0(eslint@8.0.0)': + /@eslint-community/eslint-utils@4.4.0(eslint@8.0.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: eslint: 8.0.0 eslint-visitor-keys: 3.4.3 + dev: true - '@eslint-community/regexpp@4.11.1': {} + /@eslint-community/regexpp@4.11.1: + resolution: {integrity: sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true - '@eslint/eslintrc@1.4.1': + /@eslint/eslintrc@1.4.1: + resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 debug: 4.3.7 @@ -2128,121 +351,233 @@ snapshots: strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color + dev: true - '@humanwhocodes/config-array@0.6.0': + /@humanwhocodes/config-array@0.6.0: + resolution: {integrity: sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead dependencies: '@humanwhocodes/object-schema': 1.2.1 debug: 4.3.7 minimatch: 3.1.2 transitivePeerDependencies: - supports-color + dev: true - '@humanwhocodes/object-schema@1.2.1': {} + /@humanwhocodes/object-schema@1.2.1: + resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + deprecated: Use @eslint/object-schema instead + dev: true - '@isaacs/cliui@8.0.2': + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} dependencies: string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 + string-width-cjs: /string-width@4.2.3 strip-ansi: 7.1.0 - strip-ansi-cjs: strip-ansi@6.0.1 + strip-ansi-cjs: /strip-ansi@6.0.1 wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 + dev: true - '@lezer/common@1.2.3': {} + /@lezer/common@1.2.3: + resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==} + dev: false - '@lezer/cpp@1.1.2': + /@lezer/cpp@1.1.2: + resolution: {integrity: sha512-macwKtyeUO0EW86r3xWQCzOV9/CF8imJLpJlPv3sDY57cPGeUZ8gXWOWNlJr52TVByMV3PayFQCA5SHEERDmVQ==} dependencies: '@lezer/common': 1.2.3 '@lezer/highlight': 1.2.1 '@lezer/lr': 1.4.2 + dev: false - '@lezer/go@1.0.0': + /@lezer/go@1.0.0: + resolution: {integrity: sha512-co9JfT3QqX1YkrMmourYw2Z8meGC50Ko4d54QEcQbEYpvdUvN4yb0NBZdn/9ertgvjsySxHsKzH3lbm3vqJ4Jw==} dependencies: '@lezer/common': 1.2.3 '@lezer/highlight': 1.2.1 '@lezer/lr': 1.4.2 + dev: false - '@lezer/highlight@1.2.1': + /@lezer/highlight@1.2.1: + resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==} dependencies: '@lezer/common': 1.2.3 + dev: false - '@lezer/java@1.1.3': + /@lezer/java@1.1.3: + resolution: {integrity: sha512-yHquUfujwg6Yu4Fd1GNHCvidIvJwi/1Xu2DaKl/pfWIA2c1oXkVvawH3NyXhCaFx4OdlYBVX5wvz2f7Aoa/4Xw==} dependencies: '@lezer/common': 1.2.3 '@lezer/highlight': 1.2.1 '@lezer/lr': 1.4.2 + dev: false - '@lezer/javascript@1.4.19': + /@lezer/javascript@1.4.19: + resolution: {integrity: sha512-j44kbR1QL26l6dMunZ1uhKBFteVGLVCBGNUD2sUaMnic+rbTviVuoK0CD1l9FTW31EueWvFFswCKMH7Z+M3JRA==} dependencies: '@lezer/common': 1.2.3 '@lezer/highlight': 1.2.1 '@lezer/lr': 1.4.2 + dev: false - '@lezer/lr@1.4.2': + /@lezer/lr@1.4.2: + resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==} dependencies: '@lezer/common': 1.2.3 + dev: false - '@lezer/python@1.1.14': + /@lezer/python@1.1.14: + resolution: {integrity: sha512-ykDOb2Ti24n76PJsSa4ZoDF0zH12BSw1LGfQXCYJhJyOGiFTfGaX0Du66Ze72R+u/P35U+O6I9m8TFXov1JzsA==} dependencies: '@lezer/common': 1.2.3 '@lezer/highlight': 1.2.1 '@lezer/lr': 1.4.2 + dev: false + + /@msgpack/msgpack@2.8.0: + resolution: {integrity: sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ==} + engines: {node: '>= 10'} - '@next/env@14.2.13': {} + /@next/env@14.2.13: + resolution: {integrity: sha512-s3lh6K8cbW1h5Nga7NNeXrbe0+2jIIYK9YaA9T7IufDWnZpozdFUp6Hf0d5rNWUKu4fEuSX2rCKlGjCrtylfDw==} + dev: false - '@next/eslint-plugin-next@14.2.13': + /@next/eslint-plugin-next@14.2.13: + resolution: {integrity: sha512-z8Mk0VljxhIzsSiZUSdt3wp+t2lKd+jk5a9Jsvh3zDGkItgDMfjv/ZbET6HsxEl/fSihVoHGsXV6VLyDH0lfTQ==} dependencies: glob: 10.3.10 + dev: true - '@next/swc-darwin-arm64@14.2.13': + /@next/swc-darwin-arm64@14.2.13: + resolution: {integrity: sha512-IkAmQEa2Htq+wHACBxOsslt+jMoV3msvxCn0WFSfJSkv/scy+i/EukBKNad36grRxywaXUYJc9mxEGkeIs8Bzg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false optional: true - '@next/swc-darwin-x64@14.2.13': + /@next/swc-darwin-x64@14.2.13: + resolution: {integrity: sha512-Dv1RBGs2TTjkwEnFMVL5XIfJEavnLqqwYSD6LXgTPdEy/u6FlSrLBSSfe1pcfqhFEXRAgVL3Wpjibe5wXJzWog==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false optional: true - '@next/swc-linux-arm64-gnu@14.2.13': + /@next/swc-linux-arm64-gnu@14.2.13: + resolution: {integrity: sha512-yB1tYEFFqo4ZNWkwrJultbsw7NPAAxlPXURXioRl9SdW6aIefOLS+0TEsKrWBtbJ9moTDgU3HRILL6QBQnMevg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@next/swc-linux-arm64-musl@14.2.13': + /@next/swc-linux-arm64-musl@14.2.13: + resolution: {integrity: sha512-v5jZ/FV/eHGoWhMKYrsAweQ7CWb8xsWGM/8m1mwwZQ/sutJjoFaXchwK4pX8NqwImILEvQmZWyb8pPTcP7htWg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@next/swc-linux-x64-gnu@14.2.13': + /@next/swc-linux-x64-gnu@14.2.13: + resolution: {integrity: sha512-aVc7m4YL7ViiRv7SOXK3RplXzOEe/qQzRA5R2vpXboHABs3w8vtFslGTz+5tKiQzWUmTmBNVW0UQdhkKRORmGA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@next/swc-linux-x64-musl@14.2.13': + /@next/swc-linux-x64-musl@14.2.13: + resolution: {integrity: sha512-4wWY7/OsSaJOOKvMsu1Teylku7vKyTuocvDLTZQq0TYv9OjiYYWt63PiE1nTuZnqQ4RPvME7Xai+9enoiN0Wrg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false optional: true - '@next/swc-win32-arm64-msvc@14.2.13': + /@next/swc-win32-arm64-msvc@14.2.13: + resolution: {integrity: sha512-uP1XkqCqV2NVH9+g2sC7qIw+w2tRbcMiXFEbMihkQ8B1+V6m28sshBwAB0SDmOe0u44ne1vFU66+gx/28RsBVQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false optional: true - '@next/swc-win32-ia32-msvc@14.2.13': + /@next/swc-win32-ia32-msvc@14.2.13: + resolution: {integrity: sha512-V26ezyjPqQpDBV4lcWIh8B/QICQ4v+M5Bo9ykLN+sqeKKBxJVDpEc6biDVyluTXTC40f5IqCU0ttth7Es2ZuMw==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false optional: true - '@next/swc-win32-x64-msvc@14.2.13': + /@next/swc-win32-x64-msvc@14.2.13: + resolution: {integrity: sha512-WwzOEAFBGhlDHE5Z73mNU8CO8mqMNLqaG+AO9ETmzdCQlJhVtWZnOl2+rqgVQS+YHunjOWptdFmNfbpwcUuEsw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false optional: true - '@nodelib/fs.scandir@2.1.5': + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} dependencies: '@nodelib/fs.stat': 2.0.5 run-parallel: 1.2.0 + dev: true - '@nodelib/fs.stat@2.0.5': {} + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true - '@nodelib/fs.walk@1.2.8': + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} dependencies: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 + dev: true - '@nolyfill/is-core-module@1.0.39': {} + /@nolyfill/is-core-module@1.0.39: + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} + engines: {node: '>=12.4.0'} + dev: true - '@pkgjs/parseargs@0.11.0': + /@pkgjs/parseargs@0.11.0: + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + requiresBuild: true + dev: true optional: true - '@rc-component/async-validator@5.0.4': + /@rc-component/async-validator@5.0.4: + resolution: {integrity: sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==} + engines: {node: '>=14.x'} dependencies: '@babel/runtime': 7.25.7 + dev: false - '@rc-component/color-picker@2.0.1(react-dom@18.2.0)(react@18.2.0)': + /@rc-component/color-picker@2.0.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-WcZYwAThV/b2GISQ8F+7650r5ZZJ043E57aVBFkQ+kSY4C6wdofXgB0hBx+GPGpIU0Z81eETNoDUJMr7oy/P8Q==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@ant-design/fast-color': 2.0.6 '@babel/runtime': 7.25.7 @@ -2250,43 +585,75 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - '@rc-component/context@1.4.0(react-dom@18.2.0)(react@18.2.0)': + /@rc-component/context@1.4.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - '@rc-component/mini-decimal@1.1.0': + /@rc-component/mini-decimal@1.1.0: + resolution: {integrity: sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==} + engines: {node: '>=8.x'} dependencies: '@babel/runtime': 7.25.7 + dev: false - '@rc-component/mutate-observer@1.1.0(react-dom@18.2.0)(react@18.2.0)': + /@rc-component/mutate-observer@1.1.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - '@rc-component/portal@1.1.2(react-dom@18.2.0)(react@18.2.0)': + /@rc-component/portal@1.1.2(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - '@rc-component/qrcode@1.0.0(react-dom@18.2.0)(react@18.2.0)': + /@rc-component/qrcode@1.0.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-L+rZ4HXP2sJ1gHMGHjsg9jlYBX/SLN2D6OxP9Zn3qgtpMWtO2vUfxVFwiogHpAIqs54FnALxraUy/BCO1yRIgg==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - '@rc-component/tour@1.15.1(react-dom@18.2.0)(react@18.2.0)': + /@rc-component/tour@1.15.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Tr2t7J1DKZUpfJuDZWHxyxWpfmj8EZrqSgyMZ+BCdvKZ6r1UDsfU46M/iWAAFBy961Ssfom2kv5f3UcjIL2CmQ==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) @@ -2295,8 +662,14 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - '@rc-component/trigger@2.2.3(react-dom@18.2.0)(react@18.2.0)': + /@rc-component/trigger@2.2.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-X1oFIpKoXAMXNDYCviOmTfuNuYxE4h5laBsyCqVAVMjNHxoF3/uiyA7XdegK1XbCvBbCZ6P6byWrEoDRpKL8+A==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) @@ -2306,34 +679,69 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - '@rtsao/scc@1.1.0': {} + /@rtsao/scc@1.1.0: + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + dev: true - '@rushstack/eslint-patch@1.10.4': {} + /@rushstack/eslint-patch@1.10.4: + resolution: {integrity: sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==} + dev: true - '@swc/counter@0.1.3': {} + /@swc/counter@0.1.3: + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + dev: false - '@swc/helpers@0.5.5': + /@swc/helpers@0.5.5: + resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} dependencies: '@swc/counter': 0.1.3 tslib: 2.7.0 + dev: false + + /@types/json5@0.0.29: + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + dev: true - '@types/json5@0.0.29': {} + /@types/node@20.0.0: + resolution: {integrity: sha512-cD2uPTDnQQCVpmRefonO98/PPijuOnnEy5oytWJFPY1N9aJCz2wJ5kSGWO+zJoed2cY2JxQh6yBuUq4vIn61hw==} + dev: true - '@types/node@20.0.0': {} + /@types/peerjs@1.1.0: + resolution: {integrity: sha512-dVocsfYFg5QQuUB9OAxfrSvz4br4pyX+7M61ZJSRiYtE3NdayShk1p1Y8b9TmCj724TwHskVraeF7wyPl0rYcg==} + deprecated: This is a stub types definition. peerjs provides its own type definitions, so you do not need this installed. + dependencies: + peerjs: 1.5.4 + dev: true - '@types/prop-types@15.7.13': {} + /@types/prop-types@15.7.13: + resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==} + dev: true - '@types/react-dom@18.3.0': + /@types/react-dom@18.3.0: + resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} dependencies: '@types/react': 18.3.8 + dev: true - '@types/react@18.3.8': + /@types/react@18.3.8: + resolution: {integrity: sha512-syBUrW3/XpnW4WJ41Pft+I+aPoDVbrBVQGEnbD7NijDGlVC+8gV/XKRY+7vMDlfPpbwYt0l1vd/Sj8bJGMbs9Q==} dependencies: '@types/prop-types': 15.7.13 csstype: 3.1.3 + dev: true - '@typescript-eslint/eslint-plugin@8.8.0(@typescript-eslint/parser@8.8.0)(eslint@8.0.0)(typescript@5.0.2)': + /@typescript-eslint/eslint-plugin@8.8.0(@typescript-eslint/parser@8.8.0)(eslint@8.0.0)(typescript@5.0.2): + resolution: {integrity: sha512-wORFWjU30B2WJ/aXBfOm1LX9v9nyt9D3jsSOxC3cCaTQGCW5k4jNpmjFv3U7p/7s4yvdjHzwtv2Sd2dOyhjS0A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true dependencies: '@eslint-community/regexpp': 4.11.1 '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) @@ -2349,8 +757,17 @@ snapshots: typescript: 5.0.2 transitivePeerDependencies: - supports-color + dev: true - '@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2)': + /@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2): + resolution: {integrity: sha512-uEFUsgR+tl8GmzmLjRqz+VrDv4eoaMqMXW7ruXfgThaAShO9JTciKpEsB+TvnfFfbg5IpujgMXVV36gOJRLtZg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true dependencies: '@typescript-eslint/scope-manager': 8.8.0 '@typescript-eslint/types': 8.8.0 @@ -2361,13 +778,24 @@ snapshots: typescript: 5.0.2 transitivePeerDependencies: - supports-color + dev: true - '@typescript-eslint/scope-manager@8.8.0': + /@typescript-eslint/scope-manager@8.8.0: + resolution: {integrity: sha512-EL8eaGC6gx3jDd8GwEFEV091210U97J0jeEHrAYvIYosmEGet4wJ+g0SYmLu+oRiAwbSA5AVrt6DxLHfdd+bUg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: '@typescript-eslint/types': 8.8.0 '@typescript-eslint/visitor-keys': 8.8.0 + dev: true - '@typescript-eslint/type-utils@8.8.0(eslint@8.0.0)(typescript@5.0.2)': + /@typescript-eslint/type-utils@8.8.0(eslint@8.0.0)(typescript@5.0.2): + resolution: {integrity: sha512-IKwJSS7bCqyCeG4NVGxnOP6lLT9Okc3Zj8hLO96bpMkJab+10HIfJbMouLrlpyOr3yrQ1cA413YPFiGd1mW9/Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true dependencies: '@typescript-eslint/typescript-estree': 8.8.0(typescript@5.0.2) '@typescript-eslint/utils': 8.8.0(eslint@8.0.0)(typescript@5.0.2) @@ -2377,10 +805,21 @@ snapshots: transitivePeerDependencies: - eslint - supports-color + dev: true - '@typescript-eslint/types@8.8.0': {} + /@typescript-eslint/types@8.8.0: + resolution: {integrity: sha512-QJwc50hRCgBd/k12sTykOJbESe1RrzmX6COk8Y525C9l7oweZ+1lw9JiU56im7Amm8swlz00DRIlxMYLizr2Vw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true - '@typescript-eslint/typescript-estree@8.8.0(typescript@5.0.2)': + /@typescript-eslint/typescript-estree@8.8.0(typescript@5.0.2): + resolution: {integrity: sha512-ZaMJwc/0ckLz5DaAZ+pNLmHv8AMVGtfWxZe/x2JVEkD5LnmhWiQMMcYT7IY7gkdJuzJ9P14fRy28lUrlDSWYdw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true dependencies: '@typescript-eslint/types': 8.8.0 '@typescript-eslint/visitor-keys': 8.8.0 @@ -2393,8 +832,13 @@ snapshots: typescript: 5.0.2 transitivePeerDependencies: - supports-color + dev: true - '@typescript-eslint/utils@8.8.0(eslint@8.0.0)(typescript@5.0.2)': + /@typescript-eslint/utils@8.8.0(eslint@8.0.0)(typescript@5.0.2): + resolution: {integrity: sha512-QE2MgfOTem00qrlPgyByaCHay9yb1+9BjnMFnSFkUKQfu7adBXDTnCAivURnuPPAG/qiB+kzKkZKmKfaMT0zVg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.0.0) '@typescript-eslint/scope-manager': 8.8.0 @@ -2404,38 +848,71 @@ snapshots: transitivePeerDependencies: - supports-color - typescript + dev: true - '@typescript-eslint/visitor-keys@8.8.0': + /@typescript-eslint/visitor-keys@8.8.0: + resolution: {integrity: sha512-8mq51Lx6Hpmd7HnA2fcHQo3YgfX1qbccxQOgZcb4tvasu//zXRaA1j5ZRFeCw/VRAdFi4mRM9DnZw0Nu0Q2d1g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: '@typescript-eslint/types': 8.8.0 eslint-visitor-keys: 3.4.3 + dev: true - acorn-jsx@5.3.2(acorn@8.12.1): + /acorn-jsx@5.3.2(acorn@8.12.1): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: acorn: 8.12.1 + dev: true - acorn@8.12.1: {} + /acorn@8.12.1: + resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true - ajv@6.12.6: + /ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 + dev: true - ansi-colors@4.1.3: {} + /ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + dev: true - ansi-regex@5.0.1: {} + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true - ansi-regex@6.1.0: {} + /ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + dev: true - ansi-styles@4.3.0: + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} dependencies: color-convert: 2.0.1 + dev: true - ansi-styles@6.2.1: {} + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: true - antd@5.20.6(react-dom@18.2.0)(react@18.2.0): + /antd@5.20.6(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-TZFmNenHlh26DelHCJbkB+x1OVulIKsN1f/CnAd2NxZLysXqRvSuLUeHcgccqAnxTy7B03GZ6i1tocGxPCNjgA==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@ant-design/colors': 7.1.0 '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0)(react@18.2.0) @@ -2492,19 +969,29 @@ snapshots: - date-fns - luxon - moment + dev: false - argparse@2.0.1: {} + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true - aria-query@5.1.3: + /aria-query@5.1.3: + resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} dependencies: deep-equal: 2.2.3 + dev: true - array-buffer-byte-length@1.0.1: + /array-buffer-byte-length@1.0.1: + resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 is-array-buffer: 3.0.4 + dev: true - array-includes@3.1.8: + /array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 @@ -2512,10 +999,15 @@ snapshots: es-object-atoms: 1.0.0 get-intrinsic: 1.2.4 is-string: 1.0.7 + dev: true - array-tree-filter@2.1.0: {} + /array-tree-filter@2.1.0: + resolution: {integrity: sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==} + dev: false - array.prototype.findlast@1.2.5: + /array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 @@ -2523,8 +1015,11 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.0.0 es-shim-unscopables: 1.0.2 + dev: true - array.prototype.findlastindex@1.2.5: + /array.prototype.findlastindex@1.2.5: + resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 @@ -2532,30 +1027,42 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.0.0 es-shim-unscopables: 1.0.2 + dev: true - array.prototype.flat@1.3.2: + /array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-shim-unscopables: 1.0.2 + dev: true - array.prototype.flatmap@1.3.2: + /array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-shim-unscopables: 1.0.2 + dev: true - array.prototype.tosorted@1.1.4: + /array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-errors: 1.3.0 es-shim-unscopables: 1.0.2 + dev: true - arraybuffer.prototype.slice@1.0.3: + /arraybuffer.prototype.slice@1.0.3: + resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + engines: {node: '>= 0.4'} dependencies: array-buffer-byte-length: 1.0.1 call-bind: 1.0.7 @@ -2565,69 +1072,116 @@ snapshots: get-intrinsic: 1.2.4 is-array-buffer: 3.0.4 is-shared-array-buffer: 1.0.3 + dev: true - ast-types-flow@0.0.8: {} + /ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + dev: true - available-typed-arrays@1.0.7: + /available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} dependencies: possible-typed-array-names: 1.0.0 + dev: true - axe-core@4.10.0: {} + /axe-core@4.10.0: + resolution: {integrity: sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==} + engines: {node: '>=4'} + dev: true - axobject-query@4.1.0: {} + /axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + dev: true - balanced-match@1.0.2: {} + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true - base64-js@1.5.1: {} + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: false - brace-expansion@1.1.11: + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 + dev: true - brace-expansion@2.0.1: + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: balanced-match: 1.0.2 + dev: true - braces@3.0.3: + /braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} dependencies: fill-range: 7.1.1 + dev: true - buffer@6.0.3: + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} dependencies: base64-js: 1.5.1 ieee754: 1.2.1 + dev: false - busboy@1.6.0: + /busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} dependencies: streamsearch: 1.1.0 + dev: false - call-bind@1.0.7: + /call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} dependencies: es-define-property: 1.0.0 es-errors: 1.3.0 function-bind: 1.1.2 get-intrinsic: 1.2.4 set-function-length: 1.2.2 + dev: true - callsites@3.1.0: {} + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true - caniuse-lite@1.0.30001666: {} + /caniuse-lite@1.0.30001666: + resolution: {integrity: sha512-gD14ICmoV5ZZM1OdzPWmpx+q4GyefaK06zi8hmfHV5xe4/2nOQX3+Dw5o+fSqOws2xVwL9j+anOPFwHzdEdV4g==} + dev: false - chalk@4.1.2: + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 + dev: true - chokidar@4.0.1: + /chokidar@4.0.1: + resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} + engines: {node: '>= 14.16.0'} dependencies: readdirp: 4.0.1 + dev: false - classnames@2.5.1: {} + /classnames@2.5.1: + resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + dev: false - client-only@0.0.1: {} + /client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + dev: false - codemirror@6.0.1(@lezer/common@1.2.3): + /codemirror@6.0.1(@lezer/common@1.2.3): + resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==} dependencies: '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3) '@codemirror/commands': 6.7.1 @@ -2638,62 +1192,109 @@ snapshots: '@codemirror/view': 6.34.1 transitivePeerDependencies: - '@lezer/common' + dev: false - color-convert@2.0.1: + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 + dev: true - color-name@1.1.4: {} + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true - compute-scroll-into-view@3.1.0: {} + /compute-scroll-into-view@3.1.0: + resolution: {integrity: sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==} + dev: false - concat-map@0.0.1: {} + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true - copy-to-clipboard@3.3.3: + /copy-to-clipboard@3.3.3: + resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} dependencies: toggle-selection: 1.0.6 + dev: false - crelt@1.0.6: {} + /crelt@1.0.6: + resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + dev: false - cross-spawn@7.0.3: + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 + dev: true - csstype@3.1.3: {} + /csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - damerau-levenshtein@1.0.8: {} + /damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + dev: true - data-view-buffer@1.0.1: + /data-view-buffer@1.0.1: + resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-data-view: 1.0.1 + dev: true - data-view-byte-length@1.0.1: + /data-view-byte-length@1.0.1: + resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-data-view: 1.0.1 + dev: true - data-view-byte-offset@1.0.0: + /data-view-byte-offset@1.0.0: + resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-data-view: 1.0.1 + dev: true - dayjs@1.11.13: {} + /dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + dev: false - debug@3.2.7: + /debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true dependencies: ms: 2.1.3 + dev: true - debug@4.3.7: + /debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true dependencies: ms: 2.1.3 - deep-equal@2.2.3: + /deep-equal@2.2.3: + resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==} + engines: {node: '>= 0.4'} dependencies: array-buffer-byte-length: 1.0.1 call-bind: 1.0.7 @@ -2713,48 +1314,79 @@ snapshots: which-boxed-primitive: 1.0.2 which-collection: 1.0.2 which-typed-array: 1.1.15 + dev: true - deep-is@0.1.4: {} + /deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true - define-data-property@1.1.4: + /define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} dependencies: es-define-property: 1.0.0 es-errors: 1.3.0 gopd: 1.0.1 + dev: true - define-properties@1.2.1: + /define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} dependencies: define-data-property: 1.1.4 has-property-descriptors: 1.0.2 object-keys: 1.1.1 + dev: true - doctrine@2.1.0: + /doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} dependencies: esutils: 2.0.3 + dev: true - doctrine@3.0.0: + /doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} dependencies: esutils: 2.0.3 + dev: true - eastasianwidth@0.2.0: {} + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true - emoji-regex@8.0.0: {} + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true - emoji-regex@9.2.2: {} + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true - enhanced-resolve@5.17.1: + /enhanced-resolve@5.17.1: + resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} + engines: {node: '>=10.13.0'} dependencies: graceful-fs: 4.2.11 tapable: 2.2.1 + dev: true - enquirer@2.4.1: + /enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} dependencies: ansi-colors: 4.1.3 strip-ansi: 6.0.1 + dev: true - err-code@3.0.1: {} + /err-code@3.0.1: + resolution: {integrity: sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==} + dev: false - es-abstract@1.23.3: + /es-abstract@1.23.3: + resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} + engines: {node: '>= 0.4'} dependencies: array-buffer-byte-length: 1.0.1 arraybuffer.prototype.slice: 1.0.3 @@ -2802,14 +1434,22 @@ snapshots: typed-array-length: 1.0.6 unbox-primitive: 1.0.2 which-typed-array: 1.1.15 + dev: true - es-define-property@1.0.0: + /es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} dependencies: get-intrinsic: 1.2.4 + dev: true - es-errors@1.3.0: {} + /es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + dev: true - es-get-iterator@1.1.3: + /es-get-iterator@1.1.3: + resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} dependencies: call-bind: 1.0.7 get-intrinsic: 1.2.4 @@ -2820,8 +1460,11 @@ snapshots: is-string: 1.0.7 isarray: 2.0.5 stop-iteration-iterator: 1.0.0 + dev: true - es-iterator-helpers@1.0.19: + /es-iterator-helpers@1.0.19: + resolution: {integrity: sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 @@ -2837,30 +1480,52 @@ snapshots: internal-slot: 1.0.7 iterator.prototype: 1.1.2 safe-array-concat: 1.1.2 + dev: true - es-object-atoms@1.0.0: + /es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} dependencies: es-errors: 1.3.0 + dev: true - es-set-tostringtag@2.0.3: + /es-set-tostringtag@2.0.3: + resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + engines: {node: '>= 0.4'} dependencies: get-intrinsic: 1.2.4 has-tostringtag: 1.0.2 hasown: 2.0.2 + dev: true - es-shim-unscopables@1.0.2: + /es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} dependencies: hasown: 2.0.2 + dev: true - es-to-primitive@1.2.1: + /es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} dependencies: is-callable: 1.2.7 is-date-object: 1.0.5 is-symbol: 1.0.4 + dev: true - escape-string-regexp@4.0.0: {} + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true - eslint-config-next@14.2.13(eslint@8.0.0)(typescript@5.0.2): + /eslint-config-next@14.2.13(eslint@8.0.0)(typescript@5.0.2): + resolution: {integrity: sha512-aro1EKAoyYchnO/3Tlo91hnNBO7QO7qnv/79MAFC+4Jq8TdUVKQlht5d2F+YjrePjdpOvfL+mV9JPfyYNwkk1g==} + peerDependencies: + eslint: ^7.23.0 || ^8.0.0 + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true dependencies: '@next/eslint-plugin-next': 14.2.13 '@rushstack/eslint-patch': 1.10.4 @@ -2878,16 +1543,30 @@ snapshots: - eslint-import-resolver-webpack - eslint-plugin-import-x - supports-color + dev: true - eslint-import-resolver-node@0.3.9: + /eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} dependencies: debug: 3.2.7 is-core-module: 2.15.1 resolve: 1.22.8 transitivePeerDependencies: - supports-color + dev: true - eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0): + /eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0): + resolution: {integrity: sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.3.7 @@ -2904,8 +1583,28 @@ snapshots: - eslint-import-resolver-node - eslint-import-resolver-webpack - supports-color + dev: true - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): + /eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true dependencies: '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) debug: 3.2.7 @@ -2914,8 +1613,17 @@ snapshots: eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0) transitivePeerDependencies: - supports-color + dev: true - eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): + /eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): + resolution: {integrity: sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true dependencies: '@rtsao/scc': 1.1.0 '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) @@ -2941,8 +1649,13 @@ snapshots: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color + dev: true - eslint-plugin-jsx-a11y@6.10.0(eslint@8.0.0): + /eslint-plugin-jsx-a11y@6.10.0(eslint@8.0.0): + resolution: {integrity: sha512-ySOHvXX8eSN6zz8Bywacm7CvGNhUtdjvqfQDVe6020TUK34Cywkw7m0KsCCk1Qtm9G1FayfTN1/7mMYnYO2Bhg==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 dependencies: aria-query: 5.1.3 array-includes: 3.1.8 @@ -2961,12 +1674,22 @@ snapshots: object.fromentries: 2.0.8 safe-regex-test: 1.0.3 string.prototype.includes: 2.0.0 + dev: true - eslint-plugin-react-hooks@4.6.2(eslint@8.0.0): + /eslint-plugin-react-hooks@4.6.2(eslint@8.0.0): + resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 dependencies: eslint: 8.0.0 + dev: true - eslint-plugin-react@7.37.1(eslint@8.0.0): + /eslint-plugin-react@7.37.1(eslint@8.0.0): + resolution: {integrity: sha512-xwTnwDqzbDRA8uJ7BMxPs/EXRB3i8ZfnOIp8BsxEQkT0nHPp+WWceqGgo6rKb9ctNi8GJLDT4Go5HAWELa/WMg==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 @@ -2987,22 +1710,40 @@ snapshots: semver: 6.3.1 string.prototype.matchall: 4.0.11 string.prototype.repeat: 1.0.0 + dev: true - eslint-scope@6.0.0: + /eslint-scope@6.0.0: + resolution: {integrity: sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 + dev: true - eslint-utils@3.0.0(eslint@8.0.0): + /eslint-utils@3.0.0(eslint@8.0.0): + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' dependencies: eslint: 8.0.0 eslint-visitor-keys: 2.1.0 + dev: true - eslint-visitor-keys@2.1.0: {} + /eslint-visitor-keys@2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} + engines: {node: '>=10'} + dev: true - eslint-visitor-keys@3.4.3: {} + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true - eslint@8.0.0: + /eslint@8.0.0: + resolution: {integrity: sha512-03spzPzMAO4pElm44m60Nj08nYonPGQXmw6Ceai/S4QK82IgwWO1EXx1s9namKzVlbVu3Jf81hb+N+8+v21/HQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true dependencies: '@eslint/eslintrc': 1.4.1 '@humanwhocodes/config-array': 0.6.0 @@ -3044,120 +1785,199 @@ snapshots: v8-compile-cache: 2.4.0 transitivePeerDependencies: - supports-color + dev: true - espree@9.6.1: + /espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: acorn: 8.12.1 acorn-jsx: 5.3.2(acorn@8.12.1) eslint-visitor-keys: 3.4.3 + dev: true - esquery@1.6.0: + /esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} dependencies: estraverse: 5.3.0 + dev: true - esrecurse@4.3.0: + /esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} dependencies: estraverse: 5.3.0 + dev: true + + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true - estraverse@5.3.0: {} + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true - esutils@2.0.3: {} + /eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} - fast-deep-equal@3.1.3: {} + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true - fast-glob@3.3.2: + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.8 + dev: true - fast-json-stable-stringify@2.1.0: {} + /fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + dev: true - fast-levenshtein@2.0.6: {} + /fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + dev: true - fastq@1.17.1: + /fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} dependencies: reusify: 1.0.4 + dev: true - file-entry-cache@6.0.1: + /file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} dependencies: flat-cache: 3.2.0 + dev: true - fill-range@7.1.1: + /fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} dependencies: to-regex-range: 5.0.1 + dev: true - flat-cache@3.2.0: + /flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} dependencies: flatted: 3.3.1 keyv: 4.5.4 rimraf: 3.0.2 + dev: true - flatted@3.3.1: {} + /flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + dev: true - for-each@0.3.3: + /for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} dependencies: is-callable: 1.2.7 + dev: true - foreground-child@3.3.0: + /foreground-child@3.3.0: + resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} + engines: {node: '>=14'} dependencies: cross-spawn: 7.0.3 signal-exit: 4.1.0 + dev: true - fs.realpath@1.0.0: {} + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: true - function-bind@1.1.2: {} + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true - function.prototype.name@1.1.6: + /function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 functions-have-names: 1.2.3 + dev: true - functional-red-black-tree@1.0.1: {} + /functional-red-black-tree@1.0.1: + resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} + dev: true - functions-have-names@1.2.3: {} + /functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + dev: true - get-browser-rtc@1.1.0: {} + /get-browser-rtc@1.1.0: + resolution: {integrity: sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ==} + dev: false - get-intrinsic@1.2.4: + /get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} dependencies: es-errors: 1.3.0 function-bind: 1.1.2 has-proto: 1.0.3 has-symbols: 1.0.3 hasown: 2.0.2 + dev: true - get-symbol-description@1.0.2: + /get-symbol-description@1.0.2: + resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 es-errors: 1.3.0 get-intrinsic: 1.2.4 + dev: true - get-tsconfig@4.8.1: + /get-tsconfig@4.8.1: + resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} dependencies: resolve-pkg-maps: 1.0.0 + dev: true - glob-parent@5.1.2: + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} dependencies: is-glob: 4.0.3 + dev: true - glob-parent@6.0.2: + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} dependencies: is-glob: 4.0.3 + dev: true - glob@10.3.10: + /glob@10.3.10: + resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true dependencies: foreground-child: 3.3.0 jackspeak: 2.3.6 minimatch: 9.0.5 minipass: 7.1.2 path-scurry: 1.11.1 + dev: true - glob@7.2.3: + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -3165,273 +1985,495 @@ snapshots: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 + dev: true - globals@13.24.0: + /globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} dependencies: type-fest: 0.20.2 + dev: true - globalthis@1.0.4: + /globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} dependencies: define-properties: 1.2.1 gopd: 1.0.1 + dev: true - gopd@1.0.1: + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: get-intrinsic: 1.2.4 + dev: true - graceful-fs@4.2.11: {} + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - graphemer@1.4.0: {} + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + dev: true - has-bigints@1.0.2: {} + /has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + dev: true - has-flag@4.0.0: {} + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + dev: true - has-property-descriptors@1.0.2: + /has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} dependencies: es-define-property: 1.0.0 + dev: true - has-proto@1.0.3: {} + /has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + dev: true - has-symbols@1.0.3: {} + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: true - has-tostringtag@1.0.2: + /has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} dependencies: has-symbols: 1.0.3 + dev: true - hasown@2.0.2: + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} dependencies: function-bind: 1.1.2 + dev: true - ieee754@1.2.1: {} + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: false - ignore@4.0.6: {} + /ignore@4.0.6: + resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} + engines: {node: '>= 4'} + dev: true - ignore@5.3.2: {} + /ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + dev: true - immutable@4.3.7: {} + /immutable@4.3.7: + resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} + dev: false - import-fresh@3.3.0: + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 + dev: true - imurmurhash@0.1.4: {} + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: true - inflight@1.0.6: + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. dependencies: once: 1.4.0 wrappy: 1.0.2 + dev: true - inherits@2.0.4: {} + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - internal-slot@1.0.7: + /internal-slot@1.0.7: + resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} + engines: {node: '>= 0.4'} dependencies: es-errors: 1.3.0 hasown: 2.0.2 side-channel: 1.0.6 + dev: true - is-arguments@1.1.1: + /is-arguments@1.1.1: + resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 has-tostringtag: 1.0.2 + dev: true - is-array-buffer@3.0.4: + /is-array-buffer@3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 get-intrinsic: 1.2.4 + dev: true - is-async-function@2.0.0: + /is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.2 + dev: true - is-bigint@1.0.4: + /is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} dependencies: has-bigints: 1.0.2 + dev: true - is-boolean-object@1.1.2: + /is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 has-tostringtag: 1.0.2 + dev: true - is-bun-module@1.2.1: + /is-bun-module@1.2.1: + resolution: {integrity: sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==} dependencies: semver: 7.6.3 + dev: true - is-callable@1.2.7: {} + /is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + dev: true - is-core-module@2.15.1: + /is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} dependencies: hasown: 2.0.2 + dev: true - is-data-view@1.0.1: + /is-data-view@1.0.1: + resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + engines: {node: '>= 0.4'} dependencies: is-typed-array: 1.1.13 + dev: true - is-date-object@1.0.5: + /is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.2 + dev: true - is-extglob@2.1.1: {} + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true - is-finalizationregistry@1.0.2: + /is-finalizationregistry@1.0.2: + resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} dependencies: call-bind: 1.0.7 + dev: true - is-fullwidth-code-point@3.0.0: {} + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: true - is-generator-function@1.0.10: + /is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.2 + dev: true - is-glob@4.0.3: + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} dependencies: is-extglob: 2.1.1 + dev: true - is-map@2.0.3: {} + /is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + dev: true - is-negative-zero@2.0.3: {} + /is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + dev: true - is-number-object@1.0.7: + /is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.2 + dev: true - is-number@7.0.0: {} + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true - is-regex@1.1.4: + /is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 has-tostringtag: 1.0.2 + dev: true - is-set@2.0.3: {} + /is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + dev: true - is-shared-array-buffer@1.0.3: + /is-shared-array-buffer@1.0.3: + resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 + dev: true - is-string@1.0.7: + /is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.2 + dev: true - is-symbol@1.0.4: + /is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} dependencies: has-symbols: 1.0.3 + dev: true - is-typed-array@1.1.13: + /is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} dependencies: which-typed-array: 1.1.15 + dev: true - is-weakmap@2.0.2: {} + /is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + dev: true - is-weakref@1.0.2: + /is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: call-bind: 1.0.7 + dev: true - is-weakset@2.0.3: + /is-weakset@2.0.3: + resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 get-intrinsic: 1.2.4 + dev: true - isarray@2.0.5: {} + /isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + dev: true - isexe@2.0.0: {} + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true - isomorphic.js@0.2.5: {} + /isomorphic.js@0.2.5: + resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} + dev: false - iterator.prototype@1.1.2: + /iterator.prototype@1.1.2: + resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} dependencies: define-properties: 1.2.1 get-intrinsic: 1.2.4 has-symbols: 1.0.3 reflect.getprototypeof: 1.0.6 set-function-name: 2.0.2 + dev: true - jackspeak@2.3.6: + /jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} dependencies: '@isaacs/cliui': 8.0.2 optionalDependencies: '@pkgjs/parseargs': 0.11.0 + dev: true - js-tokens@4.0.0: {} + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@4.1.0: + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true dependencies: argparse: 2.0.1 + dev: true - json-buffer@3.0.1: {} + /json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: true - json-schema-traverse@0.4.1: {} + /json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + dev: true - json-stable-stringify-without-jsonify@1.0.1: {} + /json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + dev: true - json2mq@0.2.0: + /json2mq@0.2.0: + resolution: {integrity: sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==} dependencies: string-convert: 0.2.1 + dev: false - json5@1.0.2: + /json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true dependencies: minimist: 1.2.8 + dev: true - jsx-ast-utils@3.3.5: + /jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} dependencies: array-includes: 3.1.8 array.prototype.flat: 1.3.2 object.assign: 4.1.5 object.values: 1.2.0 + dev: true - keyv@4.5.4: + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} dependencies: json-buffer: 3.0.1 + dev: true - language-subtag-registry@0.3.23: {} + /language-subtag-registry@0.3.23: + resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} + dev: true - language-tags@1.0.9: + /language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} dependencies: language-subtag-registry: 0.3.23 + dev: true - levn@0.4.1: + /levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 + dev: true - lib0@0.2.98: + /lib0@0.2.98: + resolution: {integrity: sha512-XteTiNO0qEXqqweWx+b21p/fBnNHUA1NwAtJNJek1oPrewEZs2uiT4gWivHKr9GqCjDPAhchz0UQO8NwU3bBNA==} + engines: {node: '>=16'} + hasBin: true dependencies: isomorphic.js: 0.2.5 + dev: false - lodash.merge@4.6.2: {} + /lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true - loose-envify@1.4.0: + /loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true dependencies: js-tokens: 4.0.0 - lru-cache@10.4.3: {} + /lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + dev: true - merge2@1.4.1: {} + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true - micromatch@4.0.8: + /micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} dependencies: braces: 3.0.3 picomatch: 2.3.1 + dev: true - minimatch@3.1.2: + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: brace-expansion: 1.1.11 + dev: true - minimatch@9.0.5: + /minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} dependencies: brace-expansion: 2.0.1 + dev: true - minimist@1.2.8: {} + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true - minipass@7.1.2: {} + /minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + dev: true - ms@2.1.3: {} + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - nanoid@3.3.7: {} + /nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: false - natural-compare@1.4.0: {} + /natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + dev: true - next@14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2): + /next@14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2): + resolution: {integrity: sha512-BseY9YNw8QJSwLYD7hlZzl6QVDoSFHL/URN5K64kVEVpCsSOWeyjbIGK+dZUaRViHTaMQX8aqmnn0PHBbGZezg==} + engines: {node: '>=18.17.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.41.2 + react: ^18.2.0 + react-dom: ^18.2.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + sass: + optional: true dependencies: '@next/env': 14.2.13 '@swc/helpers': 0.5.5 @@ -3456,55 +2498,87 @@ snapshots: transitivePeerDependencies: - '@babel/core' - babel-plugin-macros + dev: false - object-assign@4.1.1: {} + /object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + dev: true - object-inspect@1.13.2: {} + /object-inspect@1.13.2: + resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} + engines: {node: '>= 0.4'} + dev: true - object-is@1.1.6: + /object-is@1.1.6: + resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 + dev: true - object-keys@1.1.1: {} + /object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + dev: true - object.assign@4.1.5: + /object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 has-symbols: 1.0.3 object-keys: 1.1.1 + dev: true - object.entries@1.1.8: + /object.entries@1.1.8: + resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-object-atoms: 1.0.0 + dev: true - object.fromentries@2.0.8: + /object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-object-atoms: 1.0.0 + dev: true - object.groupby@1.0.3: + /object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 + dev: true - object.values@1.2.0: + /object.values@1.2.0: + resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-object-atoms: 1.0.0 + dev: true - once@1.4.0: + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: wrappy: 1.0.2 + dev: true - optionator@0.9.4: + /optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} dependencies: deep-is: 0.1.4 fast-levenshtein: 2.0.6 @@ -3512,53 +2586,110 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 word-wrap: 1.2.5 + dev: true - parent-module@1.0.1: + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} dependencies: callsites: 3.1.0 + dev: true - path-is-absolute@1.0.1: {} + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: true - path-key@3.1.1: {} + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: true - path-parse@1.0.7: {} + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true - path-scurry@1.11.1: + /path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} dependencies: lru-cache: 10.4.3 minipass: 7.1.2 + dev: true + + /peerjs-js-binarypack@2.1.0: + resolution: {integrity: sha512-YIwCC+pTzp3Bi8jPI9UFKO0t0SLo6xALnHkiNt/iUFmUUZG0fEEmEyFKvjsDKweiFitzHRyhuh6NvyJZ4nNxMg==} + engines: {node: '>= 14.0.0'} + + /peerjs@1.5.4: + resolution: {integrity: sha512-yFsoLMnurJKlQbx6kVSBpOp+AlNldY1JQS2BrSsHLKCZnq6t7saHleuHM5svuLNbQkUJXHLF3sKOJB1K0xulOw==} + engines: {node: '>= 14'} + dependencies: + '@msgpack/msgpack': 2.8.0 + eventemitter3: 4.0.7 + peerjs-js-binarypack: 2.1.0 + webrtc-adapter: 9.0.1 - picocolors@1.1.0: {} + /picocolors@1.1.0: + resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} + dev: false - picomatch@2.3.1: {} + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true - possible-typed-array-names@1.0.0: {} + /possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + dev: true - postcss@8.4.31: + /postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} dependencies: nanoid: 3.3.7 picocolors: 1.1.0 source-map-js: 1.2.1 + dev: false - prelude-ls@1.2.1: {} + /prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + dev: true - progress@2.0.3: {} + /progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + dev: true - prop-types@15.8.1: + /prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 + dev: true - punycode@2.3.1: {} + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + dev: true - queue-microtask@1.2.3: {} + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - randombytes@2.1.0: + /randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: safe-buffer: 5.2.1 + dev: false - rc-cascader@3.28.1(react-dom@18.2.0)(react@18.2.0): + /rc-cascader@3.28.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-9+8oHIMWVLHxuaapDiqFNmD9KSyKN/P4bo9x/MBuDbyTqP8f2/POmmZxdXWBO3yq/uE3pKyQCXYNUxrNfHRv2A==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 array-tree-filter: 2.1.0 @@ -3568,16 +2699,26 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-checkbox@3.3.0(react-dom@18.2.0)(react@18.2.0): + /rc-checkbox@3.3.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Ih3ZaAcoAiFKJjifzwsGiT/f/quIkxJoklW4yKGho14Olulwn8gN7hOBve0/WGDg5o/l/5mL0w7ff7/YGvefVw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-collapse@3.7.3(react-dom@18.2.0)(react@18.2.0): + /rc-collapse@3.7.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-60FJcdTRn0X5sELF18TANwtVi7FtModq649H11mYF1jh83DniMoM4MqY627sEKRCTm4+WXfGDcB7hY5oW6xhyw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -3585,8 +2726,13 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-dialog@9.5.2(react-dom@18.2.0)(react@18.2.0): + /rc-dialog@9.5.2(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-qVUjc8JukG+j/pNaHVSRa2GO2/KbV2thm7yO4hepQ902eGdYK913sGkwg/fh9yhKYV1ql3BKIN2xnud3rEXAPw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) @@ -3595,8 +2741,13 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-drawer@7.2.0(react-dom@18.2.0)(react@18.2.0): + /rc-drawer@7.2.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-9lOQ7kBekEJRdEpScHvtmEtXnAsy+NGDXiRWc2ZVC7QXAazNVbeT4EraQKYwCME8BJLa8Bxqxvs5swwyOepRwg==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) @@ -3605,8 +2756,13 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-dropdown@4.2.0(react-dom@18.2.0)(react@18.2.0): + /rc-dropdown@4.2.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-odM8Ove+gSh0zU27DUj5cG1gNKg7mLWBYzB5E4nNLrLwBmYEgYP43vHKDGOVZcJSVElQBI0+jTQgjnq0NfLjng==} + peerDependencies: + react: '>=16.11.0' + react-dom: '>=16.11.0' dependencies: '@babel/runtime': 7.25.7 '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) @@ -3614,16 +2770,27 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-field-form@2.4.0(react-dom@18.2.0)(react@18.2.0): + /rc-field-form@2.4.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-XZ/lF9iqf9HXApIHQHqzJK5v2w4mkUMsVqAzOyWVzoiwwXEavY6Tpuw7HavgzIoD+huVff4JghSGcgEfX6eycg==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 '@rc-component/async-validator': 5.0.4 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-image@7.9.0(react-dom@18.2.0)(react@18.2.0): + /rc-image@7.9.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-l4zqO5E0quuLMCtdKfBgj4Suv8tIS011F5k1zBBlK25iMjjiNHxA0VeTzGFtUZERSA45gvpXDg8/P6qNLjR25g==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) @@ -3633,8 +2800,13 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-input-number@9.2.0(react-dom@18.2.0)(react@18.2.0): + /rc-input-number@9.2.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-5XZFhBCV5f9UQ62AZ2hFbEY8iZT/dm23Q1kAg0H8EvOgD3UDbYYJAayoVIkM3lQaCqYAW5gV0yV3vjw1XtzWHg==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 '@rc-component/mini-decimal': 1.1.0 @@ -3643,16 +2815,26 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-input@1.6.3(react-dom@18.2.0)(react@18.2.0): + /rc-input@1.6.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-wI4NzuqBS8vvKr8cljsvnTUqItMfG1QbJoxovCgL+DX4eVUcHIjVwharwevIxyy7H/jbLryh+K7ysnJr23aWIA==} + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-mentions@2.15.0(react-dom@18.2.0)(react@18.2.0): + /rc-mentions@2.15.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-f5v5i7VdqvBDXbphoqcQWmXDif2Msd2arritVoWybrVDuHE6nQ7XCYsybHbV//WylooK52BFDouFvyaRDtXZEw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) @@ -3663,8 +2845,13 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-menu@9.14.1(react-dom@18.2.0)(react@18.2.0): + /rc-menu@9.14.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-5wlRb3M8S4yGlWhSoEYJ7ZVRElyScdcpUHxgiLxkeig1tEdyKrnED3B2fhpN0Rrpdp9jyhnmZR/Lwq2fH5VvDQ==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) @@ -3674,16 +2861,27 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-motion@2.9.3(react-dom@18.2.0)(react@18.2.0): + /rc-motion@2.9.3(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-rkW47ABVkic7WEB0EKJqzySpvDqwl60/tdkY7hWP7dYnh5pm0SzJpo54oW3TDUGXV5wfxXFmMkxrzRRbotQ0+w==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-notification@5.6.2(react-dom@18.2.0)(react@18.2.0): + /rc-notification@5.6.2(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Id4IYMoii3zzrG0lB0gD6dPgJx4Iu95Xu0BQrhHIbp7ZnAZbLqdqQ73aIWH0d0UFcElxwaKjnzNovTjo7kXz7g==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -3691,8 +2889,13 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-overflow@1.3.2(react-dom@18.2.0)(react@18.2.0): + /rc-overflow@1.3.2(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-nsUm78jkYAoPygDAcGZeC2VwIg/IBGSodtOY3pMof4W3M9qRJgqaDYm03ZayHlde3I6ipliAxbN0RUcGf5KOzw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -3700,16 +2903,40 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-pagination@4.2.0(react-dom@18.2.0)(react@18.2.0): + /rc-pagination@4.2.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-V6qeANJsT6tmOcZ4XiUmj8JXjRLbkusuufpuoBw2GiAn94fIixYjFLmbruD1Sbhn8fPLDnWawPp4CN37zQorvw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-picker@4.6.15(dayjs@1.11.13)(react-dom@18.2.0)(react@18.2.0): + /rc-picker@4.6.15(dayjs@1.11.13)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-OWZ1yrMie+KN2uEUfYCfS4b2Vu6RC1FWwNI0s+qypsc3wRt7g+peuZKVIzXCTaJwyyZruo80+akPg2+GmyiJjw==} + engines: {node: '>=8.x'} + peerDependencies: + date-fns: '>= 2.x' + dayjs: '>= 1.x' + luxon: '>= 3.x' + moment: '>= 2.x' + react: '>=16.9.0' + react-dom: '>=16.9.0' + peerDependenciesMeta: + date-fns: + optional: true + dayjs: + optional: true + luxon: + optional: true + moment: + optional: true dependencies: '@babel/runtime': 7.25.7 '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) @@ -3720,24 +2947,40 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-progress@4.0.0(react-dom@18.2.0)(react@18.2.0): + /rc-progress@4.0.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-oofVMMafOCokIUIBnZLNcOZFsABaUw8PPrf1/y0ZBvKZNpOiu5h4AO9vv11Sw0p4Hb3D0yGWuEattcQGtNJ/aw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-rate@2.13.0(react-dom@18.2.0)(react@18.2.0): + /rc-rate@2.13.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-oxvx1Q5k5wD30sjN5tqAyWTvJfLNNJn7Oq3IeS4HxWfAiC4BOXMITNAsw7u/fzdtO4MS8Ki8uRLOzcnEuoQiAw==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-resize-observer@1.4.0(react-dom@18.2.0)(react@18.2.0): + /rc-resize-observer@1.4.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-PnMVyRid9JLxFavTjeDXEXo65HCRqbmLBw9xX9gfC4BZiSzbLXKzW3jPz+J0P71pLbD5tBMTT+mkstV5gD0c9Q==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -3745,8 +2988,13 @@ snapshots: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) resize-observer-polyfill: 1.5.1 + dev: false - rc-segmented@2.3.0(react-dom@18.2.0)(react@18.2.0): + /rc-segmented@2.3.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-I3FtM5Smua/ESXutFfb8gJ8ZPcvFR+qUgeeGFQHBOvRiRKyAk4aBE5nfqrxXx+h8/vn60DQjOt6i4RNtrbOobg==} + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -3754,8 +3002,14 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-select@14.15.2(react-dom@18.2.0)(react@18.2.0): + /rc-select@14.15.2(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-oNoXlaFmpqXYcQDzcPVLrEqS2J9c+/+oJuGrlXeVVX/gVgrbHa5YcyiRUXRydFjyuA7GP3elRuLF7Y3Tfwltlw==} + engines: {node: '>=8.x'} + peerDependencies: + react: '*' + react-dom: '*' dependencies: '@babel/runtime': 7.25.7 '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) @@ -3766,32 +3020,55 @@ snapshots: rc-virtual-list: 3.14.8(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-slider@11.1.6(react-dom@18.2.0)(react@18.2.0): + /rc-slider@11.1.6(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-LACAaXM0hi+4x4ErDGZLy7weIQwmBIVbIgPE+eDHiHkyzMvKjWHraCG8/B22Y/tCQUPAsP02wBhKhth7mH2PIw==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-steps@6.0.1(react-dom@18.2.0)(react@18.2.0): + /rc-steps@6.0.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-lKHL+Sny0SeHkQKKDJlAjV5oZ8DwCdS2hFhAkIjuQt1/pB81M0cA0ErVFdHq9+jmPmFw1vJB2F5NBzFXLJxV+g==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-switch@4.1.0(react-dom@18.2.0)(react@18.2.0): + /rc-switch@4.1.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-TI8ufP2Az9oEbvyCeVE4+90PDSljGyuwix3fV58p7HV2o4wBnVToEyomJRVyTaZeqNPAp+vqeo4Wnj5u0ZZQBg==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-table@7.45.7(react-dom@18.2.0)(react@18.2.0): + /rc-table@7.45.7(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-wi9LetBL1t1csxyGkMB2p3mCiMt+NDexMlPbXHvQFmBBAsMxrgNSAPwUci2zDLUq9m8QdWc1Nh8suvrpy9mXrg==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 '@rc-component/context': 1.4.0(react-dom@18.2.0)(react@18.2.0) @@ -3801,8 +3078,14 @@ snapshots: rc-virtual-list: 3.14.8(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-tabs@15.1.1(react-dom@18.2.0)(react@18.2.0): + /rc-tabs@15.1.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Tc7bJvpEdkWIVCUL7yQrMNBJY3j44NcyWS48jF/UKMXuUlzaXK+Z/pEL5LjGcTadtPvVmNqA40yv7hmr+tCOAw==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -3813,8 +3096,13 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-textarea@1.8.2(react-dom@18.2.0)(react@18.2.0): + /rc-textarea@1.8.2(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-UFAezAqltyR00a8Lf0IPAyTd29Jj9ee8wt8DqXyDMal7r/Cg/nDt3e1OOv3Th4W6mKaZijjgwuPXhAfVNTN8sw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -3823,16 +3111,26 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-tooltip@6.2.1(react-dom@18.2.0)(react@18.2.0): + /rc-tooltip@6.2.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-rws0duD/3sHHsD905Nex7FvoUGy2UBQRhTkKxeEvr2FB+r21HsOxcDJI0TzyO8NHhnAA8ILr8pfbSBg5Jj5KBg==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) classnames: 2.5.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-tree-select@5.23.0(react-dom@18.2.0)(react@18.2.0): + /rc-tree-select@5.23.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-aQGi2tFSRw1WbXv0UVXPzHm09E0cSvUVZMLxQtMv3rnZZpNmdRXWrnd9QkLNlVH31F+X5rgghmdSFF3yZW0N9A==} + peerDependencies: + react: '*' + react-dom: '*' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -3841,8 +3139,14 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-tree@5.9.0(react-dom@18.2.0)(react@18.2.0): + /rc-tree@5.9.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-CPrgOvm9d/9E+izTONKSngNzQdIEjMox2PBufWjS1wf7vxtvmCWzK1SlpHbRY6IaBfJIeZ+88RkcIevf729cRg==} + engines: {node: '>=10.x'} + peerDependencies: + react: '*' + react-dom: '*' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -3851,23 +3155,39 @@ snapshots: rc-virtual-list: 3.14.8(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-upload@4.7.0(react-dom@18.2.0)(react@18.2.0): + /rc-upload@4.7.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-eUwxYNHlsYe5vYhKFAUGrQG95JrnPzY+BmPi1Daq39fWNl/eOc7v4UODuWrVp2LFkQBuV3cMCG/I68iub6oBrg==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - rc-util@5.43.0(react-dom@18.2.0)(react@18.2.0): + /rc-util@5.43.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-AzC7KKOXFqAdIBqdGWepL9Xn7cm3vnAmjlHqUnoQaTMZYhM4VlXGLkkHHxj/BZ7Td0+SOPKB4RGPboBVKT9htw==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-is: 18.3.1 + dev: false - rc-virtual-list@3.14.8(react-dom@18.2.0)(react@18.2.0): + /rc-virtual-list@3.14.8(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-8D0KfzpRYi6YZvlOWIxiOm9BGt4Wf2hQyEaM6RXlDDiY2NhLheuYI+RA+7ZaZj1lq+XQqy3KHlaeeXQfzI5fGg==} + engines: {node: '>=8.x'} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 @@ -3875,36 +3195,62 @@ snapshots: rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + dev: false - react-dom@18.2.0(react@18.2.0): + /react-dom@18.2.0(react@18.2.0): + resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} + peerDependencies: + react: ^18.2.0 dependencies: loose-envify: 1.4.0 react: 18.2.0 scheduler: 0.23.2 + dev: false - react-is@16.13.1: {} + /react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + dev: true - react-is@18.3.1: {} + /react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + dev: false - react-timer-hook@3.0.7(react@18.2.0): + /react-timer-hook@3.0.7(react@18.2.0): + resolution: {integrity: sha512-ATpNcU+PQRxxfNBPVqce2+REtjGAlwmfoNQfcEBMZFxPj0r3GYdKhyPHdStvqrejejEi0QvqaJZjy2lBlFvAsA==} + peerDependencies: + react: '>=16.8.0' dependencies: react: 18.2.0 + dev: false - react-use-websocket@4.9.0: {} + /react-use-websocket@4.9.0: + resolution: {integrity: sha512-/6OaCMggQCTnryCAsw/N+/wfH7bBfIXk5WXTMPdyf0x9HWJXLGUVttAT5hqAimRytD1dkHEJCUrFHAGzOAg1eg==} + dev: false - react@18.2.0: + /react@18.2.0: + resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} + engines: {node: '>=0.10.0'} dependencies: loose-envify: 1.4.0 + dev: false - readable-stream@3.6.2: + /readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} dependencies: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 + dev: false - readdirp@4.0.1: {} + /readdirp@4.0.1: + resolution: {integrity: sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw==} + engines: {node: '>= 14.16.0'} + dev: false - reflect.getprototypeof@1.0.6: + /reflect.getprototypeof@1.0.6: + resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 @@ -3913,80 +3259,139 @@ snapshots: get-intrinsic: 1.2.4 globalthis: 1.0.4 which-builtin-type: 1.1.4 + dev: true - regenerator-runtime@0.14.1: {} + /regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + dev: false - regexp.prototype.flags@1.5.3: + /regexp.prototype.flags@1.5.3: + resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-errors: 1.3.0 set-function-name: 2.0.2 + dev: true - regexpp@3.2.0: {} + /regexpp@3.2.0: + resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} + engines: {node: '>=8'} + dev: true - resize-observer-polyfill@1.5.1: {} + /resize-observer-polyfill@1.5.1: + resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==} + dev: false - resolve-from@4.0.0: {} + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true - resolve-pkg-maps@1.0.0: {} + /resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + dev: true - resolve@1.22.8: + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true dependencies: is-core-module: 2.15.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + dev: true - resolve@2.0.0-next.5: + /resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true dependencies: is-core-module: 2.15.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + dev: true - reusify@1.0.4: {} + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true - rimraf@3.0.2: + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true dependencies: glob: 7.2.3 + dev: true - run-parallel@1.2.0: + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: queue-microtask: 1.2.3 + dev: true - safe-array-concat@1.1.2: + /safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} + engines: {node: '>=0.4'} dependencies: call-bind: 1.0.7 get-intrinsic: 1.2.4 has-symbols: 1.0.3 isarray: 2.0.5 + dev: true - safe-buffer@5.2.1: {} + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: false - safe-regex-test@1.0.3: + /safe-regex-test@1.0.3: + resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-regex: 1.1.4 + dev: true - sass@1.79.2: + /sass@1.79.2: + resolution: {integrity: sha512-YmT1aoF1MwHsZEu/eXhbAJNsPGAhNP4UixW9ckEwWCvPcVdVF0/C104OGDVEqtoctKq0N+wM20O/rj+sSPsWeg==} + engines: {node: '>=14.0.0'} + hasBin: true dependencies: chokidar: 4.0.1 immutable: 4.3.7 source-map-js: 1.2.1 + dev: false - scheduler@0.23.2: + /scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} dependencies: loose-envify: 1.4.0 + dev: false - scroll-into-view-if-needed@3.1.0: + /scroll-into-view-if-needed@3.1.0: + resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==} dependencies: compute-scroll-into-view: 3.1.0 + dev: false + + /sdp@3.2.0: + resolution: {integrity: sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw==} - semver@6.3.1: {} + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + dev: true - semver@7.6.3: {} + /semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + dev: true - set-function-length@1.2.2: + /set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} dependencies: define-data-property: 1.1.4 es-errors: 1.3.0 @@ -3994,30 +3399,47 @@ snapshots: get-intrinsic: 1.2.4 gopd: 1.0.1 has-property-descriptors: 1.0.2 + dev: true - set-function-name@2.0.2: + /set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} dependencies: define-data-property: 1.1.4 es-errors: 1.3.0 functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 + dev: true - shebang-command@2.0.0: + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} dependencies: shebang-regex: 3.0.0 + dev: true - shebang-regex@3.0.0: {} + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: true - side-channel@1.0.6: + /side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 es-errors: 1.3.0 get-intrinsic: 1.2.4 object-inspect: 1.13.2 + dev: true - signal-exit@4.1.0: {} + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: true - simple-peer@9.11.1: + /simple-peer@9.11.1: + resolution: {integrity: sha512-D1SaWpOW8afq1CZGWB8xTfrT3FekjQmPValrqncJMX7QFl8YwhrPTZvMCANLtgBwwdS+7zURyqxDDEmY558tTw==} dependencies: buffer: 6.0.3 debug: 4.3.7 @@ -4028,35 +3450,57 @@ snapshots: readable-stream: 3.6.2 transitivePeerDependencies: - supports-color + dev: false - source-map-js@1.2.1: {} + /source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + dev: false - stop-iteration-iterator@1.0.0: + /stop-iteration-iterator@1.0.0: + resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} + engines: {node: '>= 0.4'} dependencies: internal-slot: 1.0.7 + dev: true - streamsearch@1.1.0: {} + /streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + dev: false - string-convert@0.2.1: {} + /string-convert@0.2.1: + resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==} + dev: false - string-width@4.2.3: + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + dev: true - string-width@5.1.2: + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} dependencies: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 strip-ansi: 7.1.0 + dev: true - string.prototype.includes@2.0.0: + /string.prototype.includes@2.0.0: + resolution: {integrity: sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==} dependencies: define-properties: 1.2.1 es-abstract: 1.23.3 + dev: true - string.prototype.matchall@4.0.11: + /string.prototype.matchall@4.0.11: + resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 @@ -4070,108 +3514,191 @@ snapshots: regexp.prototype.flags: 1.5.3 set-function-name: 2.0.2 side-channel: 1.0.6 + dev: true - string.prototype.repeat@1.0.0: + /string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} dependencies: define-properties: 1.2.1 es-abstract: 1.23.3 + dev: true - string.prototype.trim@1.2.9: + /string.prototype.trim@1.2.9: + resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 es-object-atoms: 1.0.0 + dev: true - string.prototype.trimend@1.0.8: + /string.prototype.trimend@1.0.8: + resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-object-atoms: 1.0.0 + dev: true - string.prototype.trimstart@1.0.8: + /string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-object-atoms: 1.0.0 + dev: true - string_decoder@1.3.0: + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} dependencies: safe-buffer: 5.2.1 + dev: false - strip-ansi@6.0.1: + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} dependencies: ansi-regex: 5.0.1 + dev: true - strip-ansi@7.1.0: + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} dependencies: ansi-regex: 6.1.0 + dev: true - strip-bom@3.0.0: {} + /strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + dev: true - strip-json-comments@3.1.1: {} + /strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + dev: true - style-mod@4.1.2: {} + /style-mod@4.1.2: + resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} + dev: false - styled-jsx@5.1.1(react@18.2.0): + /styled-jsx@5.1.1(react@18.2.0): + resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true dependencies: client-only: 0.0.1 react: 18.2.0 + dev: false - stylis@4.3.4: {} + /stylis@4.3.4: + resolution: {integrity: sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==} + dev: false - supports-color@7.2.0: + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} dependencies: has-flag: 4.0.0 + dev: true - supports-preserve-symlinks-flag@1.0.0: {} + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: true - tapable@2.2.1: {} + /tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + dev: true - text-table@0.2.0: {} + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + dev: true - throttle-debounce@5.0.2: {} + /throttle-debounce@5.0.2: + resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} + engines: {node: '>=12.22'} + dev: false - to-regex-range@5.0.1: + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} dependencies: is-number: 7.0.0 + dev: true - toggle-selection@1.0.6: {} + /toggle-selection@1.0.6: + resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} + dev: false - ts-api-utils@1.3.0(typescript@5.0.2): + /ts-api-utils@1.3.0(typescript@5.0.2): + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' dependencies: typescript: 5.0.2 + dev: true - tsconfig-paths@3.15.0: + /tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} dependencies: '@types/json5': 0.0.29 json5: 1.0.2 minimist: 1.2.8 strip-bom: 3.0.0 + dev: true - tslib@2.7.0: {} + /tslib@2.7.0: + resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + dev: false - type-check@0.4.0: + /type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} dependencies: prelude-ls: 1.2.1 + dev: true - type-fest@0.20.2: {} + /type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + dev: true - typed-array-buffer@1.0.2: + /typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-typed-array: 1.1.13 + dev: true - typed-array-byte-length@1.0.1: + /typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 for-each: 0.3.3 gopd: 1.0.1 has-proto: 1.0.3 is-typed-array: 1.1.13 + dev: true - typed-array-byte-offset@1.0.2: + /typed-array-byte-offset@1.0.2: + resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + engines: {node: '>= 0.4'} dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.7 @@ -4179,8 +3706,11 @@ snapshots: gopd: 1.0.1 has-proto: 1.0.3 is-typed-array: 1.1.13 + dev: true - typed-array-length@1.0.6: + /typed-array-length@1.0.6: + resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 for-each: 0.3.3 @@ -4188,37 +3718,64 @@ snapshots: has-proto: 1.0.3 is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 + dev: true - typeface-montserrat@1.1.13: {} + /typeface-montserrat@1.1.13: + resolution: {integrity: sha512-Pklkyj0e+K+6I/t0M6JBDBphpfJkF1k+3qd8qDnp9aVtCC7oGBQWTAcL6+5eArfGe7h73uPwyal73hEkf9YCUA==} + dev: false - typescript@5.0.2: {} + /typescript@5.0.2: + resolution: {integrity: sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==} + engines: {node: '>=12.20'} + hasBin: true + dev: true - unbox-primitive@1.0.2: + /unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} dependencies: call-bind: 1.0.7 has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 + dev: true - uri-js@4.4.1: + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: punycode: 2.3.1 + dev: true - util-deprecate@1.0.2: {} + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: false + + /v8-compile-cache@2.4.0: + resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==} + dev: true - v8-compile-cache@2.4.0: {} + /w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + dev: false - w3c-keyname@2.2.8: {} + /webrtc-adapter@9.0.1: + resolution: {integrity: sha512-1AQO+d4ElfVSXyzNVTOewgGT/tAomwwztX/6e3totvyyzXPvXIIuUUjAmyZGbKBKbZOXauuJooZm3g6IuFuiNQ==} + engines: {node: '>=6.0.0', npm: '>=3.10.0'} + dependencies: + sdp: 3.2.0 - which-boxed-primitive@1.0.2: + /which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} dependencies: is-bigint: 1.0.4 is-boolean-object: 1.1.2 is-number-object: 1.0.7 is-string: 1.0.7 is-symbol: 1.0.4 + dev: true - which-builtin-type@1.1.4: + /which-builtin-type@1.1.4: + resolution: {integrity: sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==} + engines: {node: '>= 0.4'} dependencies: function.prototype.name: 1.1.6 has-tostringtag: 1.0.2 @@ -4232,58 +3789,108 @@ snapshots: which-boxed-primitive: 1.0.2 which-collection: 1.0.2 which-typed-array: 1.1.15 + dev: true - which-collection@1.0.2: + /which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} dependencies: is-map: 2.0.3 is-set: 2.0.3 is-weakmap: 2.0.2 is-weakset: 2.0.3 + dev: true - which-typed-array@1.1.15: + /which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.7 for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.2 + dev: true - which@2.0.2: + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true dependencies: isexe: 2.0.0 + dev: true - word-wrap@1.2.5: {} + /word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + dev: true - wrap-ansi@7.0.0: + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 + dev: true - wrap-ansi@8.1.0: + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} dependencies: ansi-styles: 6.2.1 string-width: 5.1.2 strip-ansi: 7.1.0 + dev: true - wrappy@1.0.2: {} + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: true - ws@8.18.0: + /ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + requiresBuild: true + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false optional: true - y-codemirror.next@0.3.5(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(yjs@13.6.20): + /y-codemirror.next@0.3.5(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(yjs@13.6.20): + resolution: {integrity: sha512-VluNu3e5HfEXybnypnsGwKAj+fKLd4iAnR7JuX1Sfyydmn1jCBS5wwEL/uS04Ch2ib0DnMAOF6ZRR/8kK3wyGw==} + peerDependencies: + '@codemirror/state': ^6.0.0 + '@codemirror/view': ^6.0.0 + yjs: ^13.5.6 dependencies: '@codemirror/state': 6.4.1 '@codemirror/view': 6.34.1 lib0: 0.2.98 yjs: 13.6.20 + dev: false - y-protocols@1.0.6(yjs@13.6.20): + /y-protocols@1.0.6(yjs@13.6.20): + resolution: {integrity: sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} + peerDependencies: + yjs: ^13.0.0 dependencies: lib0: 0.2.98 yjs: 13.6.20 + dev: false - y-webrtc@10.3.0(yjs@13.6.20): + /y-webrtc@10.3.0(yjs@13.6.20): + resolution: {integrity: sha512-KalJr7dCgUgyVFxoG3CQYbpS0O2qybegD0vI4bYnYHI0MOwoVbucED3RZ5f2o1a5HZb1qEssUKS0H/Upc6p1lA==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + yjs: ^13.6.8 dependencies: lib0: 0.2.98 simple-peer: 9.11.1 @@ -4295,7 +3902,11 @@ snapshots: - bufferutil - supports-color - utf-8-validate + dev: false - yjs@13.6.20: + /yjs@13.6.20: + resolution: {integrity: sha512-Z2YZI+SYqK7XdWlloI3lhMiKnCdFCVC4PchpdO+mCYwtiTwncjUbnRK9R1JmkNfdmHyDXuWN3ibJAt0wsqTbLQ==} + engines: {node: '>=16.0.0', npm: '>=8.0.0'} dependencies: lib0: 0.2.98 + dev: false diff --git a/apps/frontend/src/app/collaboration/[id]/page.tsx b/apps/frontend/src/app/collaboration/[id]/page.tsx index 41c56023f0..ad0f106e30 100644 --- a/apps/frontend/src/app/collaboration/[id]/page.tsx +++ b/apps/frontend/src/app/collaboration/[id]/page.tsx @@ -35,6 +35,7 @@ import CollaborativeEditor, { import { CreateOrUpdateHistory } from "@/app/services/history"; import { Language } from "@codemirror/language"; import { WebrtcProvider } from "y-webrtc"; +import VideoPanel from "@/components/VideoPanel/VideoPanel"; interface CollaborationProps {} @@ -459,7 +460,7 @@ export default function CollaborationPage(props: CollaborationProps) { Chat
- +
Matched with {matchedUser} From 0e5ee2e642cd8d5fa152ad6454ea6b120685e92a Mon Sep 17 00:00:00 2001 From: bensohh Date: Sun, 3 Nov 2024 11:04:25 +0800 Subject: [PATCH 117/258] Swap chat template to video panel and edit styling --- .../src/app/collaboration/[id]/page.tsx | 10 +- .../src/app/collaboration/[id]/styles.scss | 4 +- .../src/components/VideoPanel/VideoPanel.tsx | 112 +++++++++++++++--- .../src/components/VideoPanel/styles.scss | 12 ++ 4 files changed, 116 insertions(+), 22 deletions(-) diff --git a/apps/frontend/src/app/collaboration/[id]/page.tsx b/apps/frontend/src/app/collaboration/[id]/page.tsx index ad0f106e30..6cc817a58e 100644 --- a/apps/frontend/src/app/collaboration/[id]/page.tsx +++ b/apps/frontend/src/app/collaboration/[id]/page.tsx @@ -27,6 +27,7 @@ import { MessageOutlined, PlayCircleOutlined, SendOutlined, + VideoCameraOutlined, } from "@ant-design/icons"; import { ProgrammingLanguageOptions } from "@/utils/SelectOptions"; import CollaborativeEditor, { @@ -457,15 +458,14 @@ export default function CollaborationPage(props: CollaborationProps) {
- - Chat + + Video
-
+ {/*
Matched with {matchedUser}
- {/* TODO: Map and input the history of messages sent here */}
@@ -474,7 +474,7 @@ export default function CollaborationPage(props: CollaborationProps) { placeholder="Send Message Here" rows={4} /> -
+
*/}
diff --git a/apps/frontend/src/app/collaboration/[id]/styles.scss b/apps/frontend/src/app/collaboration/[id]/styles.scss index 4f7b068e42..764002f9e1 100644 --- a/apps/frontend/src/app/collaboration/[id]/styles.scss +++ b/apps/frontend/src/app/collaboration/[id]/styles.scss @@ -37,12 +37,12 @@ } .session-row { - height: 20%; + height: 18%; padding: 1rem 0.25rem 0.25rem; } .chat-row { - height: 80%; + height: 82%; padding: 0.25rem; } diff --git a/apps/frontend/src/components/VideoPanel/VideoPanel.tsx b/apps/frontend/src/components/VideoPanel/VideoPanel.tsx index b8cc3983eb..83b6071cc8 100644 --- a/apps/frontend/src/components/VideoPanel/VideoPanel.tsx +++ b/apps/frontend/src/components/VideoPanel/VideoPanel.tsx @@ -4,6 +4,8 @@ import "./styles.scss"; import { Button } from "antd"; import { ApiOutlined, + AudioMutedOutlined, + AudioOutlined, PhoneOutlined, VideoCameraOutlined, } from "@ant-design/icons"; @@ -23,6 +25,7 @@ const VideoPanel = () => { ); const [userStream, setUserStream] = useState(null); const [videoOn, setVideoOn] = useState(true); + const [muteOn, setMuteOn] = useState(false); const handleCall = () => { navigator.mediaDevices @@ -52,6 +55,17 @@ const VideoPanel = () => { if (sender) { sender.replaceTrack(videoTrack); // Replace the video track in the call } + + const audioTrack = userStream.getAudioTracks()[0]; + + const sender2 = call.peerConnection.getSenders().find((s) => { + if (s.track) { + return s.track.kind === "audio"; + } + }); + if (sender2) { + sender2.replaceTrack(audioTrack); // Replace the video track in the call + } } } } @@ -104,7 +118,6 @@ const VideoPanel = () => { const toggleVideo = () => { if (userStream) { - console.log(userStream.getVideoTracks()); const videoTrack = userStream.getVideoTracks()[0]; if (videoTrack) { @@ -134,33 +147,102 @@ const VideoPanel = () => { } }; + const toggleMute = () => { + if (userStream) { + console.log(userStream.getAudioTracks()); + const audioTrack = userStream.getAudioTracks()[0]; + + if (audioTrack) { + if (muteOn) { + // Unmute the audio track + audioTrack.enabled = true; + setMuteOn(false); + } else { + // Mute the audio track + audioTrack.enabled = false; + setMuteOn(true); + + if (callInstance) { + const sender = callInstance.peerConnection + .getSenders() + .find((s) => { + if (s.track) { + return s.track.kind === "audio"; + } + }); + if (sender) { + sender.replaceTrack(audioTrack); // Replace the video track in the call + } + } + } + } + } + }; + return (
-

Video Feed for: {currentUsername}

+ {/*

Video Feed for: {currentUsername}

*/}
+ {/*

Video Feed for: {matchedUsername}

*/}
); diff --git a/apps/frontend/src/components/VideoPanel/styles.scss b/apps/frontend/src/components/VideoPanel/styles.scss index 2ffe99394a..058f1bc387 100644 --- a/apps/frontend/src/components/VideoPanel/styles.scss +++ b/apps/frontend/src/components/VideoPanel/styles.scss @@ -6,8 +6,20 @@ .user-video, .matched-user-video { width: 100%; + margin: 4px 0px 0px; } .header-tag { font-weight: bold; } + +.buttons-container { + margin-top: 1px; + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.icon-padding { + padding-top: 2px; +} From a3e02a2c094a75c613b1310a1be7e786120d0915 Mon Sep 17 00:00:00 2001 From: bensohh Date: Sun, 3 Nov 2024 11:04:58 +0800 Subject: [PATCH 118/258] Add some minor comments --- apps/signalling-service/server.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/signalling-service/server.js b/apps/signalling-service/server.js index 88612444e2..97105ff9c5 100644 --- a/apps/signalling-service/server.js +++ b/apps/signalling-service/server.js @@ -14,6 +14,7 @@ const pingTimeout = 30000; const port = process.env.PORT || 4444; const wss = new WebSocketServer({ noServer: true }); +// Initialise the signalling server for collaboration editor const server = http.createServer((request, response) => { response.writeHead(200, { "Content-Type": "text/plain", @@ -107,6 +108,7 @@ const onconnection = (conn) => { break; case "ping": send(conn, { type: "pong" }); + break; } } }); From 81b48c9b12af75b784a9035140d5a4daca7ced81 Mon Sep 17 00:00:00 2001 From: bensohh Date: Sun, 3 Nov 2024 11:05:21 +0800 Subject: [PATCH 119/258] Update dependencies --- apps/signalling-service/pnpm-lock.yaml | 40 +++++++++++--------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/apps/signalling-service/pnpm-lock.yaml b/apps/signalling-service/pnpm-lock.yaml index 04ce15c614..cd6e4916a0 100644 --- a/apps/signalling-service/pnpm-lock.yaml +++ b/apps/signalling-service/pnpm-lock.yaml @@ -1,31 +1,32 @@ -lockfileVersion: '9.0' +lockfileVersion: '6.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -importers: - - .: - dependencies: - lib0: - specifier: ^0.2.98 - version: 0.2.98 - ws: - specifier: ^8.18.0 - version: 8.18.0 +dependencies: + lib0: + specifier: ^0.2.98 + version: 0.2.98 + ws: + specifier: ^8.18.0 + version: 8.18.0 packages: - isomorphic.js@0.2.5: + /isomorphic.js@0.2.5: resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} + dev: false - lib0@0.2.98: + /lib0@0.2.98: resolution: {integrity: sha512-XteTiNO0qEXqqweWx+b21p/fBnNHUA1NwAtJNJek1oPrewEZs2uiT4gWivHKr9GqCjDPAhchz0UQO8NwU3bBNA==} engines: {node: '>=16'} hasBin: true + dependencies: + isomorphic.js: 0.2.5 + dev: false - ws@8.18.0: + /ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} peerDependencies: @@ -36,13 +37,4 @@ packages: optional: true utf-8-validate: optional: true - -snapshots: - - isomorphic.js@0.2.5: {} - - lib0@0.2.98: - dependencies: - isomorphic.js: 0.2.5 - - ws@8.18.0: {} + dev: false From 8b7fa39377d99703dc342fa0718578c9b2ceb517 Mon Sep 17 00:00:00 2001 From: bensohh Date: Sun, 3 Nov 2024 13:55:42 +0800 Subject: [PATCH 120/258] Implement end session due to inactivity that triggers after 15s --- .../CollaborativeEditor.tsx | 23 +++++++++++++++++++ .../src/components/VideoPanel/VideoPanel.tsx | 1 - 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx index 857e149be1..6d1f8b4d7c 100644 --- a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx +++ b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx @@ -179,6 +179,8 @@ const CollaborativeEditor = forwardRef( }, })); + let sessionEndTimeout: any; + useEffect(() => { if (process.env.NEXT_PUBLIC_SIGNALLING_SERVICE_URL === undefined) { error("Missing Signalling Service Url"); @@ -213,6 +215,27 @@ const CollaborativeEditor = forwardRef( // Listen for awareness changes provider.awareness.on("change", () => { const updatedStates = provider.awareness.getStates(); + + // Check the length of updatedStates, if it is equal to 1, we trigger endsession in 15s but if updated to 2, cancel endsession + if (sessionEndTimeout && updatedStates.size == 2) { + clearTimeout(sessionEndTimeout); + sessionEndTimeout = null; + } + + // If there's only one participant, set a timeout for 15 seconds + if (updatedStates.size === 1) { + sessionEndTimeout = setTimeout(() => { + // Trigger end session logic here + info( + `Session has ended due to inactivity from matched user ${props.matchedUser}` + ); + props.handleCloseCollaboration("peer"); + if (props.providerRef.current) { + props.providerRef.current.disconnect(); + } + }, 15000); // 15 seconds + } + for (const [clientID, state] of Array.from(updatedStates)) { if (state.sessionEnded && state.user.name !== props.user) { if (!sessionEndNotified) { diff --git a/apps/frontend/src/components/VideoPanel/VideoPanel.tsx b/apps/frontend/src/components/VideoPanel/VideoPanel.tsx index 83b6071cc8..ee3ece7c33 100644 --- a/apps/frontend/src/components/VideoPanel/VideoPanel.tsx +++ b/apps/frontend/src/components/VideoPanel/VideoPanel.tsx @@ -149,7 +149,6 @@ const VideoPanel = () => { const toggleMute = () => { if (userStream) { - console.log(userStream.getAudioTracks()); const audioTrack = userStream.getAudioTracks()[0]; if (audioTrack) { From 3528c9d8759427a6cc7a5a46760d983246e923ae Mon Sep 17 00:00:00 2001 From: bensohh Date: Sun, 3 Nov 2024 14:02:29 +0800 Subject: [PATCH 121/258] Clear timeout when user end before auto trigger --- .../components/CollaborativeEditor/CollaborativeEditor.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx index 6d1f8b4d7c..4c6b181c5e 100644 --- a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx +++ b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx @@ -175,6 +175,12 @@ const CollaborativeEditor = forwardRef( true ); success("Session ended. All participants will be notified."); + + // Event when peer disconnected, in between 0-15s user decides to end session before auto end session is triggered from inactivity + if (sessionEndTimeout) { + clearTimeout(sessionEndTimeout); + sessionEndTimeout = null; + } } }, })); From 95747696e5cd9ee036b2317e2fd878fb9a16f860 Mon Sep 17 00:00:00 2001 From: bensohh Date: Sun, 3 Nov 2024 14:05:56 +0800 Subject: [PATCH 122/258] Change default language to python for code editor --- .../CollaborativeEditor.tsx | 113 +++++++++--------- 1 file changed, 57 insertions(+), 56 deletions(-) diff --git a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx index 4c6b181c5e..3cca3e9d03 100644 --- a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx +++ b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx @@ -78,63 +78,63 @@ const CollaborativeEditor = forwardRef( ) => { const editorRef = useRef(null); // const providerRef = useRef(null); - const [selectedLanguage, setSelectedLanguage] = useState("JavaScript"); + const [selectedLanguage, setSelectedLanguage] = useState("Python"); let sessionEndNotified = false; const languageConf = new Compartment(); // Referenced: https://codemirror.net/examples/config/#dynamic-configuration - const autoLanguage = EditorState.transactionExtender.of((tr) => { - if (!tr.docChanged) return null; - - const snippet = tr.newDoc.sliceString(0, 100); - - // Handle code change - props.onCodeChange(tr.newDoc.toString()); - - // Test for various language - const docIsPython = /^\s*(def|class)\s/.test(snippet); - const docIsJava = /^\s*(class|public\s+static\s+void\s+main)\s/.test( - snippet - ); // Java has some problems - const docIsCpp = /^\s*(#include|namespace|int\s+main)\s/.test(snippet); // Yet to test c++ - const docIsGo = /^(package|import|func|type|var|const)\s/.test(snippet); - - let newLanguage; - let languageType; - let languageLabel; - - if (docIsPython) { - newLanguage = python(); - languageLabel = "Python"; - languageType = pythonLanguage; - } else if (docIsJava) { - newLanguage = java(); - languageLabel = "Java"; - languageType = javaLanguage; - } else if (docIsGo) { - newLanguage = go(); - languageLabel = "Go"; - languageType = goLanguage; - } else if (docIsCpp) { - newLanguage = cpp(); - languageLabel = "C++"; - languageType = cppLanguage; - } else { - newLanguage = javascript(); // Default to JavaScript - languageLabel = "JavaScript"; - languageType = javascriptLanguage; - } - - const stateLanguage = tr.startState.facet(language); - if (languageType == stateLanguage) return null; - - setSelectedLanguage(languageLabel); - - return { - effects: languageConf.reconfigure(newLanguage), - }; - }); + // const autoLanguage = EditorState.transactionExtender.of((tr) => { + // if (!tr.docChanged) return null; + + // const snippet = tr.newDoc.sliceString(0, 100); + + // // Handle code change + // props.onCodeChange(tr.newDoc.toString()); + + // // Test for various language + // const docIsPython = /^\s*(def|class)\s/.test(snippet); + // const docIsJava = /^\s*(class|public\s+static\s+void\s+main)\s/.test( + // snippet + // ); // Java has some problems + // const docIsCpp = /^\s*(#include|namespace|int\s+main)\s/.test(snippet); // Yet to test c++ + // const docIsGo = /^(package|import|func|type|var|const)\s/.test(snippet); + + // let newLanguage; + // let languageType; + // let languageLabel; + + // if (docIsPython) { + // newLanguage = python(); + // languageLabel = "Python"; + // languageType = pythonLanguage; + // } else if (docIsJava) { + // newLanguage = java(); + // languageLabel = "Java"; + // languageType = javaLanguage; + // } else if (docIsGo) { + // newLanguage = go(); + // languageLabel = "Go"; + // languageType = goLanguage; + // } else if (docIsCpp) { + // newLanguage = cpp(); + // languageLabel = "C++"; + // languageType = cppLanguage; + // } else { + // newLanguage = javascript(); // Default to JavaScript + // languageLabel = "JavaScript"; + // languageType = javascriptLanguage; + // } + + // const stateLanguage = tr.startState.facet(language); + // if (languageType == stateLanguage) return null; + + // setSelectedLanguage(languageLabel); + + // return { + // effects: languageConf.reconfigure(newLanguage), + // }; + // }); const [messageApi, contextHolder] = message.useMessage(); @@ -290,8 +290,9 @@ const CollaborativeEditor = forwardRef( doc: ytext.toString(), extensions: [ basicSetup, - languageConf.of(javascript()), - autoLanguage, + languageConf.of(python()), + // languageConf.of(javascript()), + // autoLanguage, yCollab(ytext, provider.awareness, { undoManager }), ], }); @@ -326,9 +327,9 @@ const CollaborativeEditor = forwardRef( ref={editorRef} style={{ height: "400px", border: "1px solid #ddd" }} /> -
+ {/*
Current Language Detected: {selectedLanguage} -
+
*/} ); } From 31579dc296607dc3cf3901e299e732efbf7a22db Mon Sep 17 00:00:00 2001 From: bensohh Date: Sun, 3 Nov 2024 15:51:54 +0800 Subject: [PATCH 123/258] Comment out isvalidtoken check for docker to run properly --- apps/frontend/src/middleware.ts | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/frontend/src/middleware.ts b/apps/frontend/src/middleware.ts index 5ea9b2212a..519c4b9f20 100644 --- a/apps/frontend/src/middleware.ts +++ b/apps/frontend/src/middleware.ts @@ -1,5 +1,5 @@ -import { NextURL } from 'next/dist/server/web/next-url'; -import { type NextRequest, NextResponse } from 'next/server'; +import { NextURL } from "next/dist/server/web/next-url"; +import { type NextRequest, NextResponse } from "next/server"; const PUBLIC_ROUTES = ["/login", "/register"]; @@ -18,23 +18,25 @@ async function isValidToken(TOKEN: string): Promise { } export default async function middleware(request: NextRequest) { - const REDIRECT_TO_LOGIN = NextResponse.redirect(new NextURL("/login", request.url)); + const REDIRECT_TO_LOGIN = NextResponse.redirect( + new NextURL("/login", request.url) + ); const TOKEN = request.cookies.get("TOKEN"); if (TOKEN == undefined) { return REDIRECT_TO_LOGIN; } - - if (!await isValidToken(TOKEN.value)) { - REDIRECT_TO_LOGIN.cookies.delete("TOKEN"); - return REDIRECT_TO_LOGIN; - } + + // if (!await isValidToken(TOKEN.value)) { + // REDIRECT_TO_LOGIN.cookies.delete("TOKEN"); + // return REDIRECT_TO_LOGIN; + // } return NextResponse.next(); - } export const config = { - matcher: "/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|login|register).*)", + matcher: + "/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|login|register).*)", // matcher: [ // "/matching", // "/", @@ -42,5 +44,4 @@ export const config = { // "/question", // "/question/.*", // ], -} - +}; From 4a896006c8e24a5cc438068db96a2f166306655f Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Sun, 3 Nov 2024 17:47:42 +0800 Subject: [PATCH 124/258] feat: use codemirror editor --- apps/frontend/src/app/question/[id]/page.tsx | 56 ++++++++++++++++---- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/apps/frontend/src/app/question/[id]/page.tsx b/apps/frontend/src/app/question/[id]/page.tsx index 64fc351c85..aee5f80bbf 100644 --- a/apps/frontend/src/app/question/[id]/page.tsx +++ b/apps/frontend/src/app/question/[id]/page.tsx @@ -21,7 +21,7 @@ import { HistoryOutlined, } from "@ant-design/icons"; import "./styles.scss"; -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { GetSingleQuestion } from "../../services/question"; import React from "react"; import TextArea from "antd/es/input/TextArea"; @@ -29,6 +29,13 @@ import { useSearchParams } from "next/navigation"; import { ProgrammingLanguageOptions } from "@/utils/SelectOptions"; import { useRouter } from "next/navigation"; import { QuestionDetailFull } from "@/components/question/QuestionDetailFull/QuestionDetailFull"; +import CollaborativeEditor, { + CollaborativeEditorHandle, +} from "@/components/CollaborativeEditor/CollaborativeEditor"; +import { WebrtcProvider } from "y-webrtc"; +import { Compartment, EditorState } from "@codemirror/state"; +import { basicSetup, EditorView } from "codemirror"; +import { javascript } from "@codemirror/lang-javascript"; export default function QuestionPage() { const [isLoading, setIsLoading] = useState(true); // Store the states related to table's loading @@ -44,6 +51,9 @@ export default function QuestionPage() { }; const router = useRouter(); + const editorRef = useRef(null); + const providerRef = useRef(null); + const languageConf = new Compartment(); // Retrieve the docRefId from query params during page navigation const searchParams = useSearchParams(); @@ -55,7 +65,17 @@ export default function QuestionPage() { const [complexity, setComplexity] = useState(undefined); const [categories, setCategories] = useState([]); // Store the selected filter categories const [description, setDescription] = useState(undefined); - const [selectedItem, setSelectedItem] = useState("python"); // State to hold the selected language item + + const state = EditorState.create({ + doc: "TODO: parse from code", + extensions: [ + basicSetup, + languageConf.of(javascript()), + EditorView.theme({ + "&": { height: "100%", overflow: "hidden" }, // Enable scroll + }), + ], + }); // When code editor page is initialised, fetch the particular question, and display in code editor useEffect(() => { @@ -73,6 +93,16 @@ export default function QuestionPage() { .finally(() => { setIsLoading(false); }); + + const view = new EditorView({ + state, + parent: editorRef.current || undefined, + }); + + return () => { + // Cleanup on component unmount + view.destroy(); + }; }, [docRefId]); // TODO: retrieve history @@ -144,14 +174,22 @@ export default function QuestionPage() { Submitted Code
+ + {/* TODO: add details of attempt here */} {/* TODO: set value of code, refactor to look like collab editor but not editable */} -
- +
From 3b810cf5174dc79a5559d290833064ac0ecfa3e0 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Sun, 3 Nov 2024 17:52:53 +0800 Subject: [PATCH 125/258] fix: add token expire check and comment out backend token check request --- apps/frontend/package.json | 1 + apps/frontend/pnpm-lock.yaml | 420 +++++++++++++++++--------------- apps/frontend/src/middleware.ts | 38 ++- 3 files changed, 249 insertions(+), 210 deletions(-) diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 94cc9de16b..593c6b7b73 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -20,6 +20,7 @@ "@codemirror/state": "^6.4.1", "antd": "^5.20.6", "codemirror": "^6.0.1", + "jwt-decode": "^4.0.0", "next": "14.2.13", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/apps/frontend/pnpm-lock.yaml b/apps/frontend/pnpm-lock.yaml index c114790857..4db0322c24 100644 --- a/apps/frontend/pnpm-lock.yaml +++ b/apps/frontend/pnpm-lock.yaml @@ -10,10 +10,10 @@ importers: dependencies: '@ant-design/icons': specifier: ^5.5.1 - version: 5.5.1(react-dom@18.2.0)(react@18.2.0) + version: 5.5.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@ant-design/nextjs-registry': specifier: ^1.0.1 - version: 1.0.1(@ant-design/cssinjs@1.21.1)(antd@5.20.6)(next@14.2.13)(react-dom@18.2.0)(react@18.2.0) + version: 1.0.1(@ant-design/cssinjs@1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(antd@5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(next@14.2.13(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@codemirror/lang-cpp': specifier: ^6.0.2 version: 6.0.2 @@ -37,13 +37,16 @@ importers: version: 6.4.1 antd: specifier: ^5.20.6 - version: 5.20.6(react-dom@18.2.0)(react@18.2.0) + version: 5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) codemirror: specifier: ^6.0.1 version: 6.0.1(@lezer/common@1.2.3) + jwt-decode: + specifier: ^4.0.0 + version: 4.0.0 next: specifier: 14.2.13 - version: 14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2) + version: 14.2.13(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2) react: specifier: ^18.2.0 version: 18.2.0 @@ -1178,6 +1181,10 @@ packages: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} + jwt-decode@4.0.0: + resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} + engines: {node: '>=18'} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -1962,22 +1969,22 @@ snapshots: dependencies: '@ctrl/tinycolor': 3.6.1 - '@ant-design/cssinjs-utils@1.1.0(react-dom@18.2.0)(react@18.2.0)': + '@ant-design/cssinjs-utils@1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0)(react@18.2.0) + '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@babel/runtime': 7.25.7 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@ant-design/cssinjs@1.21.1(react-dom@18.2.0)(react@18.2.0)': + '@ant-design/cssinjs@1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 '@emotion/hash': 0.8.0 '@emotion/unitless': 0.7.5 classnames: 2.5.1 csstype: 3.1.3 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) stylis: 4.3.4 @@ -1988,21 +1995,21 @@ snapshots: '@ant-design/icons-svg@4.4.2': {} - '@ant-design/icons@5.5.1(react-dom@18.2.0)(react@18.2.0)': + '@ant-design/icons@5.5.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@ant-design/colors': 7.1.0 '@ant-design/icons-svg': 4.4.2 '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@ant-design/nextjs-registry@1.0.1(@ant-design/cssinjs@1.21.1)(antd@5.20.6)(next@14.2.13)(react-dom@18.2.0)(react@18.2.0)': + '@ant-design/nextjs-registry@1.0.1(@ant-design/cssinjs@1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(antd@5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(next@14.2.13(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0)(react@18.2.0) - antd: 5.20.6(react-dom@18.2.0)(react@18.2.0) - next: 14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2) + '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + antd: 5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + next: 14.2.13(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -2242,19 +2249,19 @@ snapshots: dependencies: '@babel/runtime': 7.25.7 - '@rc-component/color-picker@2.0.1(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/color-picker@2.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@ant-design/fast-color': 2.0.6 '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/context@1.4.0(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/context@1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -2262,48 +2269,48 @@ snapshots: dependencies: '@babel/runtime': 7.25.7 - '@rc-component/mutate-observer@1.1.0(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/mutate-observer@1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/portal@1.1.2(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/portal@1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/qrcode@1.0.0(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/qrcode@1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/tour@1.15.1(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/tour@1.15.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/trigger@2.2.3(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/trigger@2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -2333,7 +2340,7 @@ snapshots: '@types/prop-types': 15.7.13 csstype: 3.1.3 - '@typescript-eslint/eslint-plugin@8.8.0(@typescript-eslint/parser@8.8.0)(eslint@8.0.0)(typescript@5.0.2)': + '@typescript-eslint/eslint-plugin@8.8.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint@8.0.0)(typescript@5.0.2)': dependencies: '@eslint-community/regexpp': 4.11.1 '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) @@ -2346,6 +2353,7 @@ snapshots: ignore: 5.3.2 natural-compare: 1.4.0 ts-api-utils: 1.3.0(typescript@5.0.2) + optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - supports-color @@ -2358,6 +2366,7 @@ snapshots: '@typescript-eslint/visitor-keys': 8.8.0 debug: 4.3.7 eslint: 8.0.0 + optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - supports-color @@ -2373,6 +2382,7 @@ snapshots: '@typescript-eslint/utils': 8.8.0(eslint@8.0.0)(typescript@5.0.2) debug: 4.3.7 ts-api-utils: 1.3.0(typescript@5.0.2) + optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - eslint @@ -2390,6 +2400,7 @@ snapshots: minimatch: 9.0.5 semver: 7.6.3 ts-api-utils: 1.3.0(typescript@5.0.2) + optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - supports-color @@ -2435,55 +2446,55 @@ snapshots: ansi-styles@6.2.1: {} - antd@5.20.6(react-dom@18.2.0)(react@18.2.0): + antd@5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@ant-design/colors': 7.1.0 - '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0)(react@18.2.0) - '@ant-design/cssinjs-utils': 1.1.0(react-dom@18.2.0)(react@18.2.0) - '@ant-design/icons': 5.5.1(react-dom@18.2.0)(react@18.2.0) + '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@ant-design/cssinjs-utils': 1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@ant-design/icons': 5.5.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@ant-design/react-slick': 1.1.2(react@18.2.0) '@babel/runtime': 7.25.7 '@ctrl/tinycolor': 3.6.1 - '@rc-component/color-picker': 2.0.1(react-dom@18.2.0)(react@18.2.0) - '@rc-component/mutate-observer': 1.1.0(react-dom@18.2.0)(react@18.2.0) - '@rc-component/qrcode': 1.0.0(react-dom@18.2.0)(react@18.2.0) - '@rc-component/tour': 1.15.1(react-dom@18.2.0)(react@18.2.0) - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/color-picker': 2.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/mutate-observer': 1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/qrcode': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/tour': 1.15.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 copy-to-clipboard: 3.3.3 dayjs: 1.11.13 - rc-cascader: 3.28.1(react-dom@18.2.0)(react@18.2.0) - rc-checkbox: 3.3.0(react-dom@18.2.0)(react@18.2.0) - rc-collapse: 3.7.3(react-dom@18.2.0)(react@18.2.0) - rc-dialog: 9.5.2(react-dom@18.2.0)(react@18.2.0) - rc-drawer: 7.2.0(react-dom@18.2.0)(react@18.2.0) - rc-dropdown: 4.2.0(react-dom@18.2.0)(react@18.2.0) - rc-field-form: 2.4.0(react-dom@18.2.0)(react@18.2.0) - rc-image: 7.9.0(react-dom@18.2.0)(react@18.2.0) - rc-input: 1.6.3(react-dom@18.2.0)(react@18.2.0) - rc-input-number: 9.2.0(react-dom@18.2.0)(react@18.2.0) - rc-mentions: 2.15.0(react-dom@18.2.0)(react@18.2.0) - rc-menu: 9.14.1(react-dom@18.2.0)(react@18.2.0) - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-notification: 5.6.2(react-dom@18.2.0)(react@18.2.0) - rc-pagination: 4.2.0(react-dom@18.2.0)(react@18.2.0) - rc-picker: 4.6.15(dayjs@1.11.13)(react-dom@18.2.0)(react@18.2.0) - rc-progress: 4.0.0(react-dom@18.2.0)(react@18.2.0) - rc-rate: 2.13.0(react-dom@18.2.0)(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-segmented: 2.3.0(react-dom@18.2.0)(react@18.2.0) - rc-select: 14.15.2(react-dom@18.2.0)(react@18.2.0) - rc-slider: 11.1.6(react-dom@18.2.0)(react@18.2.0) - rc-steps: 6.0.1(react-dom@18.2.0)(react@18.2.0) - rc-switch: 4.1.0(react-dom@18.2.0)(react@18.2.0) - rc-table: 7.45.7(react-dom@18.2.0)(react@18.2.0) - rc-tabs: 15.1.1(react-dom@18.2.0)(react@18.2.0) - rc-textarea: 1.8.2(react-dom@18.2.0)(react@18.2.0) - rc-tooltip: 6.2.1(react-dom@18.2.0)(react@18.2.0) - rc-tree: 5.9.0(react-dom@18.2.0)(react@18.2.0) - rc-tree-select: 5.23.0(react-dom@18.2.0)(react@18.2.0) - rc-upload: 4.7.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-cascader: 3.28.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-checkbox: 3.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-collapse: 3.7.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-dialog: 9.5.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-drawer: 7.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-dropdown: 4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-field-form: 2.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-image: 7.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-input: 1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-input-number: 9.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-mentions: 2.15.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-menu: 9.14.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-notification: 5.6.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-pagination: 4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-picker: 4.6.15(dayjs@1.11.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-progress: 4.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-rate: 2.13.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-segmented: 2.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-select: 14.15.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-slider: 11.1.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-steps: 6.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-switch: 4.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-table: 7.45.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-tabs: 15.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-textarea: 1.8.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-tooltip: 6.2.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-tree: 5.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-tree-select: 5.23.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-upload: 4.7.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) scroll-into-view-if-needed: 3.1.0 @@ -2864,15 +2875,16 @@ snapshots: dependencies: '@next/eslint-plugin-next': 14.2.13 '@rushstack/eslint-patch': 1.10.4 - '@typescript-eslint/eslint-plugin': 8.8.0(@typescript-eslint/parser@8.8.0)(eslint@8.0.0)(typescript@5.0.2) + '@typescript-eslint/eslint-plugin': 8.8.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint@8.0.0)(typescript@5.0.2) '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) eslint: 8.0.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0) - eslint-plugin-import: 2.30.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint@8.0.0))(eslint@8.0.0) + eslint-plugin-import: 2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint@8.0.0))(eslint@8.0.0))(eslint@8.0.0) eslint-plugin-jsx-a11y: 6.10.0(eslint@8.0.0) eslint-plugin-react: 7.37.1(eslint@8.0.0) eslint-plugin-react-hooks: 4.6.2(eslint@8.0.0) + optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - eslint-import-resolver-webpack @@ -2887,38 +2899,39 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0): + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint@8.0.0))(eslint@8.0.0): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 8.0.0 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) - eslint-plugin-import: 2.30.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint@8.0.0))(eslint@8.0.0))(eslint@8.0.0) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 is-glob: 4.0.3 + optionalDependencies: + eslint-plugin-import: 2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint@8.0.0))(eslint@8.0.0))(eslint@8.0.0) transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-node - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint@8.0.0))(eslint@8.0.0))(eslint@8.0.0): dependencies: - '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) eslint: 8.0.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint@8.0.0))(eslint@8.0.0) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): + eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint@8.0.0))(eslint@8.0.0))(eslint@8.0.0): dependencies: '@rtsao/scc': 1.1.0 - '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 array.prototype.flat: 1.3.2 @@ -2927,7 +2940,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.0.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint@8.0.0))(eslint@8.0.0))(eslint@8.0.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -2937,6 +2950,8 @@ snapshots: object.values: 1.2.0 semver: 6.3.1 tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -3379,6 +3394,8 @@ snapshots: object.assign: 4.1.5 object.values: 1.2.0 + jwt-decode@4.0.0: {} + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -3431,7 +3448,7 @@ snapshots: natural-compare@1.4.0: {} - next@14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2): + next@14.2.13(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2): dependencies: '@next/env': 14.2.13 '@swc/helpers': 0.5.5 @@ -3441,7 +3458,6 @@ snapshots: postcss: 8.4.31 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - sass: 1.79.2 styled-jsx: 5.1.1(react@18.2.0) optionalDependencies: '@next/swc-darwin-arm64': 14.2.13 @@ -3453,6 +3469,7 @@ snapshots: '@next/swc-win32-arm64-msvc': 14.2.13 '@next/swc-win32-ia32-msvc': 14.2.13 '@next/swc-win32-x64-msvc': 14.2.13 + sass: 1.79.2 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -3558,321 +3575,322 @@ snapshots: dependencies: safe-buffer: 5.2.1 - rc-cascader@3.28.1(react-dom@18.2.0)(react@18.2.0): + rc-cascader@3.28.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 array-tree-filter: 2.1.0 classnames: 2.5.1 - rc-select: 14.15.2(react-dom@18.2.0)(react@18.2.0) - rc-tree: 5.9.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-select: 14.15.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-tree: 5.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-checkbox@3.3.0(react-dom@18.2.0)(react@18.2.0): + rc-checkbox@3.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-collapse@3.7.3(react-dom@18.2.0)(react@18.2.0): + rc-collapse@3.7.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-dialog@9.5.2(react-dom@18.2.0)(react@18.2.0): + rc-dialog@9.5.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-drawer@7.2.0(react-dom@18.2.0)(react@18.2.0): + rc-drawer@7.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-dropdown@4.2.0(react-dom@18.2.0)(react@18.2.0): + rc-dropdown@4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-field-form@2.4.0(react-dom@18.2.0)(react@18.2.0): + rc-field-form@2.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/async-validator': 5.0.4 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-image@7.9.0(react-dom@18.2.0)(react@18.2.0): + rc-image@7.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-dialog: 9.5.2(react-dom@18.2.0)(react@18.2.0) - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-dialog: 9.5.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-input-number@9.2.0(react-dom@18.2.0)(react@18.2.0): + rc-input-number@9.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/mini-decimal': 1.1.0 classnames: 2.5.1 - rc-input: 1.6.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-input: 1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-input@1.6.3(react-dom@18.2.0)(react@18.2.0): + rc-input@1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-mentions@2.15.0(react-dom@18.2.0)(react@18.2.0): + rc-mentions@2.15.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-input: 1.6.3(react-dom@18.2.0)(react@18.2.0) - rc-menu: 9.14.1(react-dom@18.2.0)(react@18.2.0) - rc-textarea: 1.8.2(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-input: 1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-menu: 9.14.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-textarea: 1.8.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-menu@9.14.1(react-dom@18.2.0)(react@18.2.0): + rc-menu@9.14.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-overflow: 1.3.2(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-overflow: 1.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-motion@2.9.3(react-dom@18.2.0)(react@18.2.0): + rc-motion@2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-notification@5.6.2(react-dom@18.2.0)(react@18.2.0): + rc-notification@5.6.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-overflow@1.3.2(react-dom@18.2.0)(react@18.2.0): + rc-overflow@1.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-pagination@4.2.0(react-dom@18.2.0)(react@18.2.0): + rc-pagination@4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-picker@4.6.15(dayjs@1.11.13)(react-dom@18.2.0)(react@18.2.0): + rc-picker@4.6.15(dayjs@1.11.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - dayjs: 1.11.13 - rc-overflow: 1.3.2(react-dom@18.2.0)(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-overflow: 1.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + dayjs: 1.11.13 - rc-progress@4.0.0(react-dom@18.2.0)(react@18.2.0): + rc-progress@4.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-rate@2.13.0(react-dom@18.2.0)(react@18.2.0): + rc-rate@2.13.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-resize-observer@1.4.0(react-dom@18.2.0)(react@18.2.0): + rc-resize-observer@1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) resize-observer-polyfill: 1.5.1 - rc-segmented@2.3.0(react-dom@18.2.0)(react@18.2.0): + rc-segmented@2.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-select@14.15.2(react-dom@18.2.0)(react@18.2.0): + rc-select@14.15.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-overflow: 1.3.2(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) - rc-virtual-list: 3.14.8(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-overflow: 1.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-virtual-list: 3.14.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-slider@11.1.6(react-dom@18.2.0)(react@18.2.0): + rc-slider@11.1.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-steps@6.0.1(react-dom@18.2.0)(react@18.2.0): + rc-steps@6.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-switch@4.1.0(react-dom@18.2.0)(react@18.2.0): + rc-switch@4.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-table@7.45.7(react-dom@18.2.0)(react@18.2.0): + rc-table@7.45.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/context': 1.4.0(react-dom@18.2.0)(react@18.2.0) + '@rc-component/context': 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) - rc-virtual-list: 3.14.8(react-dom@18.2.0)(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-virtual-list: 3.14.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-tabs@15.1.1(react-dom@18.2.0)(react@18.2.0): + rc-tabs@15.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-dropdown: 4.2.0(react-dom@18.2.0)(react@18.2.0) - rc-menu: 9.14.1(react-dom@18.2.0)(react@18.2.0) - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-dropdown: 4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-menu: 9.14.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-textarea@1.8.2(react-dom@18.2.0)(react@18.2.0): + rc-textarea@1.8.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-input: 1.6.3(react-dom@18.2.0)(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-input: 1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-tooltip@6.2.1(react-dom@18.2.0)(react@18.2.0): + rc-tooltip@6.2.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-tree-select@5.23.0(react-dom@18.2.0)(react@18.2.0): + rc-tree-select@5.23.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-select: 14.15.2(react-dom@18.2.0)(react@18.2.0) - rc-tree: 5.9.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-select: 14.15.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-tree: 5.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-tree@5.9.0(react-dom@18.2.0)(react@18.2.0): + rc-tree@5.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) - rc-virtual-list: 3.14.8(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-virtual-list: 3.14.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-upload@4.7.0(react-dom@18.2.0)(react@18.2.0): + rc-upload@4.7.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-util@5.43.0(react-dom@18.2.0)(react@18.2.0): + rc-util@5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-is: 18.3.1 - rc-virtual-list@3.14.8(react-dom@18.2.0)(react@18.2.0): + rc-virtual-list@3.14.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) diff --git a/apps/frontend/src/middleware.ts b/apps/frontend/src/middleware.ts index 5ea9b2212a..210871af99 100644 --- a/apps/frontend/src/middleware.ts +++ b/apps/frontend/src/middleware.ts @@ -1,5 +1,6 @@ -import { NextURL } from 'next/dist/server/web/next-url'; -import { type NextRequest, NextResponse } from 'next/server'; +import { NextURL } from "next/dist/server/web/next-url"; +import { type NextRequest, NextResponse } from "next/server"; +import { jwtDecode } from "jwt-decode"; const PUBLIC_ROUTES = ["/login", "/register"]; @@ -17,24 +18,44 @@ async function isValidToken(TOKEN: string): Promise { return status === 200; } +function isTokenExpired(token: string) { + if (!token) return true; + + try { + const decodedToken = jwtDecode(token); + const currentTime = Date.now() / 1000; // Current time in seconds + return decodedToken?.exp != undefined && decodedToken.exp < currentTime; + } catch (error) { + return true; // Return true if token is invalid + } +} + export default async function middleware(request: NextRequest) { - const REDIRECT_TO_LOGIN = NextResponse.redirect(new NextURL("/login", request.url)); + const REDIRECT_TO_LOGIN = NextResponse.redirect( + new NextURL("/login", request.url) + ); const TOKEN = request.cookies.get("TOKEN"); if (TOKEN == undefined) { return REDIRECT_TO_LOGIN; } - - if (!await isValidToken(TOKEN.value)) { + + if (isTokenExpired(TOKEN.value)) { REDIRECT_TO_LOGIN.cookies.delete("TOKEN"); return REDIRECT_TO_LOGIN; } + // FIXME: isValidToken check leads to error: not being able to access user service. + // if (!(await isValidToken(TOKEN.value))) { + // REDIRECT_TO_LOGIN.cookies.delete("TOKEN"); + // return REDIRECT_TO_LOGIN; + // } + return NextResponse.next(); - } export const config = { - matcher: "/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|login|register).*)", + matcher: + "/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|login|register).*)", // matcher: [ // "/matching", // "/", @@ -42,5 +63,4 @@ export const config = { // "/question", // "/question/.*", // ], -} - +}; From 548443867a0ae0a33c7a3c7099750a2246a97a78 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Sun, 3 Nov 2024 19:06:41 +0800 Subject: [PATCH 126/258] feat; update history service model --- apps/history-service/handlers/create.go | 4 ++-- .../handlers/createOrUpdate.go | 4 ++-- .../handlers/listquestionhistory.go | 4 ++-- .../handlers/listuserhistory.go | 9 ++++---- apps/history-service/handlers/read.go | 6 +++--- apps/history-service/handlers/update.go | 2 +- apps/history-service/main.go | 1 + apps/history-service/models/models.go | 21 ++++++++++++------- apps/history-service/models/pagination.go | 10 +++++++++ 9 files changed, 39 insertions(+), 22 deletions(-) create mode 100644 apps/history-service/models/pagination.go diff --git a/apps/history-service/handlers/create.go b/apps/history-service/handlers/create.go index 7ce6037eff..1dd7e6efd8 100644 --- a/apps/history-service/handlers/create.go +++ b/apps/history-service/handlers/create.go @@ -22,7 +22,7 @@ func (s *Service) CreateHistory(w http.ResponseWriter, r *http.Request) { } // Document reference ID in firestore mapped to the match ID in model - docRef := s.Client.Collection("collaboration-history").Doc(collaborationHistory.MatchID) + docRef := s.Client.Collection("collaboration-history").Doc(collaborationHistory.HistoryDocRefID) _, err := docRef.Set(ctx, map[string]interface{}{ "title": collaborationHistory.Title, @@ -58,7 +58,7 @@ func (s *Service) CreateHistory(w http.ResponseWriter, r *http.Request) { http.Error(w, "Failed to map history data", http.StatusInternalServerError) return } - collaborationHistory.MatchID = doc.Ref.ID + collaborationHistory.HistoryDocRefID = doc.Ref.ID w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) diff --git a/apps/history-service/handlers/createOrUpdate.go b/apps/history-service/handlers/createOrUpdate.go index 6f091eba19..1c3ba5d352 100644 --- a/apps/history-service/handlers/createOrUpdate.go +++ b/apps/history-service/handlers/createOrUpdate.go @@ -66,7 +66,7 @@ func (s *Service) CreateOrUpdateHistory(w http.ResponseWriter, r *http.Request) http.Error(w, "Failed to map history data", http.StatusInternalServerError) return } - collaborationHistory.MatchID = doc.Ref.ID + collaborationHistory.HistoryDocRefID = doc.Ref.ID w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) @@ -118,7 +118,7 @@ func (s *Service) CreateOrUpdateHistory(w http.ResponseWriter, r *http.Request) http.Error(w, "Failed to map history data", http.StatusInternalServerError) return } - collaborationHistory.MatchID = doc.Ref.ID + collaborationHistory.HistoryDocRefID = doc.Ref.ID w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) diff --git a/apps/history-service/handlers/listquestionhistory.go b/apps/history-service/handlers/listquestionhistory.go index 486f83363a..6c8ee3f62f 100644 --- a/apps/history-service/handlers/listquestionhistory.go +++ b/apps/history-service/handlers/listquestionhistory.go @@ -39,7 +39,7 @@ func (s *Service) ListUserQuestionHistories(w http.ResponseWriter, r *http.Reque http.Error(w, "Failed to map history data for user", http.StatusInternalServerError) return } - history.MatchID = doc.Ref.ID + history.HistoryDocRefID = doc.Ref.ID histories = append(histories, history) } @@ -59,7 +59,7 @@ func (s *Service) ListUserQuestionHistories(w http.ResponseWriter, r *http.Reque http.Error(w, "Failed to map history data for matched user", http.StatusInternalServerError) return } - history.MatchID = doc.Ref.ID + history.HistoryDocRefID = doc.Ref.ID histories = append(histories, history) } diff --git a/apps/history-service/handlers/listuserhistory.go b/apps/history-service/handlers/listuserhistory.go index 554dc159ca..712c649020 100644 --- a/apps/history-service/handlers/listuserhistory.go +++ b/apps/history-service/handlers/listuserhistory.go @@ -2,10 +2,11 @@ package handlers import ( "encoding/json" - "github.com/go-chi/chi/v5" - "google.golang.org/api/iterator" "history-service/models" "net/http" + + "github.com/go-chi/chi/v5" + "google.golang.org/api/iterator" ) func (s *Service) ListUserHistories(w http.ResponseWriter, r *http.Request) { @@ -38,7 +39,7 @@ func (s *Service) ListUserHistories(w http.ResponseWriter, r *http.Request) { http.Error(w, "Failed to map history data for user", http.StatusInternalServerError) return } - history.MatchID = doc.Ref.ID + history.HistoryDocRefID = doc.Ref.ID histories = append(histories, history) } @@ -58,7 +59,7 @@ func (s *Service) ListUserHistories(w http.ResponseWriter, r *http.Request) { http.Error(w, "Failed to map history data for matched user", http.StatusInternalServerError) return } - history.MatchID = doc.Ref.ID + history.HistoryDocRefID = doc.Ref.ID histories = append(histories, history) } diff --git a/apps/history-service/handlers/read.go b/apps/history-service/handlers/read.go index d7c6ea23a0..f986393919 100644 --- a/apps/history-service/handlers/read.go +++ b/apps/history-service/handlers/read.go @@ -13,10 +13,10 @@ import ( func (s *Service) ReadHistory(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - matchId := chi.URLParam(r, "matchId") + historyDocRefId := chi.URLParam(r, "historyDocRefId") // Reference document - docRef := s.Client.Collection("collaboration-history").Doc(matchId) + docRef := s.Client.Collection("collaboration-history").Doc(historyDocRefId) // Get data doc, err := docRef.Get(ctx) @@ -35,7 +35,7 @@ func (s *Service) ReadHistory(w http.ResponseWriter, r *http.Request) { http.Error(w, "Failed to map history data", http.StatusInternalServerError) return } - collaborationHistory.MatchID = doc.Ref.ID + collaborationHistory.HistoryDocRefID = doc.Ref.ID w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) diff --git a/apps/history-service/handlers/update.go b/apps/history-service/handlers/update.go index 401953a472..f91d9794e9 100644 --- a/apps/history-service/handlers/update.go +++ b/apps/history-service/handlers/update.go @@ -69,7 +69,7 @@ func (s *Service) UpdateHistory(w http.ResponseWriter, r *http.Request) { http.Error(w, "Failed to map history data", http.StatusInternalServerError) return } - updatedHistory.MatchID = doc.Ref.ID + updatedHistory.HistoryDocRefID = doc.Ref.ID w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) diff --git a/apps/history-service/main.go b/apps/history-service/main.go index 17194b9f49..f57f9663ea 100644 --- a/apps/history-service/main.go +++ b/apps/history-service/main.go @@ -77,6 +77,7 @@ func initChiRouter(service *handlers.Service) *chi.Mux { func registerRoutes(r *chi.Mux, service *handlers.Service) { r.Route("/histories", func(r chi.Router) { r.Post("/", service.CreateHistory) + r.Get("/{historyDocRefId}", service.ReadHistory) r.Route("/{username}", func(r chi.Router) { r.Get("/", service.ListUserHistories) r.Get("/{questionDocRefId}", service.ListUserQuestionHistories) diff --git a/apps/history-service/models/models.go b/apps/history-service/models/models.go index 9928b8809b..b8cc571593 100644 --- a/apps/history-service/models/models.go +++ b/apps/history-service/models/models.go @@ -3,18 +3,23 @@ package models import "time" type CollaborationHistory struct { + // Submission related details + Code string `json:"code" firestore:"code"` + Language string `json:"language" firestore:"language"` + + // Match related details + User string `json:"user" firestore:"user"` + MatchedUser string `json:"matchedUser" firestore:"matchedUser"` + MatchedTopics []string `json:"matchedTopics" firestore:"matchedTopics"` + + // Question related details Title string `json:"title" firestore:"title"` - Code string `json:"code" firestore:"code"` - Language string `json:"language" firestore:"language"` - User string `json:"user" firestore:"user"` - MatchedUser string `json:"matchedUser" firestore:"matchedUser"` - MatchID string `json:"matchId" firestore:"matchId"` - MatchedTopics []string `json:"matchedTopics" firestore:"matchedTopics"` QuestionDocRefID string `json:"questionDocRefId" firestore:"questionDocRefId"` QuestionDifficulty string `json:"questionDifficulty" firestore:"questionDifficulty"` QuestionTopics []string `json:"questionTopics" firestore:"questionTopics"` // Special DB fields - CreatedAt time.Time `json:"createdAt" firestore:"createdAt"` - UpdatedAt time.Time `json:"updatedAt" firestore:"updatedAt"` + CreatedAt time.Time `json:"createdAt" firestore:"createdAt"` + UpdatedAt time.Time `json:"updatedAt" firestore:"updatedAt"` // updatedAt is unused as history is never updated once created + HistoryDocRefID string `json:"historyDocRefId"` } diff --git a/apps/history-service/models/pagination.go b/apps/history-service/models/pagination.go new file mode 100644 index 0000000000..a5a74ba7ea --- /dev/null +++ b/apps/history-service/models/pagination.go @@ -0,0 +1,10 @@ +package models + +type HistoriesResponse struct { + TotalCount int `json:"totalCount"` + TotalPages int `json:"totalPages"` + CurrentPage int `json:"currentPage"` + Limit int `json:"limit"` + HasNextPage bool `json:"hasNextPage"` + Questions []CollaborationHistory `json:"histories"` +} From 4297c31cb3eb7870965b95b7b717cc495fc9c141 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Sun, 3 Nov 2024 20:52:53 +0800 Subject: [PATCH 127/258] feat: fetch from backend for a submission --- apps/frontend/src/app/question/[id]/page.tsx | 82 ++++++++-- .../src/app/question/[id]/styles.scss | 31 +--- apps/frontend/src/app/services/history.ts | 150 ++++++++++-------- .../handlers/listquestionhistory.go | 5 +- apps/history-service/main.go | 6 +- 5 files changed, 166 insertions(+), 108 deletions(-) diff --git a/apps/frontend/src/app/question/[id]/page.tsx b/apps/frontend/src/app/question/[id]/page.tsx index aee5f80bbf..23616cd404 100644 --- a/apps/frontend/src/app/question/[id]/page.tsx +++ b/apps/frontend/src/app/question/[id]/page.tsx @@ -36,6 +36,15 @@ import { WebrtcProvider } from "y-webrtc"; import { Compartment, EditorState } from "@codemirror/state"; import { basicSetup, EditorView } from "codemirror"; import { javascript } from "@codemirror/lang-javascript"; +import { GetHistory, GetUserQuestionHistories } from "@/app/services/history"; +import { ValidateUser, VerifyTokenResponseType } from "@/app/services/user"; + +interface Submission { + submittedAt: string; + language: string; + matchedUser: string; + code: string; +} export default function QuestionPage() { const [isLoading, setIsLoading] = useState(true); // Store the states related to table's loading @@ -52,7 +61,6 @@ export default function QuestionPage() { const router = useRouter(); const editorRef = useRef(null); - const providerRef = useRef(null); const languageConf = new Compartment(); // Retrieve the docRefId from query params during page navigation @@ -65,9 +73,13 @@ export default function QuestionPage() { const [complexity, setComplexity] = useState(undefined); const [categories, setCategories] = useState([]); // Store the selected filter categories const [description, setDescription] = useState(undefined); + const [username, setUsername] = useState(""); + const [userQuestionHistories, setUserQuestionHistories] = + useState(); + const [submission, setSubmission] = useState(); const state = EditorState.create({ - doc: "TODO: parse from code", + doc: "", extensions: [ basicSetup, languageConf.of(javascript()), @@ -93,20 +105,53 @@ export default function QuestionPage() { .finally(() => { setIsLoading(false); }); + }, [docRefId]); + useEffect(() => { + ValidateUser().then((data: VerifyTokenResponseType) => { + setUsername(data.data.username); + }); + }, []); + + useEffect(() => { const view = new EditorView({ state, parent: editorRef.current || undefined, }); + // TODO: get from a specific history which was selected. + GetHistory("182d0ae6db66fdbefb657f09df3a44a8").then((data: any) => { + setSubmission({ + submittedAt: data.createdAt, + language: data.language, + matchedUser: data.matchedUser, + code: data.code, + }); + + view.dispatch( + view.state.update({ + changes: { from: 0, to: state.doc.length, insert: data.code }, + }) + ); + }); + return () => { // Cleanup on component unmount view.destroy(); }; - }, [docRefId]); + }, []); - // TODO: retrieve history - const history: any[] = []; + useEffect(() => { + GetUserQuestionHistories(username, docRefId).then((data: any) => { + setUserQuestionHistories(data); + }); + }, [docRefId, username]); + + useEffect(() => { + GetUserQuestionHistories(username, docRefId).then((data: any) => { + setUserQuestionHistories(data); + }); + }, [docRefId, username]); const columns = [ { @@ -115,9 +160,9 @@ export default function QuestionPage() { key: "id", }, { - title: "Attempted at", - dataIndex: "attemptedAt", - key: "attemptedAt", + title: "Submitted at", + dataIndex: "createdAt", + key: "createdAt", }, { title: "Language", @@ -159,7 +204,7 @@ export default function QuestionPage() {
@@ -174,6 +219,23 @@ export default function QuestionPage() { Submitted Code +
+
+ Submitted at: {submission?.submittedAt || "-"} +
+
+ Language: {submission?.language || "-"} +
+
+ Matched with: {submission?.matchedUser || "-"} +
+
{/* TODO: add details of attempt here */} {/* TODO: set value of code, refactor to look like collab editor but not editable */} @@ -190,7 +252,7 @@ export default function QuestionPage() { overflow: "scroll", border: "1px solid #ddd", }} - /> + > diff --git a/apps/frontend/src/app/question/[id]/styles.scss b/apps/frontend/src/app/question/[id]/styles.scss index a0692e044c..7382768adf 100644 --- a/apps/frontend/src/app/question/[id]/styles.scss +++ b/apps/frontend/src/app/question/[id]/styles.scss @@ -66,32 +66,6 @@ padding: 1rem; } -.chat-container { - border: 2px solid #463f3a; - border-radius: 10px; - width: 100%; - padding: 1rem; -} - -.chat-message-box { - margin-top: 1rem; - height: 365px; - border: 1px solid #d9d9d9; - border-radius: 6px; - overflow-y: scroll; -} - -.chat-header-message { - font-size: 14px; - color: #c6c6c6; - margin: 3px auto; - text-align: center; -} - -.chat-typing-box { - margin-top: 1rem; -} - .question-title, .test-title, .code-title, @@ -163,3 +137,8 @@ .code-viewer { resize: none; } + +.submission-header-detail { + font-weight: normal; + padding: 0px 10px 0px 10px; +} diff --git a/apps/frontend/src/app/services/history.ts b/apps/frontend/src/app/services/history.ts index fc01f913ec..b007d832f7 100644 --- a/apps/frontend/src/app/services/history.ts +++ b/apps/frontend/src/app/services/history.ts @@ -1,84 +1,102 @@ const HISTORY_SERVICE_URL = process.env.NEXT_PUBLIC_HISTORY_SERVICE_URL; export interface History { - title: string; - code: string; - language: string; - user: string; - matchedUser: string; - matchId: string; - matchedTopics: string[]; - questionDocRefId: string; - questionDifficulty: string; - questionTopics: string[]; - createdAt?: string; - updatedAt?: string; + title: string; + code: string; + language: string; + user: string; + matchedUser: string; + historyDocRefId: string; + matchedTopics: string[]; + questionDocRefId: string; + questionDifficulty: string; + questionTopics: string[]; + createdAt?: string; + updatedAt?: string; } export const CreateOrUpdateHistory = async ( - history: History, - matchId: string, + history: History, + historyDocRefId: string ): Promise => { - const response = await fetch( - `${HISTORY_SERVICE_URL}histories/${matchId}`, - { - method: "PUT", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(history), - } - ); - - if (response.status === 200) { - return response.json(); - } else { - throw new Error( - `Error saving history: ${response.status} ${response.statusText}` - ); + const response = await fetch( + `${HISTORY_SERVICE_URL}histories/${historyDocRefId}`, + { + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(history), } -} + ); -export const GetHistory = async ( - matchId: string, -): Promise => { - const response = await fetch( - `${HISTORY_SERVICE_URL}histories/${matchId}`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } + if (response.status === 200) { + return response.json(); + } else { + throw new Error( + `Error saving history: ${response.status} ${response.statusText}` ); + } +}; - if (response.status === 200) { - return response.json(); - } else { - throw new Error( - `Error reading history: ${response.status} ${response.statusText}` - ); +export const GetHistory = async (historyDocRefId: string): Promise => { + const response = await fetch( + `${HISTORY_SERVICE_URL}histories/${historyDocRefId}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + }, } -} + ); + + if (response.status === 200) { + return response.json(); + } else { + throw new Error( + `Error reading history: ${response.status} ${response.statusText}` + ); + } +}; export const GetUserHistories = async ( - username: string, + username: string ): Promise => { - const response = await fetch( - `${HISTORY_SERVICE_URL}histories/${username}`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - } + const response = await fetch(`${HISTORY_SERVICE_URL}histories/${username}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }); + + if (response.status === 200) { + return response.json(); + } else { + throw new Error( + `Error reading user histories: ${response.status} ${response.statusText}` ); + } +}; - if (response.status === 200) { - return response.json(); - } else { - throw new Error( - `Error reading user histories: ${response.status} ${response.statusText}` - ); +export const GetUserQuestionHistories = async ( + username: string, + questionDocRefId: string +): Promise => { + const response = await fetch( + `${HISTORY_SERVICE_URL}histories/user/${username}/question/${questionDocRefId}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + }, } -} + ); + + if (response.status === 200) { + return response.json(); + } else { + throw new Error( + `Error reading user histories: ${response.status} ${response.statusText}` + ); + } +}; diff --git a/apps/history-service/handlers/listquestionhistory.go b/apps/history-service/handlers/listquestionhistory.go index 6c8ee3f62f..3f0d7153a8 100644 --- a/apps/history-service/handlers/listquestionhistory.go +++ b/apps/history-service/handlers/listquestionhistory.go @@ -14,13 +14,14 @@ func (s *Service) ListUserQuestionHistories(w http.ResponseWriter, r *http.Reque // Parse request username := chi.URLParam(r, "username") + questionDocRefID := chi.URLParam(r, "questionDocRefId") // Reference collection collRef := s.Client.Collection("collaboration-history") // Query data - iterUser := collRef.Where("user", "==", username).Documents(ctx) - iterMatchedUser := collRef.Where("matchedUser", "==", username).Documents(ctx) + iterUser := collRef.Where("user", "==", username).Where("questionDocRefId", "==", questionDocRefID).Documents(ctx) + iterMatchedUser := collRef.Where("matchedUser", "==", username).Where("questionDocRefId", "==", questionDocRefID).Documents(ctx) // Map data var histories []models.CollaborationHistory diff --git a/apps/history-service/main.go b/apps/history-service/main.go index f57f9663ea..751f2ed525 100644 --- a/apps/history-service/main.go +++ b/apps/history-service/main.go @@ -78,10 +78,8 @@ func registerRoutes(r *chi.Mux, service *handlers.Service) { r.Route("/histories", func(r chi.Router) { r.Post("/", service.CreateHistory) r.Get("/{historyDocRefId}", service.ReadHistory) - r.Route("/{username}", func(r chi.Router) { - r.Get("/", service.ListUserHistories) - r.Get("/{questionDocRefId}", service.ListUserQuestionHistories) - }) + r.Get("/user/{username}", service.ListUserHistories) + r.Get("/user/{username}/question/{questionDocRefId}", service.ListUserQuestionHistories) }) } From d3d5b055b01f033cdc589dd3ceff90bc7bae3bfe Mon Sep 17 00:00:00 2001 From: solomonng2001 Date: Sun, 3 Nov 2024 23:25:52 +0800 Subject: [PATCH 128/258] Link frontend code execution to execution service and sync across matched users --- apps/frontend/package.json | 3 + apps/frontend/pnpm-lock.yaml | 439 ++++++++++-------- .../src/app/collaboration/[id]/page.tsx | 258 +++++++--- .../src/app/collaboration/[id]/styles.scss | 40 +- apps/frontend/src/app/services/execute.ts | 127 +++++ .../CollaborativeEditor.tsx | 54 ++- apps/frontend/src/middleware.ts | 8 +- 7 files changed, 650 insertions(+), 279 deletions(-) create mode 100644 apps/frontend/src/app/services/execute.ts diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 94cc9de16b..91d6de3d75 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -11,6 +11,7 @@ "dependencies": { "@ant-design/icons": "^5.5.1", "@ant-design/nextjs-registry": "^1.0.1", + "@codemirror/commands": "^6.7.1", "@codemirror/lang-cpp": "^6.0.2", "@codemirror/lang-go": "^6.0.1", "@codemirror/lang-java": "^6.0.1", @@ -18,6 +19,7 @@ "@codemirror/lang-python": "^6.1.6", "@codemirror/language": "^6.10.3", "@codemirror/state": "^6.4.1", + "@codemirror/view": "^6.34.1", "antd": "^5.20.6", "codemirror": "^6.0.1", "next": "14.2.13", @@ -32,6 +34,7 @@ "yjs": "^13.6.20" }, "devDependencies": { + "@types/codemirror": "^5.60.15", "@types/node": "^20", "@types/react": "^18.3.8", "@types/react-dom": "^18.3.0", diff --git a/apps/frontend/pnpm-lock.yaml b/apps/frontend/pnpm-lock.yaml index c114790857..8f8e07342a 100644 --- a/apps/frontend/pnpm-lock.yaml +++ b/apps/frontend/pnpm-lock.yaml @@ -10,10 +10,13 @@ importers: dependencies: '@ant-design/icons': specifier: ^5.5.1 - version: 5.5.1(react-dom@18.2.0)(react@18.2.0) + version: 5.5.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@ant-design/nextjs-registry': specifier: ^1.0.1 - version: 1.0.1(@ant-design/cssinjs@1.21.1)(antd@5.20.6)(next@14.2.13)(react-dom@18.2.0)(react@18.2.0) + version: 1.0.1(@ant-design/cssinjs@1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(antd@5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(next@14.2.13(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2))(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@codemirror/commands': + specifier: ^6.7.1 + version: 6.7.1 '@codemirror/lang-cpp': specifier: ^6.0.2 version: 6.0.2 @@ -35,15 +38,18 @@ importers: '@codemirror/state': specifier: ^6.4.1 version: 6.4.1 + '@codemirror/view': + specifier: ^6.34.1 + version: 6.34.1 antd: specifier: ^5.20.6 - version: 5.20.6(react-dom@18.2.0)(react@18.2.0) + version: 5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) codemirror: specifier: ^6.0.1 version: 6.0.1(@lezer/common@1.2.3) next: specifier: 14.2.13 - version: 14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2) + version: 14.2.13(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2) react: specifier: ^18.2.0 version: 18.2.0 @@ -72,6 +78,9 @@ importers: specifier: ^13.6.20 version: 13.6.20 devDependencies: + '@types/codemirror': + specifier: ^5.60.15 + version: 5.60.15 '@types/node': specifier: ^20 version: 20.0.0 @@ -389,6 +398,12 @@ packages: '@swc/helpers@0.5.5': resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} + '@types/codemirror@5.60.15': + resolution: {integrity: sha512-dTOvwEQ+ouKJ/rE9LT1Ue2hmP6H1mZv5+CCnNWu2qtiOe2LQa9lCprEY20HxiDmV/Bxh+dXjywmy5aKvoGjULA==} + + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} @@ -404,6 +419,9 @@ packages: '@types/react@18.3.8': resolution: {integrity: sha512-syBUrW3/XpnW4WJ41Pft+I+aPoDVbrBVQGEnbD7NijDGlVC+8gV/XKRY+7vMDlfPpbwYt0l1vd/Sj8bJGMbs9Q==} + '@types/tern@0.23.9': + resolution: {integrity: sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==} + '@typescript-eslint/eslint-plugin@8.8.0': resolution: {integrity: sha512-wORFWjU30B2WJ/aXBfOm1LX9v9nyt9D3jsSOxC3cCaTQGCW5k4jNpmjFv3U7p/7s4yvdjHzwtv2Sd2dOyhjS0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1962,22 +1980,22 @@ snapshots: dependencies: '@ctrl/tinycolor': 3.6.1 - '@ant-design/cssinjs-utils@1.1.0(react-dom@18.2.0)(react@18.2.0)': + '@ant-design/cssinjs-utils@1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0)(react@18.2.0) + '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@babel/runtime': 7.25.7 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@ant-design/cssinjs@1.21.1(react-dom@18.2.0)(react@18.2.0)': + '@ant-design/cssinjs@1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 '@emotion/hash': 0.8.0 '@emotion/unitless': 0.7.5 classnames: 2.5.1 csstype: 3.1.3 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) stylis: 4.3.4 @@ -1988,21 +2006,21 @@ snapshots: '@ant-design/icons-svg@4.4.2': {} - '@ant-design/icons@5.5.1(react-dom@18.2.0)(react@18.2.0)': + '@ant-design/icons@5.5.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@ant-design/colors': 7.1.0 '@ant-design/icons-svg': 4.4.2 '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@ant-design/nextjs-registry@1.0.1(@ant-design/cssinjs@1.21.1)(antd@5.20.6)(next@14.2.13)(react-dom@18.2.0)(react@18.2.0)': + '@ant-design/nextjs-registry@1.0.1(@ant-design/cssinjs@1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(antd@5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(next@14.2.13(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: - '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0)(react@18.2.0) - antd: 5.20.6(react-dom@18.2.0)(react@18.2.0) - next: 14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2) + '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + antd: 5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + next: 14.2.13(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -2242,19 +2260,19 @@ snapshots: dependencies: '@babel/runtime': 7.25.7 - '@rc-component/color-picker@2.0.1(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/color-picker@2.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@ant-design/fast-color': 2.0.6 '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/context@1.4.0(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/context@1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -2262,48 +2280,48 @@ snapshots: dependencies: '@babel/runtime': 7.25.7 - '@rc-component/mutate-observer@1.1.0(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/mutate-observer@1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/portal@1.1.2(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/portal@1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/qrcode@1.0.0(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/qrcode@1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/tour@1.15.1(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/tour@1.15.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - '@rc-component/trigger@2.2.3(react-dom@18.2.0)(react@18.2.0)': + '@rc-component/trigger@2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -2318,6 +2336,12 @@ snapshots: '@swc/counter': 0.1.3 tslib: 2.7.0 + '@types/codemirror@5.60.15': + dependencies: + '@types/tern': 0.23.9 + + '@types/estree@1.0.6': {} + '@types/json5@0.0.29': {} '@types/node@20.0.0': {} @@ -2333,7 +2357,11 @@ snapshots: '@types/prop-types': 15.7.13 csstype: 3.1.3 - '@typescript-eslint/eslint-plugin@8.8.0(@typescript-eslint/parser@8.8.0)(eslint@8.0.0)(typescript@5.0.2)': + '@types/tern@0.23.9': + dependencies: + '@types/estree': 1.0.6 + + '@typescript-eslint/eslint-plugin@8.8.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint@8.0.0)(typescript@5.0.2)': dependencies: '@eslint-community/regexpp': 4.11.1 '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) @@ -2346,6 +2374,7 @@ snapshots: ignore: 5.3.2 natural-compare: 1.4.0 ts-api-utils: 1.3.0(typescript@5.0.2) + optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - supports-color @@ -2358,6 +2387,7 @@ snapshots: '@typescript-eslint/visitor-keys': 8.8.0 debug: 4.3.7 eslint: 8.0.0 + optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - supports-color @@ -2373,6 +2403,7 @@ snapshots: '@typescript-eslint/utils': 8.8.0(eslint@8.0.0)(typescript@5.0.2) debug: 4.3.7 ts-api-utils: 1.3.0(typescript@5.0.2) + optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - eslint @@ -2390,6 +2421,7 @@ snapshots: minimatch: 9.0.5 semver: 7.6.3 ts-api-utils: 1.3.0(typescript@5.0.2) + optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - supports-color @@ -2435,55 +2467,55 @@ snapshots: ansi-styles@6.2.1: {} - antd@5.20.6(react-dom@18.2.0)(react@18.2.0): + antd@5.20.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@ant-design/colors': 7.1.0 - '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0)(react@18.2.0) - '@ant-design/cssinjs-utils': 1.1.0(react-dom@18.2.0)(react@18.2.0) - '@ant-design/icons': 5.5.1(react-dom@18.2.0)(react@18.2.0) + '@ant-design/cssinjs': 1.21.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@ant-design/cssinjs-utils': 1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@ant-design/icons': 5.5.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) '@ant-design/react-slick': 1.1.2(react@18.2.0) '@babel/runtime': 7.25.7 '@ctrl/tinycolor': 3.6.1 - '@rc-component/color-picker': 2.0.1(react-dom@18.2.0)(react@18.2.0) - '@rc-component/mutate-observer': 1.1.0(react-dom@18.2.0)(react@18.2.0) - '@rc-component/qrcode': 1.0.0(react-dom@18.2.0)(react@18.2.0) - '@rc-component/tour': 1.15.1(react-dom@18.2.0)(react@18.2.0) - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/color-picker': 2.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/mutate-observer': 1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/qrcode': 1.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/tour': 1.15.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 copy-to-clipboard: 3.3.3 dayjs: 1.11.13 - rc-cascader: 3.28.1(react-dom@18.2.0)(react@18.2.0) - rc-checkbox: 3.3.0(react-dom@18.2.0)(react@18.2.0) - rc-collapse: 3.7.3(react-dom@18.2.0)(react@18.2.0) - rc-dialog: 9.5.2(react-dom@18.2.0)(react@18.2.0) - rc-drawer: 7.2.0(react-dom@18.2.0)(react@18.2.0) - rc-dropdown: 4.2.0(react-dom@18.2.0)(react@18.2.0) - rc-field-form: 2.4.0(react-dom@18.2.0)(react@18.2.0) - rc-image: 7.9.0(react-dom@18.2.0)(react@18.2.0) - rc-input: 1.6.3(react-dom@18.2.0)(react@18.2.0) - rc-input-number: 9.2.0(react-dom@18.2.0)(react@18.2.0) - rc-mentions: 2.15.0(react-dom@18.2.0)(react@18.2.0) - rc-menu: 9.14.1(react-dom@18.2.0)(react@18.2.0) - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-notification: 5.6.2(react-dom@18.2.0)(react@18.2.0) - rc-pagination: 4.2.0(react-dom@18.2.0)(react@18.2.0) - rc-picker: 4.6.15(dayjs@1.11.13)(react-dom@18.2.0)(react@18.2.0) - rc-progress: 4.0.0(react-dom@18.2.0)(react@18.2.0) - rc-rate: 2.13.0(react-dom@18.2.0)(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-segmented: 2.3.0(react-dom@18.2.0)(react@18.2.0) - rc-select: 14.15.2(react-dom@18.2.0)(react@18.2.0) - rc-slider: 11.1.6(react-dom@18.2.0)(react@18.2.0) - rc-steps: 6.0.1(react-dom@18.2.0)(react@18.2.0) - rc-switch: 4.1.0(react-dom@18.2.0)(react@18.2.0) - rc-table: 7.45.7(react-dom@18.2.0)(react@18.2.0) - rc-tabs: 15.1.1(react-dom@18.2.0)(react@18.2.0) - rc-textarea: 1.8.2(react-dom@18.2.0)(react@18.2.0) - rc-tooltip: 6.2.1(react-dom@18.2.0)(react@18.2.0) - rc-tree: 5.9.0(react-dom@18.2.0)(react@18.2.0) - rc-tree-select: 5.23.0(react-dom@18.2.0)(react@18.2.0) - rc-upload: 4.7.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-cascader: 3.28.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-checkbox: 3.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-collapse: 3.7.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-dialog: 9.5.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-drawer: 7.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-dropdown: 4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-field-form: 2.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-image: 7.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-input: 1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-input-number: 9.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-mentions: 2.15.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-menu: 9.14.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-notification: 5.6.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-pagination: 4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-picker: 4.6.15(dayjs@1.11.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-progress: 4.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-rate: 2.13.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-segmented: 2.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-select: 14.15.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-slider: 11.1.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-steps: 6.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-switch: 4.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-table: 7.45.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-tabs: 15.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-textarea: 1.8.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-tooltip: 6.2.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-tree: 5.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-tree-select: 5.23.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-upload: 4.7.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) scroll-into-view-if-needed: 3.1.0 @@ -2864,15 +2896,16 @@ snapshots: dependencies: '@next/eslint-plugin-next': 14.2.13 '@rushstack/eslint-patch': 1.10.4 - '@typescript-eslint/eslint-plugin': 8.8.0(@typescript-eslint/parser@8.8.0)(eslint@8.0.0)(typescript@5.0.2) + '@typescript-eslint/eslint-plugin': 8.8.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint@8.0.0)(typescript@5.0.2) '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) eslint: 8.0.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0) - eslint-plugin-import: 2.30.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0) + eslint-plugin-import: 2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) eslint-plugin-jsx-a11y: 6.10.0(eslint@8.0.0) eslint-plugin-react: 7.37.1(eslint@8.0.0) eslint-plugin-react-hooks: 4.6.2(eslint@8.0.0) + optionalDependencies: typescript: 5.0.2 transitivePeerDependencies: - eslint-import-resolver-webpack @@ -2887,38 +2920,39 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0): + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 8.0.0 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) - eslint-plugin-import: 2.30.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0))(eslint@8.0.0) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 is-glob: 4.0.3 + optionalDependencies: + eslint-plugin-import: 2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-node - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0))(eslint@8.0.0): dependencies: - '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) eslint: 8.0.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0) + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): + eslint-plugin-import@2.30.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): dependencies: '@rtsao/scc': 1.1.0 - '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 array.prototype.flat: 1.3.2 @@ -2927,7 +2961,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.0.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0))(eslint@8.0.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -2937,6 +2971,8 @@ snapshots: object.values: 1.2.0 semver: 6.3.1 tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.8.0(eslint@8.0.0)(typescript@5.0.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -3431,7 +3467,7 @@ snapshots: natural-compare@1.4.0: {} - next@14.2.13(react-dom@18.2.0)(react@18.2.0)(sass@1.79.2): + next@14.2.13(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2): dependencies: '@next/env': 14.2.13 '@swc/helpers': 0.5.5 @@ -3441,7 +3477,6 @@ snapshots: postcss: 8.4.31 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - sass: 1.79.2 styled-jsx: 5.1.1(react@18.2.0) optionalDependencies: '@next/swc-darwin-arm64': 14.2.13 @@ -3453,6 +3488,7 @@ snapshots: '@next/swc-win32-arm64-msvc': 14.2.13 '@next/swc-win32-ia32-msvc': 14.2.13 '@next/swc-win32-x64-msvc': 14.2.13 + sass: 1.79.2 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -3558,321 +3594,322 @@ snapshots: dependencies: safe-buffer: 5.2.1 - rc-cascader@3.28.1(react-dom@18.2.0)(react@18.2.0): + rc-cascader@3.28.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 array-tree-filter: 2.1.0 classnames: 2.5.1 - rc-select: 14.15.2(react-dom@18.2.0)(react@18.2.0) - rc-tree: 5.9.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-select: 14.15.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-tree: 5.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-checkbox@3.3.0(react-dom@18.2.0)(react@18.2.0): + rc-checkbox@3.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-collapse@3.7.3(react-dom@18.2.0)(react@18.2.0): + rc-collapse@3.7.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-dialog@9.5.2(react-dom@18.2.0)(react@18.2.0): + rc-dialog@9.5.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-drawer@7.2.0(react-dom@18.2.0)(react@18.2.0): + rc-drawer@7.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-dropdown@4.2.0(react-dom@18.2.0)(react@18.2.0): + rc-dropdown@4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-field-form@2.4.0(react-dom@18.2.0)(react@18.2.0): + rc-field-form@2.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/async-validator': 5.0.4 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-image@7.9.0(react-dom@18.2.0)(react@18.2.0): + rc-image@7.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/portal': 1.1.2(react-dom@18.2.0)(react@18.2.0) + '@rc-component/portal': 1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-dialog: 9.5.2(react-dom@18.2.0)(react@18.2.0) - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-dialog: 9.5.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-input-number@9.2.0(react-dom@18.2.0)(react@18.2.0): + rc-input-number@9.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 '@rc-component/mini-decimal': 1.1.0 classnames: 2.5.1 - rc-input: 1.6.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-input: 1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-input@1.6.3(react-dom@18.2.0)(react@18.2.0): + rc-input@1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-mentions@2.15.0(react-dom@18.2.0)(react@18.2.0): + rc-mentions@2.15.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-input: 1.6.3(react-dom@18.2.0)(react@18.2.0) - rc-menu: 9.14.1(react-dom@18.2.0)(react@18.2.0) - rc-textarea: 1.8.2(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-input: 1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-menu: 9.14.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-textarea: 1.8.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-menu@9.14.1(react-dom@18.2.0)(react@18.2.0): + rc-menu@9.14.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-overflow: 1.3.2(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-overflow: 1.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-motion@2.9.3(react-dom@18.2.0)(react@18.2.0): + rc-motion@2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-notification@5.6.2(react-dom@18.2.0)(react@18.2.0): + rc-notification@5.6.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-overflow@1.3.2(react-dom@18.2.0)(react@18.2.0): + rc-overflow@1.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-pagination@4.2.0(react-dom@18.2.0)(react@18.2.0): + rc-pagination@4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-picker@4.6.15(dayjs@1.11.13)(react-dom@18.2.0)(react@18.2.0): + rc-picker@4.6.15(dayjs@1.11.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - dayjs: 1.11.13 - rc-overflow: 1.3.2(react-dom@18.2.0)(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-overflow: 1.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) + optionalDependencies: + dayjs: 1.11.13 - rc-progress@4.0.0(react-dom@18.2.0)(react@18.2.0): + rc-progress@4.0.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-rate@2.13.0(react-dom@18.2.0)(react@18.2.0): + rc-rate@2.13.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-resize-observer@1.4.0(react-dom@18.2.0)(react@18.2.0): + rc-resize-observer@1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) resize-observer-polyfill: 1.5.1 - rc-segmented@2.3.0(react-dom@18.2.0)(react@18.2.0): + rc-segmented@2.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-select@14.15.2(react-dom@18.2.0)(react@18.2.0): + rc-select@14.15.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-overflow: 1.3.2(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) - rc-virtual-list: 3.14.8(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-overflow: 1.3.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-virtual-list: 3.14.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-slider@11.1.6(react-dom@18.2.0)(react@18.2.0): + rc-slider@11.1.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-steps@6.0.1(react-dom@18.2.0)(react@18.2.0): + rc-steps@6.0.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-switch@4.1.0(react-dom@18.2.0)(react@18.2.0): + rc-switch@4.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-table@7.45.7(react-dom@18.2.0)(react@18.2.0): + rc-table@7.45.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/context': 1.4.0(react-dom@18.2.0)(react@18.2.0) + '@rc-component/context': 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) - rc-virtual-list: 3.14.8(react-dom@18.2.0)(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-virtual-list: 3.14.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-tabs@15.1.1(react-dom@18.2.0)(react@18.2.0): + rc-tabs@15.1.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-dropdown: 4.2.0(react-dom@18.2.0)(react@18.2.0) - rc-menu: 9.14.1(react-dom@18.2.0)(react@18.2.0) - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-dropdown: 4.2.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-menu: 9.14.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-textarea@1.8.2(react-dom@18.2.0)(react@18.2.0): + rc-textarea@1.8.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-input: 1.6.3(react-dom@18.2.0)(react@18.2.0) - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-input: 1.6.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-tooltip@6.2.1(react-dom@18.2.0)(react@18.2.0): + rc-tooltip@6.2.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 - '@rc-component/trigger': 2.2.3(react-dom@18.2.0)(react@18.2.0) + '@rc-component/trigger': 2.2.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) classnames: 2.5.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-tree-select@5.23.0(react-dom@18.2.0)(react@18.2.0): + rc-tree-select@5.23.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-select: 14.15.2(react-dom@18.2.0)(react@18.2.0) - rc-tree: 5.9.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-select: 14.15.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-tree: 5.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-tree@5.9.0(react-dom@18.2.0)(react@18.2.0): + rc-tree@5.9.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-motion: 2.9.3(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) - rc-virtual-list: 3.14.8(react-dom@18.2.0)(react@18.2.0) + rc-motion: 2.9.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-virtual-list: 3.14.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-upload@4.7.0(react-dom@18.2.0)(react@18.2.0): + rc-upload@4.7.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - rc-util@5.43.0(react-dom@18.2.0)(react@18.2.0): + rc-util@5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-is: 18.3.1 - rc-virtual-list@3.14.8(react-dom@18.2.0)(react@18.2.0): + rc-virtual-list@3.14.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.25.7 classnames: 2.5.1 - rc-resize-observer: 1.4.0(react-dom@18.2.0)(react@18.2.0) - rc-util: 5.43.0(react-dom@18.2.0)(react@18.2.0) + rc-resize-observer: 1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + rc-util: 5.43.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) diff --git a/apps/frontend/src/app/collaboration/[id]/page.tsx b/apps/frontend/src/app/collaboration/[id]/page.tsx index 41c56023f0..83758ead95 100644 --- a/apps/frontend/src/app/collaboration/[id]/page.tsx +++ b/apps/frontend/src/app/collaboration/[id]/page.tsx @@ -13,6 +13,7 @@ import { TabsProps, Tag, Typography, + Spin, } from "antd"; import { Content } from "antd/es/layout/layout"; import "./styles.scss"; @@ -35,12 +36,15 @@ import CollaborativeEditor, { import { CreateOrUpdateHistory } from "@/app/services/history"; import { Language } from "@codemirror/language"; import { WebrtcProvider } from "y-webrtc"; +import { ExecuteVisibleAndCustomTests, ExecuteVisibleAndHiddenTestsAndSubmit, ExecutionResults, GetVisibleTests, isTestResult, SubmissionHiddenTestResultsAndStatus, SubmissionResults, Test, TestData, TestResult } from "@/app/services/execute"; interface CollaborationProps {} export default function CollaborationPage(props: CollaborationProps) { const router = useRouter(); const providerRef = useRef(null); + const submissionProviderRef = useRef(null); + const executionProviderRef = useRef(null); const editorRef = useRef(null); @@ -60,7 +64,7 @@ export default function CollaborationPage(props: CollaborationProps) { const [complexity, setComplexity] = useState(undefined); const [categories, setCategories] = useState([]); // Store the selected filter categories const [description, setDescription] = useState(undefined); - const [selectedLanguage, setSelectedLanguage] = useState("Javascript"); // State to hold the selected language item + const [selectedLanguage, setSelectedLanguage] = useState("Python"); // State to hold the selected language item // Session states const [collaborationId, setCollaborationId] = useState( @@ -82,10 +86,14 @@ export default function CollaborationPage(props: CollaborationProps) { undefined ); - // Manual test case states + // Test case states const [manualTestCase, setManualTestCase] = useState( undefined ); + const [visibleTestCases, setVisibleTestCases] = useState([]); + const [isLoadingTestCase, setIsLoadingTestCase] = useState(false); + const [isLoadingSubmission, setIsLoadingSubmission] = useState(false); + const [submissionHiddenTestResultsAndStatus, setSubmissionHiddenTestResultsAndStatus] = useState(undefined); // End Button Modal state const [isModalOpen, setIsModalOpen] = useState(false); @@ -141,34 +149,99 @@ export default function CollaborationPage(props: CollaborationProps) { }); }; - const sendCodeSavedStatusToMatchedUser = () => { + const infoMessage = (message: string) => { + messageApi.open({ + type: "info", + content: message, + }); + } + + const sendSubmissionResultsToMatchedUser = (data: SubmissionResults) => { if (!providerRef.current) { throw new Error("Provider not initialized"); } - providerRef.current.awareness.setLocalStateField("codeSavedStatus", true); - }; + providerRef.current.awareness.setLocalStateField("submissionResultsState", { + submissionResults: data, + id: Date.now(), + }); + } + + const sendExecutionResultsToMatchedUser = (data: ExecutionResults) => { + if (!providerRef.current) { + throw new Error("Provider not initialized"); + } + providerRef.current.awareness.setLocalStateField("executionResultsState", { + executionResults: data, + id: Date.now(), + }); + } + + const updateSubmissionResults = (data: SubmissionResults) => { + setSubmissionHiddenTestResultsAndStatus({ + hiddenTestResults: data.hiddenTestResults, + status: data.status, + }); + setVisibleTestCases(data.visibleTestResults); + } + + const updateExecutionResults = (data: ExecutionResults) => { + setVisibleTestCases(data.visibleTestResults); + } + + const handleRunTestCases = async () => { + if (!questionDocRefId) { + throw new Error("Question ID not found"); + } + + setIsLoadingTestCase(true); + try { + const data = await ExecuteVisibleAndCustomTests( + questionDocRefId, + { + code: code, + language: selectedLanguage, + customTestCases: "", + } + ); + setVisibleTestCases(data.visibleTestResults); + infoMessage("Test cases executed. Review the results below.") + sendExecutionResultsToMatchedUser(data); + } finally { + setIsLoadingTestCase(false); + } + } const handleSubmitCode = async () => { - if (!collaborationId) { - throw new Error("Collaboration ID not found"); + if (!questionDocRefId) { + throw new Error("Question ID not found"); + } + + setIsLoadingSubmission(true); + try { + const data = await ExecuteVisibleAndHiddenTestsAndSubmit( + questionDocRefId, + { + title: questionTitle ?? "", + code: code, + language: selectedLanguage, + user: currentUser ?? "", + matchedUser: matchedUser ?? "", + matchId: collaborationId ?? "", + matchedTopics: matchedTopics ?? [], + questionDifficulty: complexity ?? "", + questionTopics: categories, + } + ); + setVisibleTestCases(data.visibleTestResults); + setSubmissionHiddenTestResultsAndStatus({ + hiddenTestResults: data.hiddenTestResults, + status: data.status, + }); + sendSubmissionResultsToMatchedUser(data); + successMessage("Code saved successfully!"); + } finally { + setIsLoadingSubmission(false); } - const data = await CreateOrUpdateHistory( - { - title: questionTitle ?? "", - code: code, - language: selectedLanguage, - user: currentUser ?? "", - matchedUser: matchedUser ?? "", - matchId: collaborationId ?? "", - matchedTopics: matchedTopics ?? [], - questionDocRefId: questionDocRefId ?? "", - questionDifficulty: complexity ?? "", - questionTopics: categories, - }, - collaborationId - ); - successMessage("Code saved successfully!"); - sendCodeSavedStatusToMatchedUser(); }; const handleCodeChange = (code: string) => { @@ -204,6 +277,10 @@ export default function CollaborationPage(props: CollaborationProps) { setDescription(data.description); }); + GetVisibleTests(questionDocRefId).then((data: Test[]) => { + setVisibleTestCases(data); + }); + // Start stopwatch startStopwatch(); }, []); @@ -221,34 +298,44 @@ export default function CollaborationPage(props: CollaborationProps) { } }, [isSessionEndModalOpen, countDown]); - // Tabs component items for testcases - const items: TabsProps["items"] = [ - { - key: "1", - label: "Case 1", - children: ( - - ), // TODO: Setup test-cases in db for each qn and pull/paste here - }, - { - key: "2", - label: "Case 2", - children: ( - - ), - }, - { - key: "3", - label: "Case 3", + // Tabs component items for visibleTestCases + var items: TabsProps["items"] = visibleTestCases.map((item, index) => { + return { + key: index.toString(), + label: `Case ${index + 1}`, children: ( - setManualTestCase(e.target.value)} - placeholder="Input Manual Test Case" - rows={6} - /> +
+ + {isTestResult(item) && ( +
+ + + {item.passed ? "Passed" : "Failed"} + +
+ Actual Output: {item.actual} +
+ {item.error && ( + <> + Error: +
+ {item.error} +
+ + )} +
+ )} +
), - }, - ]; + }; + }); // Handles the cleaning of localstorage variables, stopping the timer & signalling collab user on webrtc // type: "initiator" | "peer" @@ -360,13 +447,19 @@ export default function CollaborationPage(props: CollaborationProps) { Test Cases {/* TODO: Link to execution service for running code against test-cases */} - +
+
+ {isLoadingTestCase && } +
+ +
@@ -383,13 +476,18 @@ export default function CollaborationPage(props: CollaborationProps) { Code
{/* TODO: Link to execution service for code submission */} - +
+
+ {isLoadingSubmission && } +
+ +
{collaborationId && currentUser && selectedLanguage && ( )} +
+ + + {submissionHiddenTestResultsAndStatus ? submissionHiddenTestResultsAndStatus.status : "Not Attempted"} + +
+ {submissionHiddenTestResultsAndStatus && ( + + Passed {submissionHiddenTestResultsAndStatus.hiddenTestResults.passed} / {submissionHiddenTestResultsAndStatus.hiddenTestResults.total} hidden test cases + + )} +
diff --git a/apps/frontend/src/app/collaboration/[id]/styles.scss b/apps/frontend/src/app/collaboration/[id]/styles.scss index 4f7b068e42..1d0ed44b31 100644 --- a/apps/frontend/src/app/collaboration/[id]/styles.scss +++ b/apps/frontend/src/app/collaboration/[id]/styles.scss @@ -22,12 +22,12 @@ } .question-row { - height: 60%; + height: 50%; padding: 1rem 0.25rem 0.25rem; } .test-row { - height: 40%; + height: 50%; padding: 0.25rem; } @@ -197,3 +197,39 @@ .info-modal-icon { color: red; } + +.test-button-container { + display: flex; + justify-content: flex-end; + align-items: center; + gap: 10px; + padding-left: 10px; + + .spinner-container { + width: 24px; + min-height: 24px; + display: flex; + align-items: center; + } +} + +.test-result-container { + margin-top: 10px; +} + +.hidden-test-icon { + margin-right: 5px; +} + +.error-message { + overflow-x: auto; + overflow-y: auto; // Allows vertical scroll if content exceeds max-height + white-space: nowrap; + max-width: 100%; + padding: 4px; + min-height: 50px; // Adjust height as needed + max-height: 150px; // Adjust max height for scrollable area + border: 1px solid #ddd; // Optional: add a border for visibility + border-radius: 4px; // Optional: round the corners slightly + background-color: #f9f9f9; // Optional: light background color +} diff --git a/apps/frontend/src/app/services/execute.ts b/apps/frontend/src/app/services/execute.ts new file mode 100644 index 0000000000..2b568f1a05 --- /dev/null +++ b/apps/frontend/src/app/services/execute.ts @@ -0,0 +1,127 @@ +const EXECUTION_SERVICE_URL = process.env.NEXT_PUBLIC_EXECUTION_SERVICE_URL; + +export interface TestData { + input: string + expected: string +} + +export interface TestResult { + input: string + expected: string + actual: string + passed: boolean + error: string +} + +export type Test = TestResult | TestData + +export const isTestResult = (test: Test): test is TestResult => { + return 'actual' in test && 'passed' in test && 'error' in test; +}; + +export interface GeneralTestResults { + passed: number; + total: number; +} + +export interface SubmissionHiddenTestResultsAndStatus { + hiddenTestResults: GeneralTestResults; + status: string; +} + +export interface SubmissionResults extends SubmissionHiddenTestResultsAndStatus { + visibleTestResults: TestResult[]; +} + +export interface ExecutionResults { + visibleTestResults: TestResult[]; + customTestResults: TestResult[]; +} + +export interface Code { + code: string; + language: string; + customTestCases: string; +} + +export interface Collaboration { + title: string + code: string + language: string + user: string + matchedUser: string + matchId: string + matchedTopics: string[] + questionDifficulty: string + questionTopics: string[] +} + +export const GetVisibleTests = async ( + questionDocRefId: string, +): Promise => { + const response = await fetch( + `${EXECUTION_SERVICE_URL}tests/${questionDocRefId}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + } + ); + + if (response.status === 200) { + return response.json(); + } else { + throw new Error( + `Error fetching test cases: ${response.status} ${response.statusText}` + ); + } +} + +export const ExecuteVisibleAndCustomTests = async ( + questionDocRefId: string, + code: Code, +): Promise => { + const response = await fetch( + `${EXECUTION_SERVICE_URL}tests/${questionDocRefId}/execute`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(code), + } + ); + + if (response.status === 200) { + return response.json(); + } else { + throw new Error( + `Error executing code: ${response.status} ${response.statusText}` + ); + } +} + +export const ExecuteVisibleAndHiddenTestsAndSubmit = async ( + questionDocRefId: string, + collaboration: Collaboration, +): Promise => { + const response = await fetch( + `${EXECUTION_SERVICE_URL}tests/${questionDocRefId}/submit`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(collaboration), + } + ); + + if (response.status === 200) { + return response.json(); + } else { + throw new Error( + `Error submitting code: ${response.status} ${response.statusText}` + ); + } +} diff --git a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx index 5fa8a88fe5..17c2d7b644 100644 --- a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx +++ b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx @@ -15,6 +15,8 @@ import * as Y from "yjs"; import { yCollab } from "y-codemirror.next"; import { WebrtcProvider } from "y-webrtc"; import { EditorView, basicSetup } from "codemirror"; +import { keymap } from "@codemirror/view" +import { indentWithTab } from "@codemirror/commands" import { EditorState, Compartment } from "@codemirror/state"; import { javascript, javascriptLanguage } from "@codemirror/lang-javascript"; import { python, pythonLanguage } from "@codemirror/lang-python"; @@ -25,6 +27,7 @@ import "./styles.scss"; import { message, Select } from "antd"; import { language } from "@codemirror/language"; import { ProgrammingLanguageOptions } from "@/utils/SelectOptions"; +import { ExecutionResults, SubmissionResults } from "@/app/services/execute"; interface CollaborativeEditorProps { user: string; @@ -35,6 +38,8 @@ interface CollaborativeEditorProps { providerRef: MutableRefObject; matchedUser: string; onCodeChange: (code: string) => void; + updateSubmissionResults: (results: SubmissionResults) => void; + updateExecutionResults: (results: ExecutionResults) => void; } export interface CollaborativeEditorHandle { @@ -54,7 +59,14 @@ interface Awareness { color: string; colorLight: string; }; - codeSavedStatus: boolean; + submissionResultsState: { + submissionResults: SubmissionResults; + id: number; + }; + executionResultsState: { + executionResults: ExecutionResults; + id: number; + } } export const usercolors = [ @@ -79,7 +91,7 @@ const CollaborativeEditor = forwardRef( ) => { const editorRef = useRef(null); // const providerRef = useRef(null); - const [selectedLanguage, setSelectedLanguage] = useState("JavaScript"); + const [selectedLanguage, setSelectedLanguage] = useState("Python"); let sessionEndNotified = false; const languageConf = new Compartment(); @@ -122,9 +134,10 @@ const CollaborativeEditor = forwardRef( languageLabel = "C++"; languageType = cppLanguage; } else { - newLanguage = javascript(); // Default to JavaScript - languageLabel = "JavaScript"; - languageType = javascriptLanguage; + // Default to Python + newLanguage = python(); + languageLabel = "Python"; + languageType = pythonLanguage; } const stateLanguage = tr.startState.facet(language); @@ -167,6 +180,9 @@ const CollaborativeEditor = forwardRef( }); }; + let latestExecutionId: number = (new Date(0)).getTime(); + let latestSubmissionId: number = (new Date(0)).getTime(); + useImperativeHandle(ref, () => ({ endSession: () => { if (props.providerRef.current) { @@ -237,7 +253,7 @@ const CollaborativeEditor = forwardRef( } }); - // Listener for awareness updates to receive status changes from peers + // Listener for awareness updates to receive submission results from peer provider.awareness.on("update", ({ added, updated }: AwarenessUpdate) => { added .concat(updated) @@ -246,8 +262,14 @@ const CollaborativeEditor = forwardRef( const state = provider.awareness .getStates() .get(clientID) as Awareness; - if (state && state.codeSavedStatus && !state.sessionEnded) { - // Display the received status message + + if ( + state && + state.submissionResultsState && + state.submissionResultsState.id !== latestSubmissionId + ) { + latestSubmissionId = state.submissionResultsState.id; + props.updateSubmissionResults(state.submissionResultsState.submissionResults); messageApi.open({ type: "success", content: `${ @@ -255,6 +277,21 @@ const CollaborativeEditor = forwardRef( } saved code successfully!`, }); } + + if ( + state && + state.executionResultsState && + state.executionResultsState.id !== latestExecutionId + ) { + latestExecutionId = state.executionResultsState.id; + props.updateExecutionResults(state.executionResultsState.executionResults); + messageApi.open({ + type: "info", + content: `${ + props.matchedUser ?? "Peer" + } executed test cases. Review the results below.`, + }); + } }); }); @@ -265,6 +302,7 @@ const CollaborativeEditor = forwardRef( languageConf.of(javascript()), autoLanguage, yCollab(ytext, provider.awareness, { undoManager }), + keymap.of([indentWithTab]), ], }); diff --git a/apps/frontend/src/middleware.ts b/apps/frontend/src/middleware.ts index 5ea9b2212a..a03d5af1c8 100644 --- a/apps/frontend/src/middleware.ts +++ b/apps/frontend/src/middleware.ts @@ -24,10 +24,10 @@ export default async function middleware(request: NextRequest) { return REDIRECT_TO_LOGIN; } - if (!await isValidToken(TOKEN.value)) { - REDIRECT_TO_LOGIN.cookies.delete("TOKEN"); - return REDIRECT_TO_LOGIN; - } + // if (!await isValidToken(TOKEN.value)) { + // REDIRECT_TO_LOGIN.cookies.delete("TOKEN"); + // return REDIRECT_TO_LOGIN; + // } return NextResponse.next(); From f32dd726fdbdc17c70898a90104e7182e0eb6762 Mon Sep 17 00:00:00 2001 From: solomonng2001 Date: Sun, 3 Nov 2024 23:27:10 +0800 Subject: [PATCH 129/258] Update submission and execution logic --- apps/execution-service/constants/constant.go | 22 +++++ apps/execution-service/handlers/submit.go | 35 ++++++++ apps/execution-service/models/testResult.go | 6 -- apps/execution-service/utils/executeTest.go | 26 ++---- apps/execution-service/utils/populate.go | 80 ++++++++++++++----- .../utils/validateTestCaseFormat.go | 8 -- 6 files changed, 124 insertions(+), 53 deletions(-) create mode 100644 apps/execution-service/constants/constant.go diff --git a/apps/execution-service/constants/constant.go b/apps/execution-service/constants/constant.go new file mode 100644 index 0000000000..46d3face08 --- /dev/null +++ b/apps/execution-service/constants/constant.go @@ -0,0 +1,22 @@ +package constants + +const ( + JAVA = "Java" + PYTHON = "Python" + GOLANG = "Golang" + JAVASCRIPT = "Javascript" + CPP = "C++" +) + +const ( + ACCEPTED = "Accepted" + ATTEMPTED = "Attempted" +) + +var IS_VALID_LANGUAGE = map[string]bool{ + PYTHON: true, + //JAVA: true, + //GOLANG: true, + //JAVASCRIPT: true, + //CPP: true, +} diff --git a/apps/execution-service/handlers/submit.go b/apps/execution-service/handlers/submit.go index c38c0fb094..20e15754e6 100644 --- a/apps/execution-service/handlers/submit.go +++ b/apps/execution-service/handlers/submit.go @@ -3,8 +3,10 @@ package handlers import ( "bytes" "encoding/json" + "execution-service/constants" "execution-service/models" "execution-service/utils" + "fmt" "github.com/go-chi/chi/v5" "google.golang.org/api/iterator" "net/http" @@ -26,6 +28,11 @@ func (s *Service) ExecuteVisibleAndHiddenTestsAndSubmit(w http.ResponseWriter, r return } + if err := validateCollaborationFields(collab); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + iter := s.Client.Collection("tests").Where("questionDocRefId", "==", questionDocRefId).Limit(1).Documents(ctx) doc, err := iter.Next() if err != nil { @@ -106,6 +113,34 @@ func (s *Service) ExecuteVisibleAndHiddenTestsAndSubmit(w http.ResponseWriter, r json.NewEncoder(w).Encode(testResults) } +func validateCollaborationFields(collab models.Collaboration) error { + if collab.Title == "" { + return fmt.Errorf("title is required") + } + + if !constants.IS_VALID_LANGUAGE[collab.Language] { + return fmt.Errorf("invalid language") + } + + if collab.User == "" { + return fmt.Errorf("user is required") + } + + if collab.MatchedUser == "" { + return fmt.Errorf("matchedUser is required") + } + + if collab.MatchID == "" { + return fmt.Errorf("matchId is required") + } + + if collab.QuestionDifficulty == "" { + return fmt.Errorf("questionDifficulty is required") + } + + return nil +} + //curl -X POST http://localhost:8083/tests/Yt29JjnIDpRwIlYAX8OF/submit \ //-H "Content-Type: application/json" \ //-d '{ diff --git a/apps/execution-service/models/testResult.go b/apps/execution-service/models/testResult.go index e0843acb72..1e812220d2 100644 --- a/apps/execution-service/models/testResult.go +++ b/apps/execution-service/models/testResult.go @@ -1,11 +1,5 @@ package models -type TestResults struct { - VisibleTestResults []IndividualTestResult `json:"visibleTestResults"` - HiddenTestResults GeneralTestResults `json:"hiddenTestResults"` - CustomTestResults []IndividualTestResult `json:"customTestResults"` -} - type ExecutionResults struct { VisibleTestResults []IndividualTestResult `json:"visibleTestResults"` CustomTestResults []IndividualTestResult `json:"customTestResults"` diff --git a/apps/execution-service/utils/executeTest.go b/apps/execution-service/utils/executeTest.go index b51051ca3e..b411ba7298 100644 --- a/apps/execution-service/utils/executeTest.go +++ b/apps/execution-service/utils/executeTest.go @@ -1,30 +1,18 @@ package utils import ( + "execution-service/constants" "execution-service/execution/python" "execution-service/models" "fmt" ) -const ( - JAVA = "Java" - PYTHON = "Python" - GOLANG = "Golang" - JAVASCRIPT = "Javascript" - CPP = "C++" -) - -const ( - ACCEPTED = "Accepted" - ATTEMPTED = "Attempted" -) - func ExecuteVisibleAndCustomTests(code models.Code, test models.Test) (models.ExecutionResults, error) { var err error var testResults models.ExecutionResults switch code.Language { - case PYTHON: + case constants.PYTHON: testResults, err = getVisibleAndCustomTestResults(code, test, python.RunPythonCode) break default: @@ -42,7 +30,7 @@ func ExecuteVisibleAndHiddenTests(code models.Code, test models.Test) (models.Su var testResults models.SubmissionResults switch code.Language { - case PYTHON: + case constants.PYTHON: testResults, err = getVisibleAndHiddenTestResults(code, test, python.RunPythonCode) break default: @@ -143,14 +131,14 @@ func getVisibleAndHiddenTestResults(code models.Code, test models.Test, return models.SubmissionResults{}, err } - status := ACCEPTED + status := constants.ACCEPTED if hiddenTestResults.Passed != hiddenTestResults.Total { - status = ATTEMPTED + status = constants.ATTEMPTED } - if status == ACCEPTED { + if status == constants.ACCEPTED { for _, testResult := range visibleTestResults { if !testResult.Passed { - status = ATTEMPTED + status = constants.ATTEMPTED break } } diff --git a/apps/execution-service/utils/populate.go b/apps/execution-service/utils/populate.go index df1c386a5e..bff45c414e 100644 --- a/apps/execution-service/utils/populate.go +++ b/apps/execution-service/utils/populate.go @@ -34,9 +34,11 @@ func RepopulateTests(ctx context.Context, client *firestore.Client, { QuestionTitle: "Reverse a String", VisibleTestCases: ` -1 +2 hello olleh +Hannah +hannaH `, HiddenTestCases: ` 2 @@ -55,9 +57,11 @@ return len(inputOrOutput) > 0 { QuestionTitle: "Linked List Cycle Detection", VisibleTestCases: ` -1 +2 [3,2,0,-4] -> pos = 1 true +[1] +false `, HiddenTestCases: ` 2 @@ -119,9 +123,11 @@ return inputOrOutput == "true" || inputOrOutput == "false" { QuestionTitle: "Roman to Integer", VisibleTestCases: ` -1 +2 III 3 +IV +4 `, HiddenTestCases: ` 2 @@ -147,9 +153,11 @@ return err == nil { QuestionTitle: "Add Binary", VisibleTestCases: ` -1 +2 "11", "1" "100" +"1010", "1011" +"10101" `, HiddenTestCases: ` 2 @@ -170,9 +178,11 @@ return binaryRegex.MatchString(inputOrOutput) { QuestionTitle: "Fibonacci Number", VisibleTestCases: ` -1 +2 0 0 +10 +55 `, HiddenTestCases: ` 2 @@ -193,9 +203,11 @@ return err == nil && num >= 0 { QuestionTitle: "Implement Stack using Queues", VisibleTestCases: ` -1 +2 push(1), push(2), top() 2 +push(1), empty() +false `, HiddenTestCases: ` 2 @@ -233,9 +245,11 @@ return err == nil }, { QuestionTitle: "Combine Two Tables", VisibleTestCases: ` -1 +2 Person: [(1, "Smith", "John"), (2, "Doe", "Jane")], Address: [(1, 1, "NYC", "NY"), (2, 3, "LA", "CA")] [("John", "Smith", "NYC", "NY"), ("Jane", "Doe", null, null)] +Person: [(1, "White", "Mary")], Address: [] +[("Mary", "White", null, null)] `, HiddenTestCases: ` 2 @@ -254,9 +268,11 @@ return len(inputOrOutput) > 0 { QuestionTitle: "Repeated DNA Sequences", VisibleTestCases: ` -1 +2 AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT ["AAAAACCCCC", "CCCCCAAAAA"] +ACGTACGTACGT +[] `, HiddenTestCases: ` 2 @@ -318,9 +334,11 @@ return true { QuestionTitle: "Course Schedule", VisibleTestCases: ` -1 +2 2, [[1,0]] true +2, [[1,0],[0,1]] +false `, HiddenTestCases: ` 2 @@ -339,9 +357,11 @@ return len(inputOrOutput) > 0 { QuestionTitle: "LRU Cache Design", VisibleTestCases: ` -1 +2 put(1, 1), put(2, 2), get(1) 1 +put(1, 1), put(2, 2), put(3, 3), get(2) +-1 `, HiddenTestCases: ` 2 @@ -360,9 +380,11 @@ return len(inputOrOutput) > 0 { QuestionTitle: "Longest Common Subsequence", VisibleTestCases: ` -1 +2 "abcde", "ace" 3 +"abc", "def" +0 `, HiddenTestCases: ` 2 @@ -381,9 +403,11 @@ return len(inputOrOutput) > 0 { QuestionTitle: "Rotate Image", VisibleTestCases: ` -1 +2 [[1,2,3],[4,5,6],[7,8,9]] [[7,4,1],[8,5,2],[9,6,3]] +[[1]] +[[1]] `, HiddenTestCases: ` 2 @@ -402,9 +426,11 @@ return len(inputOrOutput) > 0 { QuestionTitle: "Airplane Seat Assignment Probability", VisibleTestCases: ` -1 +2 1 1.00000 +3 +0.50000 `, HiddenTestCases: ` 2 @@ -423,9 +449,11 @@ return len(inputOrOutput) > 0 { QuestionTitle: "Validate Binary Search Tree", VisibleTestCases: ` -1 +2 [2,1,3] true +[5,1,4,null,null,3,6] +false `, HiddenTestCases: ` 2 @@ -444,9 +472,11 @@ return len(inputOrOutput) > 0 { QuestionTitle: "Sliding Window Maximum", VisibleTestCases: ` -1 +2 [1,3,-1,-3,5,3,6,7], k=3 [3,3,5,5,6,7] +[9, 11], k=2 +[11] `, HiddenTestCases: ` 2 @@ -465,9 +495,11 @@ return len(inputOrOutput) > 0 { QuestionTitle: "N-Queen Problem", VisibleTestCases: ` -1 +2 4 [[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]] +2 +[] `, HiddenTestCases: ` 2 @@ -486,9 +518,11 @@ return len(inputOrOutput) > 0 { QuestionTitle: "Serialize and Deserialize a Binary Tree", VisibleTestCases: ` -1 +2 [1,2,3,null,null,4,5] "1 2 null null 3 4 null null 5 null null" +[] +"null" `, HiddenTestCases: ` 2 @@ -507,9 +541,11 @@ return len(inputOrOutput) > 0 { QuestionTitle: "Wildcard Matching", VisibleTestCases: ` -1 +2 "aa", "a" false +"aa", "*" +true `, HiddenTestCases: ` 2 @@ -528,9 +564,11 @@ return len(inputOrOutput) > 0 { QuestionTitle: "Chalkboard XOR Game", VisibleTestCases: ` -1 +2 [1,1,2] false +[1,2,3] +true `, HiddenTestCases: ` 2 @@ -549,9 +587,11 @@ return len(inputOrOutput) > 0 { QuestionTitle: "Trips and Users", VisibleTestCases: ` -1 +2 Trips: [(1, 1, 10, 'NYC', 'completed', '2013-10-01'), (2, 2, 11, 'NYC', 'cancelled_by_driver', '2013-10-01')],Users: [(10, 'No', 'client'), (11, 'No', 'driver')] 0.50 +Trips: [(1, 1, 10, 'NYC', 'completed', '2013-10-03'), (2, 2, 11, 'NYC', 'cancelled_by_client', '2013-10-03')],Users: [(10, 'No', 'client'), (11, 'Yes', 'driver')] +0.00 `, HiddenTestCases: ` 2 diff --git a/apps/execution-service/utils/validateTestCaseFormat.go b/apps/execution-service/utils/validateTestCaseFormat.go index ef03752a1b..e38e0881b4 100644 --- a/apps/execution-service/utils/validateTestCaseFormat.go +++ b/apps/execution-service/utils/validateTestCaseFormat.go @@ -30,10 +30,7 @@ func ValidateTestCaseFormat(testCase string, validateInputCode string, validateO len(lines)) } - println("test1") - for i := 1; i < len(lines); i += 2 { - println("test2") ok, err := validateInputOrOutputFormat(validateInputCode, lines[i]) if err != nil { return false, fmt.Errorf("error validating input: %v", err) @@ -41,7 +38,6 @@ func ValidateTestCaseFormat(testCase string, validateInputCode string, validateO if !ok { return false, fmt.Errorf("test case format is incorrect, input format is invalid") } - println("test3") ok, err = validateInputOrOutputFormat(validateOutputCode, lines[i+1]) if err != nil { return false, fmt.Errorf("error validating output: %v", err) @@ -49,9 +45,7 @@ func ValidateTestCaseFormat(testCase string, validateInputCode string, validateO if !ok { return false, fmt.Errorf("test case format is incorrect, output format is invalid") } - println("test4") } - println("test5") return true, nil } @@ -67,8 +61,6 @@ package main %s `, validateInputOrOutputCode) - println(fullCode) - // Evaluate the function code _, err := i.Eval(fullCode) if err != nil { From fdb4c1aae569a5dc8eba5e54cd290f8ce947db17 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 3 Nov 2024 23:33:05 +0800 Subject: [PATCH 130/258] add "unit test" for ReadQuestion --- apps/question-service/tests/read_test.go | 71 ++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 apps/question-service/tests/read_test.go diff --git a/apps/question-service/tests/read_test.go b/apps/question-service/tests/read_test.go new file mode 100644 index 0000000000..6f6f19afad --- /dev/null +++ b/apps/question-service/tests/read_test.go @@ -0,0 +1,71 @@ +package tests + +import ( + "context" + "fmt" + "log" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "question-service/handlers" + "strings" + "testing" + + "cloud.google.com/go/firestore" + firebase "firebase.google.com/go/v4" + "github.com/go-chi/chi/v5" + "github.com/joho/godotenv" + "google.golang.org/api/option" +) + +func createService(t testing.TB) *handlers.Service { + err := godotenv.Load(filepath.Join("../", ".env")) + if err != nil { + log.Fatalf("Error loading .env file") + } + + ctx := context.Background() + client, err := initFirestore(ctx) + + if err != nil { + t.Fatalf("failed to initialize Firestore: %v", err) + } + + return &handlers.Service{Client: client} +} + +// initFirestore initializes the Firestore client +func initFirestore(ctx context.Context) (*firestore.Client, error) { + credentialsPath := "../" + os.Getenv("FIREBASE_CREDENTIAL_PATH") + opt := option.WithCredentialsFile(credentialsPath) + app, err := firebase.NewApp(ctx, nil, opt) + if err != nil { + return nil, fmt.Errorf("failed to initialize Firebase App: %v", err) + } + + client, err := app.Firestore(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get Firestore client: %v", err) + } + return client, nil +} + +func Test_Read(t *testing.T) { + service := createService(t) + res := httptest.NewRecorder() + + // adds chi context + // https://stackoverflow.com/questions/54580582/testing-chi-routes-w-path-variables + rctx := chi.NewRouteContext() + rctx.URLParams.Add("docRefID", "6SdbW4Awcfm5x0UQtWmg") + + req := httptest.NewRequest(http.MethodGet, "http://localhost:8080/questions/6SdbW4Awcfm5x0UQtWmg", strings.NewReader("")) + req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) + + service.ReadQuestion(res, req) + + if res.Result().StatusCode != 200 { + t.Fatalf("expected status code 200 but got %v", res.Result()) + } +} From ca7864d05d534f8120c1d46a90150f00ce1e9323 Mon Sep 17 00:00:00 2001 From: solomonng2001 Date: Sun, 3 Nov 2024 23:38:20 +0800 Subject: [PATCH 131/258] Update README APIs --- apps/execution-service/README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/execution-service/README.md b/apps/execution-service/README.md index fc84f1647a..d0263d82f2 100644 --- a/apps/execution-service/README.md +++ b/apps/execution-service/README.md @@ -25,7 +25,7 @@ The server will be available at http://localhost:8083. To run the application via Docker, run the following command: ```bash -docker build -t question-service . +docker build -t execution-service . ``` ```bash @@ -38,7 +38,8 @@ The server will be available at http://localhost:8083. - `POST /tests/populate` - `GET /tests/{questionDocRefId}/` -- `GET /tests/{questionDocRefId}/execute` +- `POST /tests/{questionDocRefId}/execute` +- `POST /tests/{questionDocRefId}/submit` ## Managing Firebase @@ -80,7 +81,7 @@ The following json format will be returned: ] ``` -`GET /tests/{questionDocRefId}/execute` +`POST /tests/{questionDocRefId}/execute` To execute test cases via a question ID without custom test cases, run the following command, with custom code and language: @@ -154,6 +155,8 @@ The following json format will be returned: } ``` +`POST /tests/{questionDocRefId}/submit` + To submit a solution and execute visible and hidden test cases via a question ID, run the following command, with custom code and language: ```bash From d047aa17183051a07c09a79881500c4a2d0fc001 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 3 Nov 2024 23:42:59 +0800 Subject: [PATCH 132/258] add test for not found --- apps/question-service/tests/read_test.go | 40 +++++++++++++++++++----- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/apps/question-service/tests/read_test.go b/apps/question-service/tests/read_test.go index 6f6f19afad..7849bc1495 100644 --- a/apps/question-service/tests/read_test.go +++ b/apps/question-service/tests/read_test.go @@ -19,17 +19,15 @@ import ( "google.golang.org/api/option" ) -func createService(t testing.TB) *handlers.Service { - err := godotenv.Load(filepath.Join("../", ".env")) - if err != nil { - log.Fatalf("Error loading .env file") - } +var service *handlers.Service + +func createService() *handlers.Service { ctx := context.Background() client, err := initFirestore(ctx) if err != nil { - t.Fatalf("failed to initialize Firestore: %v", err) + log.Fatalf("failed to initialize Firestore: %v", err) } return &handlers.Service{Client: client} @@ -51,8 +49,18 @@ func initFirestore(ctx context.Context) (*firestore.Client, error) { return client, nil } +func TestMain(m *testing.M) { + err := godotenv.Load(filepath.Join("../", ".env")) + if err != nil { + log.Fatalf("Error loading .env file") + } + service = createService() + defer service.Client.Close() + exitCode := m.Run() + os.Exit(exitCode) +} + func Test_Read(t *testing.T) { - service := createService(t) res := httptest.NewRecorder() // adds chi context @@ -69,3 +77,21 @@ func Test_Read(t *testing.T) { t.Fatalf("expected status code 200 but got %v", res.Result()) } } + +func Test_ReadNotFound(t *testing.T) { + res := httptest.NewRecorder() + + // adds chi context + // https://stackoverflow.com/questions/54580582/testing-chi-routes-w-path-variables + rctx := chi.NewRouteContext() + rctx.URLParams.Add("docRefID", "not-found-docref") + + req := httptest.NewRequest(http.MethodGet, "http://localhost:8080/questions/not-found-docref", strings.NewReader("")) + req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) + + service.ReadQuestion(res, req) + + if res.Result().StatusCode != 404 { + t.Fatalf("expected status code 404 but got response %v", res.Result()) + } +} From ba541a560dc69223eaf51ddc812e31f23857428b Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 3 Nov 2024 23:49:25 +0800 Subject: [PATCH 133/258] update workflow to add credentials --- .github/workflows/test.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a436f34556..bf7182da60 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,7 +22,16 @@ jobs: - name: Set up .env run: | - echo ./apps/question-service/.env.example > .env + cd ./apps/question-service + echo .env.example > .env + + - name: Set up credentials + env: + QUESTION_FIREBASE_JSON: ${{ secrets.QUESTION_SERVICE_FIREBASE_CREDENTIAL }} + QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} + run: | + cd ./apps/question-service + echo "$QUESTION_FIREBASE_JSON" > "./$QUESTION_FIREBASE_CREDENTIAL_PATH" - name: Setup Go uses: actions/setup-go@v5 From 3d66e85a35492a1de141abfd0473e2177b0da5e7 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Sun, 3 Nov 2024 23:57:25 +0800 Subject: [PATCH 134/258] fix: use historyDocRefId --- apps/frontend/src/app/collaboration/[id]/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/src/app/collaboration/[id]/page.tsx b/apps/frontend/src/app/collaboration/[id]/page.tsx index ee538edbf2..c3aefc9af4 100644 --- a/apps/frontend/src/app/collaboration/[id]/page.tsx +++ b/apps/frontend/src/app/collaboration/[id]/page.tsx @@ -152,7 +152,7 @@ export default function CollaborationPage(props: CollaborationProps) { language: selectedLanguage, user: currentUser ?? "", matchedUser: matchedUser ?? "", - matchId: collaborationId ?? "", + historyDocRefId: collaborationId ?? "", matchedTopics: matchedTopics ?? [], questionDocRefId: questionDocRefId ?? "", questionDifficulty: complexity ?? "", From 89577e4fc9a5a7cc144309d341e027f3603eb109 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Mon, 4 Nov 2024 00:00:06 +0800 Subject: [PATCH 135/258] asd --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bf7182da60..6ce939d68a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,6 +46,7 @@ jobs: - name: Run tests run: | cd ./apps/question-service + tree . go test ./... test: From 07131a85bdb2eae99c5aefc37b8e04e9d712d0fe Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Mon, 4 Nov 2024 00:02:47 +0800 Subject: [PATCH 136/258] asd2 --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6ce939d68a..01be69b8c6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,7 +23,7 @@ jobs: - name: Set up .env run: | cd ./apps/question-service - echo .env.example > .env + cp .env.example .env - name: Set up credentials env: @@ -46,7 +46,7 @@ jobs: - name: Run tests run: | cd ./apps/question-service - tree . + tree -a . go test ./... test: From f1a0e366c9224cffc15201ce8535c7d0da6a3e11 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Mon, 4 Nov 2024 00:12:58 +0800 Subject: [PATCH 137/258] asd3 --- .github/workflows/test.yml | 3 ++- apps/question-service/tests/killme2_test.go | 30 +++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 apps/question-service/tests/killme2_test.go diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 01be69b8c6..bc23adf91a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,7 +46,8 @@ jobs: - name: Run tests run: | cd ./apps/question-service - tree -a . + cat .env + cat cs3219-g24-firebase-adminsdk-9cm7h-b1675603ab.json go test ./... test: diff --git a/apps/question-service/tests/killme2_test.go b/apps/question-service/tests/killme2_test.go new file mode 100644 index 0000000000..39ab1ed329 --- /dev/null +++ b/apps/question-service/tests/killme2_test.go @@ -0,0 +1,30 @@ +package tests + +import ( + "fmt" + "net/http" + "net/http/httptest" + "os" + "strings" + "testing" +) + +func Test2(t *testing.T) { + err := os.Setenv("FIRESTORE_EMULATOR_HOST", "localhost:9000") + + if err != nil { + t.Fatalf("failed to setup env") + } + + service := createService() + response := httptest.NewRecorder() + + service.ReadQuestion( + response, + httptest.NewRequest(http.MethodGet, "/questions/6SdbW4Awcfm5x0UQtWmg", strings.NewReader("")), + ) + fmt.Printf("%v", response.Result()) +} + +// func TestMain +// func createService() From 0208df53e754e811e929c84c31a8b7f032880017 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Mon, 4 Nov 2024 00:17:09 +0800 Subject: [PATCH 138/258] asd3 --- .github/workflows/test.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bc23adf91a..8523a3832a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,9 +21,14 @@ jobs: uses: actions/checkout@v2 - name: Set up .env + env: + QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} + JWT_SECRET: ${{ secrets.JWT_SECRET }} run: | cd ./apps/question-service - cp .env.example .env + + echo "FIREBASE_CREDENTIAL_PATH=$QUESTION_FIREBASE_CREDENTIAL_PATH" >> .env + echo "JWT_SECRET=$JWT_SECRET" >> .env - name: Set up credentials env: From 77b8d46cc73ee23ca154aef732e3e6e0869ea5a1 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Mon, 4 Nov 2024 00:19:38 +0800 Subject: [PATCH 139/258] asd4 --- .github/workflows/test.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8523a3832a..4bba203616 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -51,8 +51,6 @@ jobs: - name: Run tests run: | cd ./apps/question-service - cat .env - cat cs3219-g24-firebase-adminsdk-9cm7h-b1675603ab.json go test ./... test: From 221d7374184b9f107d429299179c38c3c97d8fc4 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Mon, 4 Nov 2024 00:31:24 +0800 Subject: [PATCH 140/258] remove file --- apps/question-service/tests/killme2_test.go | 30 --------------------- 1 file changed, 30 deletions(-) delete mode 100644 apps/question-service/tests/killme2_test.go diff --git a/apps/question-service/tests/killme2_test.go b/apps/question-service/tests/killme2_test.go deleted file mode 100644 index 39ab1ed329..0000000000 --- a/apps/question-service/tests/killme2_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package tests - -import ( - "fmt" - "net/http" - "net/http/httptest" - "os" - "strings" - "testing" -) - -func Test2(t *testing.T) { - err := os.Setenv("FIRESTORE_EMULATOR_HOST", "localhost:9000") - - if err != nil { - t.Fatalf("failed to setup env") - } - - service := createService() - response := httptest.NewRecorder() - - service.ReadQuestion( - response, - httptest.NewRequest(http.MethodGet, "/questions/6SdbW4Awcfm5x0UQtWmg", strings.NewReader("")), - ) - fmt.Printf("%v", response.Result()) -} - -// func TestMain -// func createService() From 259e4620290f14673c974a4d9ca48f7c62150845 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Mon, 4 Nov 2024 01:30:50 +0800 Subject: [PATCH 141/258] feat: clickable row entries --- .../src/app/collaboration/[id]/page.tsx | 4 +- apps/frontend/src/app/question/[id]/page.tsx | 179 +++++++++--------- apps/frontend/src/app/services/history.ts | 19 +- 3 files changed, 102 insertions(+), 100 deletions(-) diff --git a/apps/frontend/src/app/collaboration/[id]/page.tsx b/apps/frontend/src/app/collaboration/[id]/page.tsx index c3aefc9af4..840614f4f9 100644 --- a/apps/frontend/src/app/collaboration/[id]/page.tsx +++ b/apps/frontend/src/app/collaboration/[id]/page.tsx @@ -25,7 +25,7 @@ import { import CollaborativeEditor, { CollaborativeEditorHandle, } from "@/components/CollaborativeEditor/CollaborativeEditor"; -import { CreateOrUpdateHistory } from "@/app/services/history"; +import { CreateHistory } from "@/app/services/history"; import { WebrtcProvider } from "y-webrtc"; import { QuestionDetailFull } from "@/components/question/QuestionDetailFull/QuestionDetailFull"; @@ -145,7 +145,7 @@ export default function CollaborationPage(props: CollaborationProps) { if (!collaborationId) { throw new Error("Collaboration ID not found"); } - const data = await CreateOrUpdateHistory( + const data = await CreateHistory( { title: questionTitle ?? "", code: code, diff --git a/apps/frontend/src/app/question/[id]/page.tsx b/apps/frontend/src/app/question/[id]/page.tsx index 23616cd404..ff0d4512f6 100644 --- a/apps/frontend/src/app/question/[id]/page.tsx +++ b/apps/frontend/src/app/question/[id]/page.tsx @@ -1,38 +1,15 @@ "use client"; import Header from "@/components/Header/header"; -import { - Button, - Col, - Layout, - message, - Row, - Tag, - Select, - Table, - Input, -} from "antd"; +import { Col, Layout, message, Row, Table } from "antd"; import { Content } from "antd/es/layout/layout"; -import { - LeftOutlined, - RightOutlined, - CaretRightOutlined, - CodeOutlined, - SendOutlined, - HistoryOutlined, -} from "@ant-design/icons"; +import { CodeOutlined, HistoryOutlined } from "@ant-design/icons"; import "./styles.scss"; import { useEffect, useRef, useState } from "react"; import { GetSingleQuestion } from "../../services/question"; import React from "react"; -import TextArea from "antd/es/input/TextArea"; import { useSearchParams } from "next/navigation"; -import { ProgrammingLanguageOptions } from "@/utils/SelectOptions"; import { useRouter } from "next/navigation"; import { QuestionDetailFull } from "@/components/question/QuestionDetailFull/QuestionDetailFull"; -import CollaborativeEditor, { - CollaborativeEditorHandle, -} from "@/components/CollaborativeEditor/CollaborativeEditor"; -import { WebrtcProvider } from "y-webrtc"; import { Compartment, EditorState } from "@codemirror/state"; import { basicSetup, EditorView } from "codemirror"; import { javascript } from "@codemirror/lang-javascript"; @@ -44,6 +21,7 @@ interface Submission { language: string; matchedUser: string; code: string; + historyDocRefId: string; } export default function QuestionPage() { @@ -73,10 +51,14 @@ export default function QuestionPage() { const [complexity, setComplexity] = useState(undefined); const [categories, setCategories] = useState([]); // Store the selected filter categories const [description, setDescription] = useState(undefined); - const [username, setUsername] = useState(""); + const [username, setUsername] = useState(undefined); const [userQuestionHistories, setUserQuestionHistories] = useState(); const [submission, setSubmission] = useState(); + const [isHistoryLoading, setIsHistoryLoading] = useState(true); + const [currentSubmissionId, setCurrentSubmissionId] = useState< + string | undefined + >(undefined); const state = EditorState.create({ doc: "", @@ -107,6 +89,18 @@ export default function QuestionPage() { }); }, [docRefId]); + useEffect(() => { + if (username === undefined) return; + GetUserQuestionHistories(username, docRefId) + .then((data: any) => { + console.log(data); + setUserQuestionHistories(data); + }) + .finally(() => { + setIsHistoryLoading(false); + }); + }, [username]); + useEffect(() => { ValidateUser().then((data: VerifyTokenResponseType) => { setUsername(data.data.username); @@ -114,22 +108,27 @@ export default function QuestionPage() { }, []); useEffect(() => { + if (currentSubmissionId === undefined) return; + const view = new EditorView({ state, parent: editorRef.current || undefined, }); // TODO: get from a specific history which was selected. - GetHistory("182d0ae6db66fdbefb657f09df3a44a8").then((data: any) => { + // Show latest history by default, or load specific history + GetHistory(currentSubmissionId).then((data: any) => { + const submittedAt = new Date(data.createdAt); setSubmission({ - submittedAt: data.createdAt, + submittedAt: submittedAt.toLocaleString("en-US"), language: data.language, matchedUser: data.matchedUser, code: data.code, + historyDocRefId: data.historyDocRefId, }); view.dispatch( - view.state.update({ + state.update({ changes: { from: 0, to: state.doc.length, insert: data.code }, }) ); @@ -139,23 +138,11 @@ export default function QuestionPage() { // Cleanup on component unmount view.destroy(); }; - }, []); - - useEffect(() => { - GetUserQuestionHistories(username, docRefId).then((data: any) => { - setUserQuestionHistories(data); - }); - }, [docRefId, username]); - - useEffect(() => { - GetUserQuestionHistories(username, docRefId).then((data: any) => { - setUserQuestionHistories(data); - }); - }, [docRefId, username]); + }, [currentSubmissionId]); const columns = [ { - title: "Id", + title: "ID", dataIndex: "id", key: "id", }, @@ -163,6 +150,9 @@ export default function QuestionPage() { title: "Submitted at", dataIndex: "createdAt", key: "createdAt", + render: (date: string) => { + return new Date(date).toLocaleString(); + }, }, { title: "Language", @@ -176,6 +166,10 @@ export default function QuestionPage() { }, ]; + const handleRowClick = (s: Submission) => { + setCurrentSubmissionId(s.historyDocRefId); + }; + return (
{contextHolder} @@ -206,56 +200,67 @@ export default function QuestionPage() { rowKey="id" dataSource={userQuestionHistories} columns={columns} - loading={isLoading} + onRow={(record: any) => { + return { + onClick: () => handleRowClick(record), + style: { cursor: "pointer" }, + }; + }} + loading={isHistoryLoading} />
- -
-
-
- - Submitted Code -
-
-
-
- Submitted at: {submission?.submittedAt || "-"} -
-
- Language: {submission?.language || "-"} -
-
- Matched with: {submission?.matchedUser || "-"} -
-
+ {currentSubmissionId && ( + +
+ <> +
+
+ + Submitted Code +
+
- {/* TODO: add details of attempt here */} - {/* TODO: set value of code, refactor to look like collab editor but not editable */} -
-
+ {/* Details of submission */} +
+
+ Submitted at: {submission?.submittedAt || "-"} +
+
+ Language: {submission?.language || "-"} +
+
+ Matched with: {submission?.matchedUser || "-"} +
+
+ + {/* Code Editor */} +
+
+
+
-
-
+ + )} diff --git a/apps/frontend/src/app/services/history.ts b/apps/frontend/src/app/services/history.ts index b007d832f7..a2e52bcaf5 100644 --- a/apps/frontend/src/app/services/history.ts +++ b/apps/frontend/src/app/services/history.ts @@ -15,20 +15,17 @@ export interface History { updatedAt?: string; } -export const CreateOrUpdateHistory = async ( +export const CreateHistory = async ( history: History, historyDocRefId: string ): Promise => { - const response = await fetch( - `${HISTORY_SERVICE_URL}histories/${historyDocRefId}`, - { - method: "PUT", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(history), - } - ); + const response = await fetch(`${HISTORY_SERVICE_URL}histories/`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(history), + }); if (response.status === 200) { return response.json(); From 657a29d9bdea3023b41d8d03ff3743a6c6aa7238 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Mon, 4 Nov 2024 01:47:09 +0800 Subject: [PATCH 142/258] feat: modify create so that history is always created --- apps/history-service/handlers/create.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/history-service/handlers/create.go b/apps/history-service/handlers/create.go index 1dd7e6efd8..6290a44d28 100644 --- a/apps/history-service/handlers/create.go +++ b/apps/history-service/handlers/create.go @@ -22,9 +22,9 @@ func (s *Service) CreateHistory(w http.ResponseWriter, r *http.Request) { } // Document reference ID in firestore mapped to the match ID in model - docRef := s.Client.Collection("collaboration-history").Doc(collaborationHistory.HistoryDocRefID) + collection := s.Client.Collection("collaboration-history") - _, err := docRef.Set(ctx, map[string]interface{}{ + docRef, _, err := collection.Add(ctx, map[string]interface{}{ "title": collaborationHistory.Title, "code": collaborationHistory.Code, "language": collaborationHistory.Language, From da6001db322f0a49d25814ae86a40c3877735013 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Mon, 4 Nov 2024 02:06:20 +0800 Subject: [PATCH 143/258] fix test.yml --- .github/workflows/test.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d60f288d27..18b5fad0df 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -54,15 +54,21 @@ jobs: go test ./... frontend-unit-tests: - - name: Set up Node.js - uses: actions/setup-node@v2 - with: - node-version: '22' + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 - name: Setup .env run: | cd ./apps/frontend cp .env.example .env + + - name: Set up Node.js + uses: actions/setup-node@v2 + with: + node-version: '22' - name: Install pnpm run: npm i -g pnpm From 1ae0f5bc54ecc6d6de50537362661dc45fa0e23b Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Mon, 4 Nov 2024 02:09:08 +0800 Subject: [PATCH 144/258] feat: order by created at desc --- apps/history-service/handlers/createOrUpdate.go | 1 + apps/history-service/handlers/delete.go | 2 +- .../handlers/listquestionhistory.go | 15 +++++++++++++-- apps/history-service/handlers/listuserhistory.go | 13 +++++++++++-- apps/history-service/handlers/update.go | 2 +- 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/apps/history-service/handlers/createOrUpdate.go b/apps/history-service/handlers/createOrUpdate.go index 1c3ba5d352..561c463d43 100644 --- a/apps/history-service/handlers/createOrUpdate.go +++ b/apps/history-service/handlers/createOrUpdate.go @@ -13,6 +13,7 @@ import ( "google.golang.org/grpc/status" ) +// Unused func (s *Service) CreateOrUpdateHistory(w http.ResponseWriter, r *http.Request) { ctx := r.Context() diff --git a/apps/history-service/handlers/delete.go b/apps/history-service/handlers/delete.go index f528e4bc34..29121908d7 100644 --- a/apps/history-service/handlers/delete.go +++ b/apps/history-service/handlers/delete.go @@ -8,7 +8,7 @@ import ( "google.golang.org/grpc/status" ) -// Delete a code snippet by ID +// Delete a code snippet by ID: unused func (s *Service) DeleteHistory(w http.ResponseWriter, r *http.Request) { ctx := r.Context() diff --git a/apps/history-service/handlers/listquestionhistory.go b/apps/history-service/handlers/listquestionhistory.go index 3f0d7153a8..999a04993c 100644 --- a/apps/history-service/handlers/listquestionhistory.go +++ b/apps/history-service/handlers/listquestionhistory.go @@ -5,6 +5,7 @@ import ( "history-service/models" "net/http" + "cloud.google.com/go/firestore" "github.com/go-chi/chi/v5" "google.golang.org/api/iterator" ) @@ -20,8 +21,14 @@ func (s *Service) ListUserQuestionHistories(w http.ResponseWriter, r *http.Reque collRef := s.Client.Collection("collaboration-history") // Query data - iterUser := collRef.Where("user", "==", username).Where("questionDocRefId", "==", questionDocRefID).Documents(ctx) - iterMatchedUser := collRef.Where("matchedUser", "==", username).Where("questionDocRefId", "==", questionDocRefID).Documents(ctx) + iterUser := collRef.Where("user", "==", username). + Where("questionDocRefId", "==", questionDocRefID). + OrderBy("createdAt", firestore.Desc). + Documents(ctx) + iterMatchedUser := collRef.Where("matchedUser", "==", username). + Where("questionDocRefId", "==", questionDocRefID). + OrderBy("createdAt", firestore.Desc). + Documents(ctx) // Map data var histories []models.CollaborationHistory @@ -62,6 +69,10 @@ func (s *Service) ListUserQuestionHistories(w http.ResponseWriter, r *http.Reque } history.HistoryDocRefID = doc.Ref.ID + // Swap matched user and user + history.MatchedUser = history.User + history.User = username + histories = append(histories, history) } diff --git a/apps/history-service/handlers/listuserhistory.go b/apps/history-service/handlers/listuserhistory.go index 712c649020..80c06d0963 100644 --- a/apps/history-service/handlers/listuserhistory.go +++ b/apps/history-service/handlers/listuserhistory.go @@ -5,6 +5,7 @@ import ( "history-service/models" "net/http" + "cloud.google.com/go/firestore" "github.com/go-chi/chi/v5" "google.golang.org/api/iterator" ) @@ -19,8 +20,12 @@ func (s *Service) ListUserHistories(w http.ResponseWriter, r *http.Request) { collRef := s.Client.Collection("collaboration-history") // Query data - iterUser := collRef.Where("user", "==", username).Documents(ctx) - iterMatchedUser := collRef.Where("matchedUser", "==", username).Documents(ctx) + iterUser := collRef.Where("user", "==", username). + OrderBy("createdAt", firestore.Desc). + Documents(ctx) + iterMatchedUser := collRef.Where("matchedUser", "==", username). + OrderBy("createdAt", firestore.Desc). + Documents(ctx) // Map data var histories []models.CollaborationHistory @@ -61,6 +66,10 @@ func (s *Service) ListUserHistories(w http.ResponseWriter, r *http.Request) { } history.HistoryDocRefID = doc.Ref.ID + // Swap matched user and user + history.MatchedUser = history.User + history.User = username + histories = append(histories, history) } diff --git a/apps/history-service/handlers/update.go b/apps/history-service/handlers/update.go index f91d9794e9..9f946ca3e9 100644 --- a/apps/history-service/handlers/update.go +++ b/apps/history-service/handlers/update.go @@ -13,7 +13,7 @@ import ( "google.golang.org/grpc/status" ) -// Update an existing code snippet +// Update an existing code snippet: Unused func (s *Service) UpdateHistory(w http.ResponseWriter, r *http.Request) { ctx := r.Context() From a3bcb12da7f8a518f106ae3251ee0ada944b44b5 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Mon, 4 Nov 2024 02:09:30 +0800 Subject: [PATCH 145/258] fix: swap matched user and user on frontend for specific submission --- apps/frontend/src/app/question/[id]/page.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/apps/frontend/src/app/question/[id]/page.tsx b/apps/frontend/src/app/question/[id]/page.tsx index ff0d4512f6..f7fd03da5e 100644 --- a/apps/frontend/src/app/question/[id]/page.tsx +++ b/apps/frontend/src/app/question/[id]/page.tsx @@ -122,7 +122,8 @@ export default function QuestionPage() { setSubmission({ submittedAt: submittedAt.toLocaleString("en-US"), language: data.language, - matchedUser: data.matchedUser, + matchedUser: + username == data.matchedUser ? data.User : data.matchedUser, code: data.code, historyDocRefId: data.historyDocRefId, }); @@ -141,11 +142,6 @@ export default function QuestionPage() { }, [currentSubmissionId]); const columns = [ - { - title: "ID", - dataIndex: "id", - key: "id", - }, { title: "Submitted at", dataIndex: "createdAt", @@ -206,6 +202,7 @@ export default function QuestionPage() { style: { cursor: "pointer" }, }; }} + scroll={{ y: "max-content" }} loading={isHistoryLoading} />
From 4015266b2919966aec8233e6b855b56893034191 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Mon, 4 Nov 2024 02:25:49 +0800 Subject: [PATCH 146/258] fix: backend history sorting --- apps/history-service/handlers/listquestionhistory.go | 9 ++++++--- apps/history-service/handlers/listuserhistory.go | 9 ++++++--- apps/history-service/models/models.go | 9 +++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/apps/history-service/handlers/listquestionhistory.go b/apps/history-service/handlers/listquestionhistory.go index 999a04993c..481770f85e 100644 --- a/apps/history-service/handlers/listquestionhistory.go +++ b/apps/history-service/handlers/listquestionhistory.go @@ -4,8 +4,8 @@ import ( "encoding/json" "history-service/models" "net/http" + "sort" - "cloud.google.com/go/firestore" "github.com/go-chi/chi/v5" "google.golang.org/api/iterator" ) @@ -23,12 +23,12 @@ func (s *Service) ListUserQuestionHistories(w http.ResponseWriter, r *http.Reque // Query data iterUser := collRef.Where("user", "==", username). Where("questionDocRefId", "==", questionDocRefID). - OrderBy("createdAt", firestore.Desc). Documents(ctx) + defer iterUser.Stop() iterMatchedUser := collRef.Where("matchedUser", "==", username). Where("questionDocRefId", "==", questionDocRefID). - OrderBy("createdAt", firestore.Desc). Documents(ctx) + defer iterMatchedUser.Stop() // Map data var histories []models.CollaborationHistory @@ -76,6 +76,9 @@ func (s *Service) ListUserQuestionHistories(w http.ResponseWriter, r *http.Reque histories = append(histories, history) } + // Sort the histories by created at time + sort.Sort(models.HistorySorter(histories)) + w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(histories) diff --git a/apps/history-service/handlers/listuserhistory.go b/apps/history-service/handlers/listuserhistory.go index 80c06d0963..269f6486ed 100644 --- a/apps/history-service/handlers/listuserhistory.go +++ b/apps/history-service/handlers/listuserhistory.go @@ -4,8 +4,8 @@ import ( "encoding/json" "history-service/models" "net/http" + "sort" - "cloud.google.com/go/firestore" "github.com/go-chi/chi/v5" "google.golang.org/api/iterator" ) @@ -21,11 +21,11 @@ func (s *Service) ListUserHistories(w http.ResponseWriter, r *http.Request) { // Query data iterUser := collRef.Where("user", "==", username). - OrderBy("createdAt", firestore.Desc). Documents(ctx) + defer iterUser.Stop() iterMatchedUser := collRef.Where("matchedUser", "==", username). - OrderBy("createdAt", firestore.Desc). Documents(ctx) + defer iterUser.Stop() // Map data var histories []models.CollaborationHistory @@ -73,6 +73,9 @@ func (s *Service) ListUserHistories(w http.ResponseWriter, r *http.Request) { histories = append(histories, history) } + // Sort the histories by created at time + sort.Sort(models.HistorySorter(histories)) + w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(histories) diff --git a/apps/history-service/models/models.go b/apps/history-service/models/models.go index b8cc571593..3e1f3a7836 100644 --- a/apps/history-service/models/models.go +++ b/apps/history-service/models/models.go @@ -23,3 +23,12 @@ type CollaborationHistory struct { UpdatedAt time.Time `json:"updatedAt" firestore:"updatedAt"` // updatedAt is unused as history is never updated once created HistoryDocRefID string `json:"historyDocRefId"` } + +// Sorting interface for history, which sorts by created at in desc order +type HistorySorter []CollaborationHistory + +func (s HistorySorter) Len() int { return len(s) } +func (s HistorySorter) Less(i, j int) bool { + return s[i].CreatedAt.After(s[j].CreatedAt) +} +func (s HistorySorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] } From 36d7b07058446476a4561a93977284183a064eb1 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Mon, 4 Nov 2024 03:43:14 +0800 Subject: [PATCH 147/258] feat: implement pagination for histories on question page --- apps/frontend/src/app/question/[id]/page.tsx | 63 +++++++++++++++---- apps/frontend/src/app/services/history.ts | 16 ++++- apps/history-service/handlers/create.go | 2 +- .../handlers/createOrUpdate.go | 2 +- .../handlers/listquestionhistory.go | 33 ++++++++-- .../handlers/listuserhistory.go | 33 ++++++++-- apps/history-service/handlers/read.go | 2 +- apps/history-service/handlers/update.go | 2 +- apps/history-service/models/models.go | 4 +- apps/history-service/models/pagination.go | 44 +++++++++++-- 10 files changed, 166 insertions(+), 35 deletions(-) diff --git a/apps/frontend/src/app/question/[id]/page.tsx b/apps/frontend/src/app/question/[id]/page.tsx index f7fd03da5e..a28d2a1a49 100644 --- a/apps/frontend/src/app/question/[id]/page.tsx +++ b/apps/frontend/src/app/question/[id]/page.tsx @@ -1,6 +1,6 @@ "use client"; import Header from "@/components/Header/header"; -import { Col, Layout, message, Row, Table } from "antd"; +import { Col, Layout, message, PaginationProps, Row, Table } from "antd"; import { Content } from "antd/es/layout/layout"; import { CodeOutlined, HistoryOutlined } from "@ant-design/icons"; import "./styles.scss"; @@ -24,6 +24,13 @@ interface Submission { historyDocRefId: string; } +interface TablePagination { + totalCount: number; + totalPages: number; + currentPage: number; + limit: number; +} + export default function QuestionPage() { const [isLoading, setIsLoading] = useState(true); // Store the states related to table's loading @@ -59,6 +66,12 @@ export default function QuestionPage() { const [currentSubmissionId, setCurrentSubmissionId] = useState< string | undefined >(undefined); + const [paginationParams, setPaginationParams] = useState({ + totalCount: 0, + totalPages: 0, + currentPage: 1, + limit: 3, + }); const state = EditorState.create({ doc: "", @@ -71,6 +84,33 @@ export default function QuestionPage() { ], }); + // Handler for change in page jumper + const onPageJump: PaginationProps["onChange"] = (pageNumber) => { + setPaginationParams((prev) => { + loadQuestionHistories(pageNumber, paginationParams.limit); + return { ...paginationParams, currentPage: pageNumber }; + }); + }; + + async function loadQuestionHistories(currentPage: number, limit: number) { + if (username === undefined) return; + setIsHistoryLoading(true); + GetUserQuestionHistories(username, docRefId, currentPage, limit) + .then((data: any) => { + setUserQuestionHistories(data.histories); + setPaginationParams({ + ...paginationParams, + totalCount: data.totalCount, + totalPages: data.totalPages, + currentPage: data.currentPage, + limit: data.limit, + }); + }) + .finally(() => { + setIsHistoryLoading(false); + }); + } + // When code editor page is initialised, fetch the particular question, and display in code editor useEffect(() => { if (!isLoading) { @@ -90,15 +130,7 @@ export default function QuestionPage() { }, [docRefId]); useEffect(() => { - if (username === undefined) return; - GetUserQuestionHistories(username, docRefId) - .then((data: any) => { - console.log(data); - setUserQuestionHistories(data); - }) - .finally(() => { - setIsHistoryLoading(false); - }); + loadQuestionHistories(paginationParams.currentPage, paginationParams.limit); }, [username]); useEffect(() => { @@ -108,6 +140,7 @@ export default function QuestionPage() { }, []); useEffect(() => { + // Only show history if a history is selected if (currentSubmissionId === undefined) return; const view = new EditorView({ @@ -115,8 +148,6 @@ export default function QuestionPage() { parent: editorRef.current || undefined, }); - // TODO: get from a specific history which was selected. - // Show latest history by default, or load specific history GetHistory(currentSubmissionId).then((data: any) => { const submittedAt = new Date(data.createdAt); setSubmission({ @@ -202,8 +233,14 @@ export default function QuestionPage() { style: { cursor: "pointer" }, }; }} - scroll={{ y: "max-content" }} loading={isHistoryLoading} + pagination={{ + size: "small", + current: paginationParams.currentPage, + total: paginationParams.totalCount, + pageSize: paginationParams.limit, + onChange: onPageJump, + }} /> diff --git a/apps/frontend/src/app/services/history.ts b/apps/frontend/src/app/services/history.ts index a2e52bcaf5..5ecdda6efa 100644 --- a/apps/frontend/src/app/services/history.ts +++ b/apps/frontend/src/app/services/history.ts @@ -77,10 +77,22 @@ export const GetUserHistories = async ( export const GetUserQuestionHistories = async ( username: string, - questionDocRefId: string + questionDocRefId: string, + currentPage?: number, + limit?: number ): Promise => { + let query_params = ""; + + if (currentPage) { + query_params += `?offset=${(currentPage - 1) * (limit ? limit : 10)}`; + } + + if (limit) { + query_params += `${query_params.length > 0 ? "&" : "?"}limit=${limit}`; + } + const response = await fetch( - `${HISTORY_SERVICE_URL}histories/user/${username}/question/${questionDocRefId}`, + `${HISTORY_SERVICE_URL}histories/user/${username}/question/${questionDocRefId}${query_params}`, { method: "GET", headers: { diff --git a/apps/history-service/handlers/create.go b/apps/history-service/handlers/create.go index 6290a44d28..a960da60ef 100644 --- a/apps/history-service/handlers/create.go +++ b/apps/history-service/handlers/create.go @@ -15,7 +15,7 @@ func (s *Service) CreateHistory(w http.ResponseWriter, r *http.Request) { ctx := r.Context() // Parse request - var collaborationHistory models.CollaborationHistory + var collaborationHistory models.SubmissionHistory if err := utils.DecodeJSONBody(w, r, &collaborationHistory); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return diff --git a/apps/history-service/handlers/createOrUpdate.go b/apps/history-service/handlers/createOrUpdate.go index 561c463d43..c87aa026fb 100644 --- a/apps/history-service/handlers/createOrUpdate.go +++ b/apps/history-service/handlers/createOrUpdate.go @@ -19,7 +19,7 @@ func (s *Service) CreateOrUpdateHistory(w http.ResponseWriter, r *http.Request) // Parse request matchId := chi.URLParam(r, "matchId") - var collaborationHistory models.CollaborationHistory + var collaborationHistory models.SubmissionHistory if err := utils.DecodeJSONBody(w, r, &collaborationHistory); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return diff --git a/apps/history-service/handlers/listquestionhistory.go b/apps/history-service/handlers/listquestionhistory.go index 481770f85e..239f9aeed5 100644 --- a/apps/history-service/handlers/listquestionhistory.go +++ b/apps/history-service/handlers/listquestionhistory.go @@ -5,6 +5,7 @@ import ( "history-service/models" "net/http" "sort" + "strconv" "github.com/go-chi/chi/v5" "google.golang.org/api/iterator" @@ -31,7 +32,7 @@ func (s *Service) ListUserQuestionHistories(w http.ResponseWriter, r *http.Reque defer iterMatchedUser.Stop() // Map data - var histories []models.CollaborationHistory + var histories []models.SubmissionHistory for { doc, err := iterUser.Next() if err == iterator.Done { @@ -42,7 +43,7 @@ func (s *Service) ListUserQuestionHistories(w http.ResponseWriter, r *http.Reque return } - var history models.CollaborationHistory + var history models.SubmissionHistory if err := doc.DataTo(&history); err != nil { http.Error(w, "Failed to map history data for user", http.StatusInternalServerError) return @@ -62,7 +63,7 @@ func (s *Service) ListUserQuestionHistories(w http.ResponseWriter, r *http.Reque return } - var history models.CollaborationHistory + var history models.SubmissionHistory if err := doc.DataTo(&history); err != nil { http.Error(w, "Failed to map history data for matched user", http.StatusInternalServerError) return @@ -79,7 +80,31 @@ func (s *Service) ListUserQuestionHistories(w http.ResponseWriter, r *http.Reque // Sort the histories by created at time sort.Sort(models.HistorySorter(histories)) + // Pagination + limitParam := r.URL.Query().Get("limit") + limit := 10 + if limitParam != "" { + l, err := strconv.Atoi(limitParam) // convert limit to integer + if err != nil || l <= 0 { + http.Error(w, "Invalid limit: "+strconv.Itoa(l), http.StatusBadRequest) + return + } + limit = l + } + offsetParam := r.URL.Query().Get("offset") + offset := 0 + if offsetParam != "" { + o, err := strconv.Atoi(offsetParam) // convert offset to integer + if err != nil { + http.Error(w, "Invalid offset: "+strconv.Itoa(o), http.StatusBadRequest) + return + } + offset = o + } + + response := models.PaginateResponse(limit, offset, histories) + w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(histories) + json.NewEncoder(w).Encode(response) } diff --git a/apps/history-service/handlers/listuserhistory.go b/apps/history-service/handlers/listuserhistory.go index 269f6486ed..5fa8a021d2 100644 --- a/apps/history-service/handlers/listuserhistory.go +++ b/apps/history-service/handlers/listuserhistory.go @@ -5,6 +5,7 @@ import ( "history-service/models" "net/http" "sort" + "strconv" "github.com/go-chi/chi/v5" "google.golang.org/api/iterator" @@ -28,7 +29,7 @@ func (s *Service) ListUserHistories(w http.ResponseWriter, r *http.Request) { defer iterUser.Stop() // Map data - var histories []models.CollaborationHistory + var histories []models.SubmissionHistory for { doc, err := iterUser.Next() if err == iterator.Done { @@ -39,7 +40,7 @@ func (s *Service) ListUserHistories(w http.ResponseWriter, r *http.Request) { return } - var history models.CollaborationHistory + var history models.SubmissionHistory if err := doc.DataTo(&history); err != nil { http.Error(w, "Failed to map history data for user", http.StatusInternalServerError) return @@ -59,7 +60,7 @@ func (s *Service) ListUserHistories(w http.ResponseWriter, r *http.Request) { return } - var history models.CollaborationHistory + var history models.SubmissionHistory if err := doc.DataTo(&history); err != nil { http.Error(w, "Failed to map history data for matched user", http.StatusInternalServerError) return @@ -76,7 +77,31 @@ func (s *Service) ListUserHistories(w http.ResponseWriter, r *http.Request) { // Sort the histories by created at time sort.Sort(models.HistorySorter(histories)) + // Pagination + limitParam := r.URL.Query().Get("limit") + limit := 10 + if limitParam != "" { + l, err := strconv.Atoi(limitParam) // convert limit to integer + if err != nil || l <= 0 { + http.Error(w, "Invalid limit: "+strconv.Itoa(l), http.StatusBadRequest) + return + } + limit = l + } + offsetParam := r.URL.Query().Get("offset") + offset := 0 + if offsetParam != "" { + o, err := strconv.Atoi(offsetParam) // convert offset to integer + if err != nil { + http.Error(w, "Invalid offset: "+strconv.Itoa(o), http.StatusBadRequest) + return + } + offset = o + } + + response := models.PaginateResponse(limit, offset, histories) + w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(histories) + json.NewEncoder(w).Encode(response) } diff --git a/apps/history-service/handlers/read.go b/apps/history-service/handlers/read.go index f986393919..6f7c35404d 100644 --- a/apps/history-service/handlers/read.go +++ b/apps/history-service/handlers/read.go @@ -30,7 +30,7 @@ func (s *Service) ReadHistory(w http.ResponseWriter, r *http.Request) { } // Map data - var collaborationHistory models.CollaborationHistory + var collaborationHistory models.SubmissionHistory if err := doc.DataTo(&collaborationHistory); err != nil { http.Error(w, "Failed to map history data", http.StatusInternalServerError) return diff --git a/apps/history-service/handlers/update.go b/apps/history-service/handlers/update.go index 9f946ca3e9..a25b983368 100644 --- a/apps/history-service/handlers/update.go +++ b/apps/history-service/handlers/update.go @@ -19,7 +19,7 @@ func (s *Service) UpdateHistory(w http.ResponseWriter, r *http.Request) { // Parse request matchId := chi.URLParam(r, "matchId") - var updatedHistory models.CollaborationHistory + var updatedHistory models.SubmissionHistory if err := utils.DecodeJSONBody(w, r, &updatedHistory); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return diff --git a/apps/history-service/models/models.go b/apps/history-service/models/models.go index 3e1f3a7836..158ec947d6 100644 --- a/apps/history-service/models/models.go +++ b/apps/history-service/models/models.go @@ -2,7 +2,7 @@ package models import "time" -type CollaborationHistory struct { +type SubmissionHistory struct { // Submission related details Code string `json:"code" firestore:"code"` Language string `json:"language" firestore:"language"` @@ -25,7 +25,7 @@ type CollaborationHistory struct { } // Sorting interface for history, which sorts by created at in desc order -type HistorySorter []CollaborationHistory +type HistorySorter []SubmissionHistory func (s HistorySorter) Len() int { return len(s) } func (s HistorySorter) Less(i, j int) bool { diff --git a/apps/history-service/models/pagination.go b/apps/history-service/models/pagination.go index a5a74ba7ea..6553325500 100644 --- a/apps/history-service/models/pagination.go +++ b/apps/history-service/models/pagination.go @@ -1,10 +1,42 @@ package models type HistoriesResponse struct { - TotalCount int `json:"totalCount"` - TotalPages int `json:"totalPages"` - CurrentPage int `json:"currentPage"` - Limit int `json:"limit"` - HasNextPage bool `json:"hasNextPage"` - Questions []CollaborationHistory `json:"histories"` + TotalCount int `json:"totalCount"` + TotalPages int `json:"totalPages"` + CurrentPage int `json:"currentPage"` + Limit int `json:"limit"` + HasNextPage bool `json:"hasNextPage"` + Questions []SubmissionHistory `json:"histories"` +} + +func PaginateResponse(limit, offset int, histories []SubmissionHistory) *HistoriesResponse { + start := offset + end := offset + limit + + var paginatedHistory []SubmissionHistory + if start < len(histories) { + if end > len(histories) { + end = len(histories) + } + paginatedHistory = histories[start:end] + } + + // Calculate pagination info + totalCount := len(histories) + totalPages := (totalCount + limit - 1) / limit + currentPage := (offset / limit) + 1 + if len(paginatedHistory) == 0 { + currentPage = 0 + } + hasNextPage := totalPages > currentPage + + // Construct response + return &HistoriesResponse{ + TotalCount: totalCount, + TotalPages: totalPages, + CurrentPage: currentPage, + Limit: limit, + HasNextPage: hasNextPage, + Questions: paginatedHistory, + } } From fb89725d10a6fc7da93ee9171b5773781100fbbe Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Mon, 4 Nov 2024 03:57:08 +0800 Subject: [PATCH 148/258] fix: heights of submission editor --- apps/frontend/src/app/question/[id]/page.tsx | 5 +++-- apps/frontend/src/app/question/[id]/styles.scss | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/frontend/src/app/question/[id]/page.tsx b/apps/frontend/src/app/question/[id]/page.tsx index a28d2a1a49..82600926c0 100644 --- a/apps/frontend/src/app/question/[id]/page.tsx +++ b/apps/frontend/src/app/question/[id]/page.tsx @@ -79,7 +79,7 @@ export default function QuestionPage() { basicSetup, languageConf.of(javascript()), EditorView.theme({ - "&": { height: "100%", overflow: "hidden" }, // Enable scroll + "&": { height: "100%", overflow: "hidden" }, // Enable Scroll }), ], }); @@ -241,6 +241,7 @@ export default function QuestionPage() { pageSize: paginationParams.limit, onChange: onPageJump, }} + scroll={{ y: 200 }} /> @@ -279,7 +280,7 @@ export default function QuestionPage() {
Date: Mon, 4 Nov 2024 03:58:51 +0800 Subject: [PATCH 149/258] fix: disable editor --- apps/frontend/src/app/question/[id]/page.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/frontend/src/app/question/[id]/page.tsx b/apps/frontend/src/app/question/[id]/page.tsx index 82600926c0..8719beeb32 100644 --- a/apps/frontend/src/app/question/[id]/page.tsx +++ b/apps/frontend/src/app/question/[id]/page.tsx @@ -81,6 +81,7 @@ export default function QuestionPage() { EditorView.theme({ "&": { height: "100%", overflow: "hidden" }, // Enable Scroll }), + EditorView.editable.of(false), // Disable editing ], }); From 1d5a38ddc1f04727389c4f358f986b1c3e44828d Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Mon, 4 Nov 2024 03:59:55 +0800 Subject: [PATCH 150/258] fix: other user query --- apps/frontend/src/app/question/[id]/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/src/app/question/[id]/page.tsx b/apps/frontend/src/app/question/[id]/page.tsx index 8719beeb32..95cf48164c 100644 --- a/apps/frontend/src/app/question/[id]/page.tsx +++ b/apps/frontend/src/app/question/[id]/page.tsx @@ -155,7 +155,7 @@ export default function QuestionPage() { submittedAt: submittedAt.toLocaleString("en-US"), language: data.language, matchedUser: - username == data.matchedUser ? data.User : data.matchedUser, + username == data.matchedUser ? data.user : data.matchedUser, code: data.code, historyDocRefId: data.historyDocRefId, }); From b1dd96c64e33bb255abf482ef7d02563c1f61d33 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Mon, 4 Nov 2024 04:59:44 +0800 Subject: [PATCH 151/258] feat: add history page --- apps/frontend/src/app/history/page.tsx | 191 ++++++++++++++++++ apps/frontend/src/app/history/styles.scss | 64 ++++++ apps/frontend/src/app/question/[id]/page.tsx | 18 +- apps/frontend/src/app/services/history.ts | 29 ++- .../frontend/src/components/Header/header.tsx | 19 +- 5 files changed, 302 insertions(+), 19 deletions(-) create mode 100644 apps/frontend/src/app/history/page.tsx create mode 100644 apps/frontend/src/app/history/styles.scss diff --git a/apps/frontend/src/app/history/page.tsx b/apps/frontend/src/app/history/page.tsx new file mode 100644 index 0000000000..8a6023e4a2 --- /dev/null +++ b/apps/frontend/src/app/history/page.tsx @@ -0,0 +1,191 @@ +"use client"; +import Header from "@/components/Header/header"; +import { Layout, message, PaginationProps, Row, Table, Tag } from "antd"; +import { Content } from "antd/es/layout/layout"; +import { HistoryOutlined } from "@ant-design/icons"; +import "./styles.scss"; +import { useEffect, useState } from "react"; +import React from "react"; +import { useRouter } from "next/navigation"; +import { GetUserHistories, History } from "@/app/services/history"; +import { ValidateUser, VerifyTokenResponseType } from "@/app/services/user"; + +interface TablePagination { + totalCount: number; + totalPages: number; + currentPage: number; + limit: number; +} + +export default function QuestionPage() { + // Message States + const [messageApi, contextHolder] = message.useMessage(); + + const error = (message: string) => { + messageApi.open({ + type: "error", + content: message, + }); + }; + + const router = useRouter(); + + const [username, setUsername] = useState(undefined); + const [userQuestionHistories, setUserQuestionHistories] = + useState(); + const [isHistoryLoading, setIsHistoryLoading] = useState(true); + const [paginationParams, setPaginationParams] = useState({ + totalCount: 0, + totalPages: 0, + currentPage: 1, + limit: 10, + }); + + // Handler for change in page jumper + const onPageJump: PaginationProps["onChange"] = (pageNumber) => { + setPaginationParams((prev) => { + loadQuestionHistories(pageNumber, paginationParams.limit); + return { ...paginationParams, currentPage: pageNumber }; + }); + }; + + // Handler for show size change for pagination + const onShowSizeChange: PaginationProps["onShowSizeChange"] = ( + current, + pageSize + ) => { + setPaginationParams((prev) => { + loadQuestionHistories(current, pageSize); + return { ...paginationParams, currentPage: current, limit: pageSize }; + }); + }; + + async function loadQuestionHistories(currentPage: number, limit: number) { + if (username === undefined) return; + setIsHistoryLoading(true); + GetUserHistories(username, currentPage, limit) + .then((data: any) => { + setUserQuestionHistories(data.histories); + setPaginationParams({ + ...paginationParams, + totalCount: data.totalCount, + totalPages: data.totalPages, + currentPage: data.currentPage, + limit: data.limit, + }); + }) + .finally(() => { + setIsHistoryLoading(false); + }); + } + + useEffect(() => { + loadQuestionHistories(paginationParams.currentPage, paginationParams.limit); + }, [username]); + + useEffect(() => { + ValidateUser().then((data: VerifyTokenResponseType) => { + setUsername(data.data.username); + }); + }, []); + + const columns = [ + { + title: "Title", + dataIndex: "title", + key: "title", + }, + { + title: "Categories", + dataIndex: "questionTopics", + key: "questionTopics", + render: (categories: string[]) => + categories.map((category) => {category}), + }, + { + title: "Difficulty", + dataIndex: "questionDifficulty", + key: "questionDifficulty", + render: (difficulty: string) => { + let color = ""; + if (difficulty === "easy") { + color = "#2DB55D"; + } else if (difficulty === "medium") { + color = "orange"; + } else if (difficulty === "hard") { + color = "red"; + } + return ( +
+ {difficulty.charAt(0).toUpperCase() + difficulty.slice(1)} +
+ ); + }, + }, + { + title: "Submitted at", + dataIndex: "createdAt", + key: "createdAt", + render: (date: string) => { + return new Date(date).toLocaleString(); + }, + }, + { + title: "Language", + dataIndex: "language", + key: "language", + }, + { + title: "Matched with", + dataIndex: "matchedUser", + key: "matchedUser", + }, + ]; + + const handleRowClick = (h: History) => { + // Link to page + // questionId is just read as "history", as only the doc ref id is involved in requests + // If the question database is reloaded, then the questionDocRefId may not be correct + router.push( + `/question/history?data=${h.questionDocRefId}&history=${h.historyDocRefId}` + ); + }; + + return ( +
+ {contextHolder} + +
+ +
+
+
Submission History
+
+
+
{ + return { + onClick: () => handleRowClick(record), + style: { cursor: "pointer" }, + }; + }} + loading={isHistoryLoading} + pagination={{ + current: paginationParams.currentPage, + total: paginationParams.totalCount, + pageSize: paginationParams.limit, + onChange: onPageJump, + showSizeChanger: true, + onShowSizeChange: onShowSizeChange, + }} + /> + + + + + + ); +} diff --git a/apps/frontend/src/app/history/styles.scss b/apps/frontend/src/app/history/styles.scss new file mode 100644 index 0000000000..3d435ad375 --- /dev/null +++ b/apps/frontend/src/app/history/styles.scss @@ -0,0 +1,64 @@ +.layout { + background: white; +} + +.content { + background: white; +} + +.content-card { + margin: 4rem 8rem; + padding: 2rem 4rem; + background-color: white; + min-height: 100vh; + border-radius: 30px; + box-shadow: 0px 10px 60px rgba(226, 236, 249, 0.5); +} + +.content-row-1 { + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.content-title { + // font-family: "Poppins"; + // font-style: normal; + font-weight: 600; + font-size: 22px; + line-height: 33px; + letter-spacing: -0.01em; + color: #000000; +} + +.content-filter { + margin: 1.5rem 0; +} + +.edit-button { + margin-right: 0.5rem; +} + +.filter-button { + margin-left: 8px; + box-shadow: 0 2px 0 rgba(0, 0, 0, 0.02) !important; +} + +.clear-button { + width: 100%; +} + +.categories-multi-select, +.difficulty-select, +.order-select { + width: 100%; +} + +.create-title, +.new-problem-categories-multi-select, +.new-problem-difficulty-select, +.create-description, +.create-problem-id { + width: 100%; + margin: 5px; +} diff --git a/apps/frontend/src/app/question/[id]/page.tsx b/apps/frontend/src/app/question/[id]/page.tsx index 95cf48164c..4a03f91ee9 100644 --- a/apps/frontend/src/app/question/[id]/page.tsx +++ b/apps/frontend/src/app/question/[id]/page.tsx @@ -20,8 +20,8 @@ interface Submission { submittedAt: string; language: string; matchedUser: string; - code: string; historyDocRefId: string; + code: string; } interface TablePagination { @@ -44,13 +44,13 @@ export default function QuestionPage() { }); }; - const router = useRouter(); const editorRef = useRef(null); const languageConf = new Compartment(); - // Retrieve the docRefId from query params during page navigation + // Retrieve the questionDocRefId and historyDocRefId from query params during page navigation const searchParams = useSearchParams(); - const docRefId: string = searchParams?.get("data") ?? ""; + const questionDocRefId: string = searchParams?.get("data") ?? ""; + const historyDocRefId: string = searchParams?.get("history") ?? ""; // Code Editor States const [questionTitle, setQuestionTitle] = useState( undefined @@ -65,7 +65,7 @@ export default function QuestionPage() { const [isHistoryLoading, setIsHistoryLoading] = useState(true); const [currentSubmissionId, setCurrentSubmissionId] = useState< string | undefined - >(undefined); + >(historyDocRefId == "" ? undefined : historyDocRefId); const [paginationParams, setPaginationParams] = useState({ totalCount: 0, totalPages: 0, @@ -96,7 +96,7 @@ export default function QuestionPage() { async function loadQuestionHistories(currentPage: number, limit: number) { if (username === undefined) return; setIsHistoryLoading(true); - GetUserQuestionHistories(username, docRefId, currentPage, limit) + GetUserQuestionHistories(username, questionDocRefId, currentPage, limit) .then((data: any) => { setUserQuestionHistories(data.histories); setPaginationParams({ @@ -118,7 +118,7 @@ export default function QuestionPage() { setIsLoading(true); } - GetSingleQuestion(docRefId) + GetSingleQuestion(questionDocRefId) .then((data: any) => { setQuestionTitle(data.title); setComplexity(data.complexity); @@ -128,7 +128,7 @@ export default function QuestionPage() { .finally(() => { setIsLoading(false); }); - }, [docRefId]); + }, [questionDocRefId]); useEffect(() => { loadQuestionHistories(paginationParams.currentPage, paginationParams.limit); @@ -156,8 +156,8 @@ export default function QuestionPage() { language: data.language, matchedUser: username == data.matchedUser ? data.user : data.matchedUser, - code: data.code, historyDocRefId: data.historyDocRefId, + code: data.code, }); view.dispatch( diff --git a/apps/frontend/src/app/services/history.ts b/apps/frontend/src/app/services/history.ts index 5ecdda6efa..f98f23c657 100644 --- a/apps/frontend/src/app/services/history.ts +++ b/apps/frontend/src/app/services/history.ts @@ -57,14 +57,29 @@ export const GetHistory = async (historyDocRefId: string): Promise => { }; export const GetUserHistories = async ( - username: string + username: string, + currentPage?: number, + limit?: number ): Promise => { - const response = await fetch(`${HISTORY_SERVICE_URL}histories/${username}`, { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }); + let query_params = ""; + + if (currentPage) { + query_params += `?offset=${(currentPage - 1) * (limit ? limit : 10)}`; + } + + if (limit) { + query_params += `${query_params.length > 0 ? "&" : "?"}limit=${limit}`; + } + + const response = await fetch( + `${HISTORY_SERVICE_URL}histories/user/${username}${query_params}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + } + ); if (response.status === 200) { return response.json(); diff --git a/apps/frontend/src/components/Header/header.tsx b/apps/frontend/src/components/Header/header.tsx index a9b2df7091..387699f5db 100644 --- a/apps/frontend/src/components/Header/header.tsx +++ b/apps/frontend/src/components/Header/header.tsx @@ -11,14 +11,17 @@ import { Header as AntdHeader } from "antd/es/layout/layout"; import { useRouter } from "next/navigation"; import "./styles.scss"; import DropdownButton from "antd/es/dropdown/dropdown-button"; -import { LogoutOutlined, UserOutlined } from "@ant-design/icons"; +import { + HistoryOutlined, + LogoutOutlined, + UserOutlined, +} from "@ant-design/icons"; import { deleteToken } from "@/app/services/login-store"; interface HeaderProps { selectedKey: string[] | undefined; } const Header = (props: HeaderProps): JSX.Element => { - const { push } = useRouter(); // Stores the details for the header buttons const items = [ @@ -45,10 +48,20 @@ const Header = (props: HeaderProps): JSX.Element => { onClick: () => push("/profile"), }, { - type: "divider", + key: 1, + label: ( +
+ History +
+ ), + onClick: () => push("/history"), }, { key: 2, + type: "divider", + }, + { + key: 3, label: (
Logout From 76ce6c73aab6ec4a6076ae73d77594ab623b236f Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Mon, 4 Nov 2024 05:16:41 +0800 Subject: [PATCH 152/258] fix: pagination --- apps/frontend/src/app/history/page.tsx | 2 +- apps/frontend/src/app/question/[id]/page.tsx | 2 +- apps/history-service/models/pagination.go | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/frontend/src/app/history/page.tsx b/apps/frontend/src/app/history/page.tsx index 8a6023e4a2..a1942ea8ad 100644 --- a/apps/frontend/src/app/history/page.tsx +++ b/apps/frontend/src/app/history/page.tsx @@ -44,7 +44,7 @@ export default function QuestionPage() { // Handler for change in page jumper const onPageJump: PaginationProps["onChange"] = (pageNumber) => { setPaginationParams((prev) => { - loadQuestionHistories(pageNumber, paginationParams.limit); + loadQuestionHistories(pageNumber, prev.limit); return { ...paginationParams, currentPage: pageNumber }; }); }; diff --git a/apps/frontend/src/app/question/[id]/page.tsx b/apps/frontend/src/app/question/[id]/page.tsx index 4a03f91ee9..d05e1a7535 100644 --- a/apps/frontend/src/app/question/[id]/page.tsx +++ b/apps/frontend/src/app/question/[id]/page.tsx @@ -88,7 +88,7 @@ export default function QuestionPage() { // Handler for change in page jumper const onPageJump: PaginationProps["onChange"] = (pageNumber) => { setPaginationParams((prev) => { - loadQuestionHistories(pageNumber, paginationParams.limit); + loadQuestionHistories(pageNumber, prev.limit); return { ...paginationParams, currentPage: pageNumber }; }); }; diff --git a/apps/history-service/models/pagination.go b/apps/history-service/models/pagination.go index 6553325500..3b9f1d38c3 100644 --- a/apps/history-service/models/pagination.go +++ b/apps/history-service/models/pagination.go @@ -18,8 +18,12 @@ func PaginateResponse(limit, offset int, histories []SubmissionHistory) *Histori if end > len(histories) { end = len(histories) } - paginatedHistory = histories[start:end] + } else { + start = 0 + offset = 0 + end = limit } + paginatedHistory = histories[start:end] // Calculate pagination info totalCount := len(histories) From 4c4ada94bd16a24adf49ce240bf89bf4a7296dd8 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Mon, 4 Nov 2024 05:19:28 +0800 Subject: [PATCH 153/258] feat: remove buttons in match found modal --- apps/frontend/src/app/history/page.tsx | 2 +- .../src/app/matching/modalContent/MatchFoundContent.tsx | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/apps/frontend/src/app/history/page.tsx b/apps/frontend/src/app/history/page.tsx index a1942ea8ad..e881b3118b 100644 --- a/apps/frontend/src/app/history/page.tsx +++ b/apps/frontend/src/app/history/page.tsx @@ -91,7 +91,7 @@ export default function QuestionPage() { const columns = [ { - title: "Title", + title: "Question Title", dataIndex: "title", key: "title", }, diff --git a/apps/frontend/src/app/matching/modalContent/MatchFoundContent.tsx b/apps/frontend/src/app/matching/modalContent/MatchFoundContent.tsx index e7ff88bc7b..340a6e13c2 100644 --- a/apps/frontend/src/app/matching/modalContent/MatchFoundContent.tsx +++ b/apps/frontend/src/app/matching/modalContent/MatchFoundContent.tsx @@ -53,12 +53,6 @@ const MatchFoundContent: React.FC = ({
Joining in... {formatTime(totalSeconds)}
- -
); }; From d00edf0d46a4890f50be1916438d02565f822702 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Mon, 4 Nov 2024 05:27:16 +0800 Subject: [PATCH 154/258] feat: remove cancel button in match found modal --- .../src/app/matching/MatchingModal.tsx | 10 +- .../modalContent/JoinedMatchContent.tsx | 103 ++++++++---------- .../modalContent/MatchFoundContent.tsx | 3 + 3 files changed, 58 insertions(+), 58 deletions(-) diff --git a/apps/frontend/src/app/matching/MatchingModal.tsx b/apps/frontend/src/app/matching/MatchingModal.tsx index cbb4e67a75..29b1eaa2c6 100644 --- a/apps/frontend/src/app/matching/MatchingModal.tsx +++ b/apps/frontend/src/app/matching/MatchingModal.tsx @@ -103,8 +103,14 @@ const MatchingModal: React.FC = ({ matchingState.info.matchedUser ); localStorage.setItem("collabId", matchingState.info.matchId); - localStorage.setItem("questionDocRefId", matchingState.info.questionDocRefId); - localStorage.setItem("matchedTopics", matchingState.info.matchedTopics.join(",")); + localStorage.setItem( + "questionDocRefId", + matchingState.info.questionDocRefId + ); + localStorage.setItem( + "matchedTopics", + matchingState.info.matchedTopics.join(",") + ); // Redirect to collaboration page router.push(`/collaboration/${matchingState.info.matchId}`); diff --git a/apps/frontend/src/app/matching/modalContent/JoinedMatchContent.tsx b/apps/frontend/src/app/matching/modalContent/JoinedMatchContent.tsx index 55e40888f1..940d4fb64d 100644 --- a/apps/frontend/src/app/matching/modalContent/JoinedMatchContent.tsx +++ b/apps/frontend/src/app/matching/modalContent/JoinedMatchContent.tsx @@ -1,64 +1,55 @@ -import React from 'react'; -import { - Avatar, - } from 'antd'; -import { - UserOutlined, -} from '@ant-design/icons'; -import 'typeface-montserrat'; -import './styles.scss'; -import { handleCancelMatch } from '../handlers'; -import { formatTime } from '@/utils/DateTime'; - +import React from "react"; +import { Avatar } from "antd"; +import { UserOutlined } from "@ant-design/icons"; +import "typeface-montserrat"; +import "./styles.scss"; +import { handleCancelMatch } from "../handlers"; +import { formatTime } from "@/utils/DateTime"; interface Props { - cancel(): void - name1: string, // user's username - name2: string, // matched user's username + cancel(): void; + name1: string; // user's username + name2: string; // matched user's username } -const JoinedMatchContent: React.FC = ({cancel, name1: me, name2: you}) => { - const matchAlreadyJoined = () => { - throw new Error('Match already joined.'); - } +const JoinedMatchContent: React.FC = ({ + cancel, + name1: me, + name2: you, +}) => { + const matchAlreadyJoined = () => { + throw new Error("Match already joined."); + }; - return ( -
-
-
- } /> -
{me}
-
- - - -
- } /> -
{you}
-
-
-
Match Found!
-
- Waiting for others... {formatTime(83)} -
- - + return ( +
+
+
+ } /> +
{me}
- ) -} + + + +
+ } /> +
{you}
+
+
+
Match Found!
+
Waiting for others...
+ +
+ ); +}; export default JoinedMatchContent; diff --git a/apps/frontend/src/app/matching/modalContent/MatchFoundContent.tsx b/apps/frontend/src/app/matching/modalContent/MatchFoundContent.tsx index 340a6e13c2..4efb1a1a04 100644 --- a/apps/frontend/src/app/matching/modalContent/MatchFoundContent.tsx +++ b/apps/frontend/src/app/matching/modalContent/MatchFoundContent.tsx @@ -53,6 +53,9 @@ const MatchFoundContent: React.FC = ({
Joining in... {formatTime(totalSeconds)}
+
); }; From f79896f9f3c0c3e24271289b3043ced147e27d48 Mon Sep 17 00:00:00 2001 From: solomonng2001 Date: Mon, 4 Nov 2024 14:06:03 +0800 Subject: [PATCH 155/258] Add sandbox for python execution (to be debugged) --- apps/docker-compose.yml | 9 +++++++++ apps/execution-service/Dockerfile | 6 ++++++ apps/execution-service/execution/python/Dockerfile | 3 +++ apps/execution-service/execution/python/python.go | 12 ++++++++++-- 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 apps/execution-service/execution/python/Dockerfile diff --git a/apps/docker-compose.yml b/apps/docker-compose.yml index 30d5443d32..a0565fe1dd 100644 --- a/apps/docker-compose.yml +++ b/apps/docker-compose.yml @@ -94,6 +94,7 @@ services: - apps_network volumes: - ./execution-service:/execution-service + - /var/run/docker.sock:/var/run/docker.sock redis: image: redis:latest @@ -103,5 +104,13 @@ services: - 6379:6379 container_name: redis-container + python-sandbox: + build: + context: ./execution-service/execution/python + dockerfile: Dockerfile + networks: + - apps_network + container_name: python-sandbox + networks: apps_network: diff --git a/apps/execution-service/Dockerfile b/apps/execution-service/Dockerfile index 1a0bb66e44..eda8bea8d0 100644 --- a/apps/execution-service/Dockerfile +++ b/apps/execution-service/Dockerfile @@ -2,6 +2,12 @@ FROM golang:1.23 WORKDIR /usr/src/app +# Install Docker CLI +RUN apt-get update && apt-get install -y \ + docker.io \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + # pre-copy/cache go.mod for pre-downloading dependencies and only redownloading them in subsequent builds if they change COPY go.mod go.sum ./ diff --git a/apps/execution-service/execution/python/Dockerfile b/apps/execution-service/execution/python/Dockerfile new file mode 100644 index 0000000000..54ff4e8d0e --- /dev/null +++ b/apps/execution-service/execution/python/Dockerfile @@ -0,0 +1,3 @@ +FROM python:3.10-slim + +WORKDIR /app diff --git a/apps/execution-service/execution/python/python.go b/apps/execution-service/execution/python/python.go index a8f89316fc..b59f195901 100644 --- a/apps/execution-service/execution/python/python.go +++ b/apps/execution-service/execution/python/python.go @@ -25,8 +25,16 @@ func RunPythonCode(code string, input string) (string, string, error) { return "", "", fmt.Errorf("failed to close temporary file: %w", err) } + // Read the contents of the script file for debugging + content, err := os.ReadFile(tmpFile.Name()) + if err != nil { + return "", "", fmt.Errorf("failed to read temporary file: %w", err) + } + fmt.Printf("Contents of script.py:\n%s\n", content) + // Prepare the command to execute the Python script - cmd := exec.Command("python3", tmpFile.Name()) + cmd := exec.Command("docker", "run", "--rm", "-v", fmt.Sprintf("%s:/app/script.py", tmpFile.Name()), "python-sandbox", "python", "/app/script.py") + //cmd := exec.Command("python3", tmpFile.Name()) cmd.Stdin = bytes.NewBufferString(input) // Capture the output and error @@ -37,7 +45,7 @@ func RunPythonCode(code string, input string) (string, string, error) { // Run the command if err := cmd.Run(); err != nil { - return "", fmt.Sprintf("Command execution failed: %s: %w", errorOutput.String(), err), nil + return "", fmt.Sprintf("Command execution failed: %s: %v", errorOutput.String(), err), nil } return strings.TrimSuffix(output.String(), "\n"), strings.TrimSuffix(errorOutput.String(), "\n"), nil From bcd29d32534f3c48681cab3625695667c0ebf8fd Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Mon, 4 Nov 2024 15:27:42 +0800 Subject: [PATCH 156/258] merge n11 --- .github/workflows/test.yml | 13 ++-- apps/question-service/tests/read_test.go | 86 +++++++++++------------- 2 files changed, 48 insertions(+), 51 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 18b5fad0df..457d5f37a9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -43,15 +43,16 @@ jobs: with: go-version: '1.23.x' - - name: Install dependencies + - name: Install Go dependencies run: | cd ./apps/question-service go mod tidy - - name: Run tests - run: | - cd ./apps/question-service - go test ./... + - name: Install firebase tools + run: curl -sL firebase.tools | bash + + - name: Run Go tests with Firebase emulator + run: firebase emulators:exec --only firestore 'cd ./apps/question-service' frontend-unit-tests: runs-on: ubuntu-latest @@ -83,7 +84,7 @@ jobs: cd ./apps/frontend pnpm test - test: + test-docker-compose: runs-on: ubuntu-latest steps: diff --git a/apps/question-service/tests/read_test.go b/apps/question-service/tests/read_test.go index 7849bc1495..2186e49d1a 100644 --- a/apps/question-service/tests/read_test.go +++ b/apps/question-service/tests/read_test.go @@ -2,74 +2,74 @@ package tests import ( "context" - "fmt" "log" "net/http" "net/http/httptest" "os" - "path/filepath" "question-service/handlers" + "question-service/utils" "strings" "testing" "cloud.google.com/go/firestore" - firebase "firebase.google.com/go/v4" "github.com/go-chi/chi/v5" - "github.com/joho/godotenv" - "google.golang.org/api/option" ) var service *handlers.Service +var ctx = context.Background() -func createService() *handlers.Service { - - ctx := context.Background() - client, err := initFirestore(ctx) - +func TestMain(m *testing.M) { + // Set FIRESTORE_EMULATOR_HOST environment variable. + err := os.Setenv("FIRESTORE_EMULATOR_HOST", "localhost:8080") if err != nil { - log.Fatalf("failed to initialize Firestore: %v", err) + log.Fatalf("could not set env %v", err) } + // Create client. + client, err := firestore.NewClient(ctx, "my-project-id") + service = &handlers.Service{Client: client} - return &handlers.Service{Client: client} -} - -// initFirestore initializes the Firestore client -func initFirestore(ctx context.Context) (*firestore.Client, error) { - credentialsPath := "../" + os.Getenv("FIREBASE_CREDENTIAL_PATH") - opt := option.WithCredentialsFile(credentialsPath) - app, err := firebase.NewApp(ctx, nil, opt) if err != nil { - return nil, fmt.Errorf("failed to initialize Firebase App: %v", err) + log.Fatalf("could not create client %v", err) } + defer client.Close() - client, err := app.Firestore(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get Firestore client: %v", err) - } - return client, nil + m.Run() + os.Exit(0) } -func TestMain(m *testing.M) { - err := godotenv.Load(filepath.Join("../", ".env")) +// Sets up the firestore emulator with the sample questions +// This repopulates the db +// Returns the docref of one of the questions if a test need it +func setupDb(t *testing.T) string { + // Repopulate document + utils.Populate(service.Client) + + coll := service.Client.Collection("questions") + if coll == nil { + t.Fatalf("Failed to get CollectionRef") + } + docRef, err := coll.DocumentRefs(ctx).Next() if err != nil { - log.Fatalf("Error loading .env file") + t.Fatalf("Failed to get DocRef: %v", err) } - service = createService() - defer service.Client.Close() - exitCode := m.Run() - os.Exit(exitCode) + return docRef.ID } -func Test_Read(t *testing.T) { - res := httptest.NewRecorder() - +func ReadRequestWithId(id string) *http.Request { // adds chi context // https://stackoverflow.com/questions/54580582/testing-chi-routes-w-path-variables rctx := chi.NewRouteContext() - rctx.URLParams.Add("docRefID", "6SdbW4Awcfm5x0UQtWmg") + rctx.URLParams.Add("docRefID", id) - req := httptest.NewRequest(http.MethodGet, "http://localhost:8080/questions/6SdbW4Awcfm5x0UQtWmg", strings.NewReader("")) + req := httptest.NewRequest(http.MethodGet, "http://localhost:12345/questions/"+id, strings.NewReader("")) req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) + return req +} +func Test_Read(t *testing.T) { + id := setupDb(t) + + res := httptest.NewRecorder() + req := ReadRequestWithId(id) service.ReadQuestion(res, req) @@ -79,19 +79,15 @@ func Test_Read(t *testing.T) { } func Test_ReadNotFound(t *testing.T) { - res := httptest.NewRecorder() - - // adds chi context - // https://stackoverflow.com/questions/54580582/testing-chi-routes-w-path-variables - rctx := chi.NewRouteContext() - rctx.URLParams.Add("docRefID", "not-found-docref") + setupDb(t) - req := httptest.NewRequest(http.MethodGet, "http://localhost:8080/questions/not-found-docref", strings.NewReader("")) - req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, rctx)) + res := httptest.NewRecorder() + req := ReadRequestWithId("invalid-docref") service.ReadQuestion(res, req) if res.Result().StatusCode != 404 { t.Fatalf("expected status code 404 but got response %v", res.Result()) } + } From 8dd1799c6ee6ace96fb416311d2e3a39106fda23 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Mon, 4 Nov 2024 18:03:19 +0800 Subject: [PATCH 157/258] Add back go test in workflow --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 457d5f37a9..46980de7cc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -52,7 +52,7 @@ jobs: run: curl -sL firebase.tools | bash - name: Run Go tests with Firebase emulator - run: firebase emulators:exec --only firestore 'cd ./apps/question-service' + run: firebase emulators:exec --only firestore 'cd ./apps/question-service; go test ./...' frontend-unit-tests: runs-on: ubuntu-latest From e28bf0f5e43181d4709b4a91a2291584024419cb Mon Sep 17 00:00:00 2001 From: bensohh Date: Mon, 4 Nov 2024 20:38:23 +0800 Subject: [PATCH 158/258] Add end call function, ammend styling and fix bugs --- .../src/components/VideoPanel/VideoPanel.tsx | 111 ++++++++++++++++-- .../src/components/VideoPanel/styles.scss | 3 +- 2 files changed, 101 insertions(+), 13 deletions(-) diff --git a/apps/frontend/src/components/VideoPanel/VideoPanel.tsx b/apps/frontend/src/components/VideoPanel/VideoPanel.tsx index ee3ece7c33..36fdd948e2 100644 --- a/apps/frontend/src/components/VideoPanel/VideoPanel.tsx +++ b/apps/frontend/src/components/VideoPanel/VideoPanel.tsx @@ -23,9 +23,12 @@ const VideoPanel = () => { const [callInstance, setCallInstance] = useState( null ); + const [remoteCallInstance, setRemoteCallInstance] = + useState(null); const [userStream, setUserStream] = useState(null); const [videoOn, setVideoOn] = useState(true); const [muteOn, setMuteOn] = useState(false); + const [isCalling, setIsCalling] = useState(false); const handleCall = () => { navigator.mediaDevices @@ -37,6 +40,7 @@ const VideoPanel = () => { if (peerInstance) { const call = peerInstance?.call(partnerId, stream); setCallInstance(call); + setIsCalling(true); // Set isCalling as true since it is the initiator if (call) { call.on("stream", (userVideoStream: MediaStream) => { if (remoteVideoRef.current) { @@ -100,6 +104,8 @@ const VideoPanel = () => { peer.on("call", (call) => { call.answer(stream); + setIsCalling(true); // When a peer initiates call, on answer, set the calling state to true + setRemoteCallInstance(call); // Set remote call instance media connection call.on("stream", (userVideoStream) => { if (remoteVideoRef.current) { remoteVideoRef.current.srcObject = userVideoStream; @@ -116,6 +122,17 @@ const VideoPanel = () => { } }, []); + // When remote peer initiates end call, we set isCalling to false + useEffect(() => { + remoteCallInstance?.on("close", () => { + setIsCalling(false); + }); + + callInstance?.on("close", () => { + setIsCalling(false); + }); + }, [remoteCallInstance?.open, callInstance?.open]); + const toggleVideo = () => { if (userStream) { const videoTrack = userStream.getVideoTracks()[0]; @@ -126,8 +143,10 @@ const VideoPanel = () => { videoTrack.enabled = false; setVideoOn(false); - if (callInstance) { - const sender = callInstance.peerConnection + if (callInstance && remoteCallInstance?.open) { + const sender = ( + callInstance.peerConnection || remoteCallInstance.peerConnection + ) .getSenders() .find((s) => { if (s.track) { @@ -147,6 +166,18 @@ const VideoPanel = () => { } }; + const handleCloseConnection = () => { + if (callInstance && callInstance.open) { + callInstance.close(); + setIsCalling(false); + } + + if (remoteCallInstance && remoteCallInstance.open) { + remoteCallInstance.close(); + setIsCalling(false); + } + }; + const toggleMute = () => { if (userStream) { const audioTrack = userStream.getAudioTracks()[0]; @@ -161,8 +192,10 @@ const VideoPanel = () => { audioTrack.enabled = false; setMuteOn(true); - if (callInstance) { - const sender = callInstance.peerConnection + if (callInstance && remoteCallInstance?.open) { + const sender = ( + callInstance.peerConnection || remoteCallInstance.peerConnection + ) .getSenders() .find((s) => { if (s.track) { @@ -186,6 +219,7 @@ const VideoPanel = () => { playsInline ref={currentUserVideoRef} autoPlay + muted />
-
+ ) : ( +
+ + + + + + +
+ ) + } + type="primary" + danger={isCalling} + > + {isCalling ? "End" : "Call"} {/*

Video Feed for: {matchedUsername}

*/} -
diff --git a/apps/frontend/src/components/question/QuestionDetailFull/QuestionDetailFull.tsx b/apps/frontend/src/components/question/QuestionDetailFull/QuestionDetailFull.tsx index d891b20bd3..d5a22292ec 100644 --- a/apps/frontend/src/components/question/QuestionDetailFull/QuestionDetailFull.tsx +++ b/apps/frontend/src/components/question/QuestionDetailFull/QuestionDetailFull.tsx @@ -2,6 +2,7 @@ import { Row, TabsProps } from "antd"; import { QuestionDetail } from "../QuestionDetail/QuestionDetail"; import { TestcaseDetail } from "../TestcaseDetail/TestcaseDetail"; import "./styles.scss"; +import { Test } from "@/app/services/execute"; // TODO: should add function for test case submission in props interface QuestionDetailFullProps { @@ -9,7 +10,7 @@ interface QuestionDetailFullProps { complexity?: string; categories?: string[]; description?: string; - testcaseItems?: TabsProps["items"]; + visibleTestcases?: Test[]; shouldShowSubmitButton?: boolean; handleRunTestCases?: () => void; isLoadingTestCase?: boolean; @@ -29,7 +30,7 @@ export const QuestionDetailFull = (props: QuestionDetailFullProps) => { void; @@ -11,9 +16,7 @@ interface TestcaseDetailProps { } export const TestcaseDetail = (props: TestcaseDetailProps) => { - // TODO: Tabs component items for testcases - // TODO: Setup test-cases in db for each qn and pull/paste here - const items: TabsProps["items"] = [ + const defaultTestcaseTabs: TabsProps["items"] = [ { key: "1", label: "Case 1", @@ -37,6 +40,53 @@ export const TestcaseDetail = (props: TestcaseDetailProps) => { // }, ]; + var visibleTestcasesTabs: TabsProps["items"] = props.visibleTestcases?.map( + (item, index) => { + return { + key: index.toString(), + label: ( + + Case {index + 1} + + ), + children: ( +
+ + {isTestResult(item) && ( +
+ + + {item.passed ? "Passed" : "Failed"} + +
+ Actual Output:{" "} + {item.actual} +
+ {item.error && ( + <> + Error: +
{item.error}
+ + )} +
+ )} +
+ ), + }; + } + ); + return (
@@ -63,7 +113,10 @@ export const TestcaseDetail = (props: TestcaseDetailProps) => { )}
- +
); From 324463e3b1ae0812202668ebeacdd1f13c4b7b64 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Wed, 6 Nov 2024 01:33:41 +0800 Subject: [PATCH 169/258] branch name --- apps/signalling-service/.dockerignore | 9 ++++++ apps/signalling-service/pnpm-lock.yaml | 40 +++++++++++++++----------- 2 files changed, 33 insertions(+), 16 deletions(-) create mode 100644 apps/signalling-service/.dockerignore diff --git a/apps/signalling-service/.dockerignore b/apps/signalling-service/.dockerignore new file mode 100644 index 0000000000..3f214be645 --- /dev/null +++ b/apps/signalling-service/.dockerignore @@ -0,0 +1,9 @@ +node_modules +.git +.gitignore +README.md +LICENSE +.env +.env* +Dockerfile +.dockerignore \ No newline at end of file diff --git a/apps/signalling-service/pnpm-lock.yaml b/apps/signalling-service/pnpm-lock.yaml index cd6e4916a0..04ce15c614 100644 --- a/apps/signalling-service/pnpm-lock.yaml +++ b/apps/signalling-service/pnpm-lock.yaml @@ -1,32 +1,31 @@ -lockfileVersion: '6.0' +lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -dependencies: - lib0: - specifier: ^0.2.98 - version: 0.2.98 - ws: - specifier: ^8.18.0 - version: 8.18.0 +importers: + + .: + dependencies: + lib0: + specifier: ^0.2.98 + version: 0.2.98 + ws: + specifier: ^8.18.0 + version: 8.18.0 packages: - /isomorphic.js@0.2.5: + isomorphic.js@0.2.5: resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} - dev: false - /lib0@0.2.98: + lib0@0.2.98: resolution: {integrity: sha512-XteTiNO0qEXqqweWx+b21p/fBnNHUA1NwAtJNJek1oPrewEZs2uiT4gWivHKr9GqCjDPAhchz0UQO8NwU3bBNA==} engines: {node: '>=16'} hasBin: true - dependencies: - isomorphic.js: 0.2.5 - dev: false - /ws@8.18.0: + ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} peerDependencies: @@ -37,4 +36,13 @@ packages: optional: true utf-8-validate: optional: true - dev: false + +snapshots: + + isomorphic.js@0.2.5: {} + + lib0@0.2.98: + dependencies: + isomorphic.js: 0.2.5 + + ws@8.18.0: {} From eb946d7df516bf82d7eeebf64828b0ac7d9cccf0 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Wed, 6 Nov 2024 15:09:21 +0800 Subject: [PATCH 170/258] fix: implement check to ensure correct user shows up in matchedUser field --- apps/frontend/src/app/question/[id]/page.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/frontend/src/app/question/[id]/page.tsx b/apps/frontend/src/app/question/[id]/page.tsx index 6182559041..5bf5b332b9 100644 --- a/apps/frontend/src/app/question/[id]/page.tsx +++ b/apps/frontend/src/app/question/[id]/page.tsx @@ -21,6 +21,7 @@ interface Submission { submittedAt: string; language: string; matchedUser: string; + otherUser: string; historyDocRefId: string; code: string; } @@ -162,6 +163,7 @@ export default function QuestionPage() { language: data.language, matchedUser: username == data.matchedUser ? data.user : data.matchedUser, + otherUser: data.user, historyDocRefId: data.historyDocRefId, code: data.code, }); @@ -279,7 +281,13 @@ export default function QuestionPage() { Language: {submission?.language || "-"}
- Matched with: {submission?.matchedUser || "-"} + Matched with:{" "} + {submission?.matchedUser + ? // Check to ensure that matched user is correct, otherwise swap with otherUser + username == submission.matchedUser + ? submission.otherUser + : submission.matchedUser + : "-"}
From b2362510a8ced6b6cd2f940d2232188f47f35d9c Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Wed, 6 Nov 2024 15:37:42 +0800 Subject: [PATCH 171/258] feat: add loading to submission --- apps/frontend/src/app/question/[id]/page.tsx | 92 +++++++++++++------ .../src/app/question/[id]/styles.scss | 2 + 2 files changed, 65 insertions(+), 29 deletions(-) diff --git a/apps/frontend/src/app/question/[id]/page.tsx b/apps/frontend/src/app/question/[id]/page.tsx index 5bf5b332b9..a97ca31d3f 100644 --- a/apps/frontend/src/app/question/[id]/page.tsx +++ b/apps/frontend/src/app/question/[id]/page.tsx @@ -1,6 +1,6 @@ "use client"; import Header from "@/components/Header/header"; -import { Col, Layout, message, PaginationProps, Row, Table } from "antd"; +import { Col, Layout, message, PaginationProps, Row, Spin, Table } from "antd"; import { Content } from "antd/es/layout/layout"; import { CodeOutlined, HistoryOutlined } from "@ant-design/icons"; import "./styles.scss"; @@ -65,6 +65,7 @@ export default function QuestionPage() { useState(); const [submission, setSubmission] = useState(); const [isHistoryLoading, setIsHistoryLoading] = useState(true); + const [isSubmissionLoading, setIsSubmissionLoading] = useState(true); const [currentSubmissionId, setCurrentSubmissionId] = useState< string | undefined >(historyDocRefId == "" ? undefined : historyDocRefId); @@ -156,24 +157,28 @@ export default function QuestionPage() { parent: editorRef.current || undefined, }); - GetHistory(currentSubmissionId).then((data: any) => { - const submittedAt = new Date(data.createdAt); - setSubmission({ - submittedAt: submittedAt.toLocaleString("en-US"), - language: data.language, - matchedUser: - username == data.matchedUser ? data.user : data.matchedUser, - otherUser: data.user, - historyDocRefId: data.historyDocRefId, - code: data.code, - }); + setIsSubmissionLoading(true); + GetHistory(currentSubmissionId) + .then((data: any) => { + const submittedAt = new Date(data.createdAt); + setSubmission({ + submittedAt: submittedAt.toLocaleString("en-US"), + language: data.language, + matchedUser: + username == data.matchedUser ? data.user : data.matchedUser, + otherUser: data.user, + historyDocRefId: data.historyDocRefId, + code: data.code, + }); + setIsSubmissionLoading(false); - view.dispatch( - state.update({ - changes: { from: 0, to: state.doc.length, insert: data.code }, - }) - ); - }); + view.dispatch( + state.update({ + changes: { from: 0, to: state.doc.length, insert: data.code }, + }) + ); + }) + .finally(() => {}); return () => { // Cleanup on component unmount @@ -258,7 +263,25 @@ export default function QuestionPage() { {currentSubmissionId && (
- <> + {isSubmissionLoading && ( +
+ +
+ )} +
@@ -271,23 +294,34 @@ export default function QuestionPage() { style={{ margin: "10px", display: "flex", + justifyContent: "space-between", flexDirection: "row", }} >
- Submitted at: {submission?.submittedAt || "-"} +
+ Submitted at:  +
+
{submission?.submittedAt || "-"}
- Language: {submission?.language || "-"} +
+ Language:  +
+
{submission?.language || "-"}
- Matched with:{" "} - {submission?.matchedUser - ? // Check to ensure that matched user is correct, otherwise swap with otherUser - username == submission.matchedUser - ? submission.otherUser - : submission.matchedUser - : "-"} +
+ Matched with:  +
+
+ {submission?.matchedUser + ? // Check to ensure that matched user is correct, otherwise swap with otherUser + username == submission.matchedUser + ? submission.otherUser + : submission.matchedUser + : "-"} +
@@ -307,7 +341,7 @@ export default function QuestionPage() { }} >
- +
)} diff --git a/apps/frontend/src/app/question/[id]/styles.scss b/apps/frontend/src/app/question/[id]/styles.scss index f4266b0071..6a0f6c746e 100644 --- a/apps/frontend/src/app/question/[id]/styles.scss +++ b/apps/frontend/src/app/question/[id]/styles.scss @@ -140,5 +140,7 @@ .submission-header-detail { font-weight: normal; + display: flex; + flex-direction: row; padding: 0px 10px 0px 10px; } From afaef67016d5e3b3b8d1f26b7a871e54607ba499 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Wed, 6 Nov 2024 15:41:38 +0800 Subject: [PATCH 172/258] feat: adjust padding --- apps/frontend/src/app/question/[id]/page.tsx | 16 +++++++++------- apps/frontend/src/app/question/[id]/styles.scss | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/frontend/src/app/question/[id]/page.tsx b/apps/frontend/src/app/question/[id]/page.tsx index a97ca31d3f..274136a2aa 100644 --- a/apps/frontend/src/app/question/[id]/page.tsx +++ b/apps/frontend/src/app/question/[id]/page.tsx @@ -300,21 +300,23 @@ export default function QuestionPage() { >
- Submitted at:  + Submitted at: +
+
+ {submission?.submittedAt || "-"}
-
{submission?.submittedAt || "-"}
-
- Language:  +
Language:
+
+ {submission?.language || "-"}
-
{submission?.language || "-"}
- Matched with:  + Matched with:
-
+
{submission?.matchedUser ? // Check to ensure that matched user is correct, otherwise swap with otherUser username == submission.matchedUser diff --git a/apps/frontend/src/app/question/[id]/styles.scss b/apps/frontend/src/app/question/[id]/styles.scss index 6a0f6c746e..216017579a 100644 --- a/apps/frontend/src/app/question/[id]/styles.scss +++ b/apps/frontend/src/app/question/[id]/styles.scss @@ -142,5 +142,5 @@ font-weight: normal; display: flex; flex-direction: row; - padding: 0px 10px 0px 10px; + padding: 0px 10px 0px 0px; } From a81e28065cf680d0ac5673fbfd06c87ecd93ca36 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Wed, 6 Nov 2024 16:25:21 +0800 Subject: [PATCH 173/258] feat: adjust css --- apps/frontend/src/app/question/[id]/page.tsx | 10 ++- .../src/app/question/[id]/styles.scss | 71 ++----------------- 2 files changed, 12 insertions(+), 69 deletions(-) diff --git a/apps/frontend/src/app/question/[id]/page.tsx b/apps/frontend/src/app/question/[id]/page.tsx index 274136a2aa..277228f5c3 100644 --- a/apps/frontend/src/app/question/[id]/page.tsx +++ b/apps/frontend/src/app/question/[id]/page.tsx @@ -227,7 +227,7 @@ export default function QuestionPage() { visibleTestcases={visibleTestCases} /> -
+
@@ -280,6 +280,10 @@ export default function QuestionPage() { visibility: `${ isSubmissionLoading ? "hidden" : "visible" }`, + + display: "flex", + flexDirection: "column", + height: "100%", }} >
@@ -330,8 +334,8 @@ export default function QuestionPage() { {/* Code Editor */}
Date: Wed, 6 Nov 2024 23:17:35 +0800 Subject: [PATCH 174/258] feat: implement rabbitmq msg queue --- apps/execution-service/go.mod | 1 + apps/execution-service/go.sum | 2 + apps/execution-service/handlers/submit.go | 58 ++++++------ apps/execution-service/main.go | 17 ++-- .../messagequeue/rabbitmq.go | 61 +++++++++++++ apps/execution-service/utils/log.go | 9 ++ apps/history-service/databases/history.go | 32 +++++++ apps/history-service/go.mod | 1 + apps/history-service/go.sum | 2 + apps/history-service/handlers/create.go | 19 +--- apps/history-service/main.go | 15 +-- apps/history-service/messagequeue/rabbitmq.go | 91 +++++++++++++++++++ apps/history-service/utils/log.go | 9 ++ 13 files changed, 259 insertions(+), 58 deletions(-) create mode 100644 apps/execution-service/messagequeue/rabbitmq.go create mode 100644 apps/execution-service/utils/log.go create mode 100644 apps/history-service/databases/history.go create mode 100644 apps/history-service/messagequeue/rabbitmq.go create mode 100644 apps/history-service/utils/log.go diff --git a/apps/execution-service/go.mod b/apps/execution-service/go.mod index 32a516cf23..aff484d2a7 100644 --- a/apps/execution-service/go.mod +++ b/apps/execution-service/go.mod @@ -31,6 +31,7 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/googleapis/gax-go/v2 v2.13.0 // indirect + github.com/rabbitmq/amqp091-go v1.10.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect diff --git a/apps/execution-service/go.sum b/apps/execution-service/go.sum index 7d3c75e147..8a595690fa 100644 --- a/apps/execution-service/go.sum +++ b/apps/execution-service/go.sum @@ -85,6 +85,8 @@ github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwA github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw= +github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/apps/execution-service/handlers/submit.go b/apps/execution-service/handlers/submit.go index 0bd06656a3..44cfa3d49e 100644 --- a/apps/execution-service/handlers/submit.go +++ b/apps/execution-service/handlers/submit.go @@ -1,16 +1,16 @@ package handlers import ( - "bytes" "encoding/json" "execution-service/constants" + "execution-service/messagequeue" "execution-service/models" "execution-service/utils" "fmt" + "net/http" + "github.com/go-chi/chi/v5" "google.golang.org/api/iterator" - "net/http" - "os" ) func (s *Service) ExecuteVisibleAndHiddenTestsAndSubmit(w http.ResponseWriter, r *http.Request) { @@ -84,33 +84,39 @@ func (s *Service) ExecuteVisibleAndHiddenTestsAndSubmit(w http.ResponseWriter, r return } - // get history-service url from os env - historyServiceUrl := os.Getenv("HISTORY_SERVICE_URL") - if historyServiceUrl == "" { - http.Error(w, "HISTORY_SERVICE_URL is not set", http.StatusInternalServerError) - return - } - - req, err := http.NewRequest(http.MethodPost, historyServiceUrl+"histories", - bytes.NewBuffer(jsonData)) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - req.Header.Set("Content-Type", "application/json") - - client := &http.Client{} - resp, err := client.Do(req) + err = messagequeue.PublishSubmissionMessage(jsonData) if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, fmt.Sprintf("Failed to save submission history: %v", err), http.StatusInternalServerError) return } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - http.Error(w, "Failed to save submission history", http.StatusInternalServerError) - } + // get history-service url from os env + // historyServiceUrl := os.Getenv("HISTORY_SERVICE_URL") + // if historyServiceUrl == "" { + // http.Error(w, "HISTORY_SERVICE_URL is not set", http.StatusInternalServerError) + // return + // } + + // req, err := http.NewRequest(http.MethodPost, historyServiceUrl+"histories", + // bytes.NewBuffer(jsonData)) + // if err != nil { + // http.Error(w, err.Error(), http.StatusInternalServerError) + // return + // } + + // req.Header.Set("Content-Type", "application/json") + + // client := &http.Client{} + // resp, err := client.Do(req) + // if err != nil { + // http.Error(w, err.Error(), http.StatusInternalServerError) + // return + // } + // defer resp.Body.Close() + + // if resp.StatusCode != http.StatusOK { + // http.Error(w, "Failed to save submission history", http.StatusInternalServerError) + // } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) diff --git a/apps/execution-service/main.go b/apps/execution-service/main.go index 706d0afcd6..f5f4bfe4c2 100644 --- a/apps/execution-service/main.go +++ b/apps/execution-service/main.go @@ -3,6 +3,8 @@ package main import ( "context" "execution-service/handlers" + "execution-service/messagequeue" + "execution-service/utils" "fmt" "log" "net/http" @@ -21,16 +23,15 @@ import ( func main() { // Load .env file err := godotenv.Load() - if err != nil { - log.Fatal("Error loading .env file") - } + utils.FailOnError(err, "Error loading .env file") + + amqpChannel := messagequeue.InitRabbitMQServer() + defer amqpChannel.Close() // Initialize Firestore client ctx := context.Background() client, err := initFirestore(ctx) - if err != nil { - log.Fatalf("Failed to initialize Firestore client: %v", err) - } + utils.FailOnError(err, "Failed to initialize Firestore client") defer client.Close() service := &handlers.Service{Client: client} @@ -107,7 +108,5 @@ func initRestServer(r *chi.Mux) { // Start the server log.Printf("Starting REST server on http://localhost:%s", port) err := http.ListenAndServe(fmt.Sprintf(":%s", port), r) - if err != nil { - log.Fatalf("Failed to start server: %v", err) - } + utils.FailOnError(err, "Failed to start REST server") } diff --git a/apps/execution-service/messagequeue/rabbitmq.go b/apps/execution-service/messagequeue/rabbitmq.go new file mode 100644 index 0000000000..0eaa731e7f --- /dev/null +++ b/apps/execution-service/messagequeue/rabbitmq.go @@ -0,0 +1,61 @@ +package messagequeue + +import ( + "execution-service/utils" + "fmt" + "log" + "os" + + amqp "github.com/rabbitmq/amqp091-go" +) + +const CODE_SUBMISSION_QUEUE_KEY = "code-submission" + +var ( + codeSubmissionQueue amqp.Queue + rabbitMQChannel *amqp.Channel +) + +func InitRabbitMQServer() *amqp.Channel { + // Connect to RabbitMQ server + rabbitMQURL := os.Getenv("RABBITMQ_URL") + conn, err := amqp.Dial(rabbitMQURL) + utils.FailOnError(err, "Failed to connect to RabbitMQ") + defer conn.Close() + + // Create a channel + ch, err := conn.Channel() + utils.FailOnError(err, "Failed to open a channel") + rabbitMQChannel = ch + + // Declare a queue + q, err := ch.QueueDeclare( + CODE_SUBMISSION_QUEUE_KEY, // name + false, // durable + false, // delete when unused + false, // exclusive + false, // no-wait + nil, // arguments + ) + utils.FailOnError(err, "Failed to declare a queue") + codeSubmissionQueue = q + + return ch +} + +func PublishSubmissionMessage(submission []byte) error { + err := rabbitMQChannel.Publish( + "", // exchange + codeSubmissionQueue.Name, // routing key + false, // mandatory + false, // immediate + amqp.Publishing{ + ContentType: "application/json", + Body: submission, + }) + if err != nil { + return fmt.Errorf("Failed to publish a message: %v", err) + } + log.Printf("RabbitMQ: [x] Sent %s", submission) + return nil +} diff --git a/apps/execution-service/utils/log.go b/apps/execution-service/utils/log.go new file mode 100644 index 0000000000..a77b2c29ca --- /dev/null +++ b/apps/execution-service/utils/log.go @@ -0,0 +1,9 @@ +package utils + +import "log" + +func FailOnError(err error, msg string) { + if err != nil { + log.Fatalf("%s: %s", msg, err) + } +} diff --git a/apps/history-service/databases/history.go b/apps/history-service/databases/history.go new file mode 100644 index 0000000000..e9b41e4b14 --- /dev/null +++ b/apps/history-service/databases/history.go @@ -0,0 +1,32 @@ +package databases + +import ( + "context" + "history-service/models" + + "cloud.google.com/go/firestore" +) + +func CreateHistory(client *firestore.Client, ctx context.Context, submissionHistory models.SubmissionHistory) (*firestore.DocumentRef, error) { + // Document reference ID in firestore mapped to the match ID in model + collection := client.Collection("collaboration-history") + + docRef, _, err := collection.Add(ctx, map[string]interface{}{ + "title": submissionHistory.Title, + "code": submissionHistory.Code, + "language": submissionHistory.Language, + "user": submissionHistory.User, + "matchedUser": submissionHistory.MatchedUser, + "matchedTopics": submissionHistory.MatchedTopics, + "questionDocRefId": submissionHistory.QuestionDocRefID, + "questionDifficulty": submissionHistory.QuestionDifficulty, + "questionTopics": submissionHistory.QuestionTopics, + "status": submissionHistory.Status, + "createdAt": firestore.ServerTimestamp, + "updatedAt": firestore.ServerTimestamp, + }) + if err != nil { + return nil, err + } + return docRef, nil +} diff --git a/apps/history-service/go.mod b/apps/history-service/go.mod index 37d6005bf1..2bdb4f0c8a 100644 --- a/apps/history-service/go.mod +++ b/apps/history-service/go.mod @@ -31,6 +31,7 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/googleapis/gax-go/v2 v2.13.0 // indirect + github.com/rabbitmq/amqp091-go v1.10.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect diff --git a/apps/history-service/go.sum b/apps/history-service/go.sum index ce7234e8f6..fbc00bcfaa 100644 --- a/apps/history-service/go.sum +++ b/apps/history-service/go.sum @@ -85,6 +85,8 @@ github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwA github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw= +github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/apps/history-service/handlers/create.go b/apps/history-service/handlers/create.go index 3dc635d0dd..e4868730b7 100644 --- a/apps/history-service/handlers/create.go +++ b/apps/history-service/handlers/create.go @@ -2,11 +2,11 @@ package handlers import ( "encoding/json" + "history-service/databases" "history-service/models" "history-service/utils" "net/http" - "cloud.google.com/go/firestore" "google.golang.org/api/iterator" ) @@ -22,22 +22,7 @@ func (s *Service) CreateHistory(w http.ResponseWriter, r *http.Request) { } // Document reference ID in firestore mapped to the match ID in model - collection := s.Client.Collection("collaboration-history") - - docRef, _, err := collection.Add(ctx, map[string]interface{}{ - "title": submissionHistory.Title, - "code": submissionHistory.Code, - "language": submissionHistory.Language, - "user": submissionHistory.User, - "matchedUser": submissionHistory.MatchedUser, - "matchedTopics": submissionHistory.MatchedTopics, - "questionDocRefId": submissionHistory.QuestionDocRefID, - "questionDifficulty": submissionHistory.QuestionDifficulty, - "questionTopics": submissionHistory.QuestionTopics, - "status": submissionHistory.Status, - "createdAt": firestore.ServerTimestamp, - "updatedAt": firestore.ServerTimestamp, - }) + docRef, err := databases.CreateHistory(s.Client, ctx, submissionHistory) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/apps/history-service/main.go b/apps/history-service/main.go index 751f2ed525..9d22656df1 100644 --- a/apps/history-service/main.go +++ b/apps/history-service/main.go @@ -3,7 +3,10 @@ package main import ( "context" "fmt" + "history-service/databases" "history-service/handlers" + "history-service/messagequeue" + "history-service/utils" "log" "net/http" "os" @@ -20,20 +23,20 @@ import ( func main() { err := godotenv.Load() - if err != nil { - log.Fatal("Error loading .env file") - } + utils.FailOnError(err, "Error loading .env file") // Initialize Firestore client ctx := context.Background() client, err := initFirestore(ctx) - if err != nil { - log.Fatalf("Failed to initialize Firestore client: %v", err) - } + utils.FailOnError(err, "Failed to initialize Firestore client") defer client.Close() service := &handlers.Service{Client: client} + amqpChannel := messagequeue.InitRabbitMQServer() + defer amqpChannel.Close() + messagequeue.ConsumeSubmissionMessages(client, databases.CreateHistory) + r := initChiRouter(service) initRestServer(r) } diff --git a/apps/history-service/messagequeue/rabbitmq.go b/apps/history-service/messagequeue/rabbitmq.go new file mode 100644 index 0000000000..9b42aeed84 --- /dev/null +++ b/apps/history-service/messagequeue/rabbitmq.go @@ -0,0 +1,91 @@ +package messagequeue + +import ( + "context" + "encoding/json" + "history-service/models" + "history-service/utils" + "log" + "os" + + "cloud.google.com/go/firestore" + amqp "github.com/rabbitmq/amqp091-go" +) + +const CODE_SUBMISSION_QUEUE_KEY = "code-submission" + +var ( + codeSubmissionQueue amqp.Queue + rabbitMQChannel *amqp.Channel +) + +func InitRabbitMQServer() *amqp.Channel { + // Connect to RabbitMQ server + rabbitMQURL := os.Getenv("RABBITMQ_URL") + conn, err := amqp.Dial(rabbitMQURL) + utils.FailOnError(err, "Failed to connect to RabbitMQ") + defer conn.Close() + + // Create a channel + ch, err := conn.Channel() + utils.FailOnError(err, "Failed to open a channel") + rabbitMQChannel = ch + defer ch.Close() + + // Declare a queue + q, err := ch.QueueDeclare( + "code-submission", // name + false, // durable + false, // delete when unused + false, // exclusive + false, // no-wait + nil, // arguments + ) + utils.FailOnError(err, "Failed to declare a queue") + codeSubmissionQueue = q + + return ch +} + +func ConsumeSubmissionMessages(client *firestore.Client, createSubmission func( + *firestore.Client, context.Context, models.SubmissionHistory) ( + *firestore.DocumentRef, error)) { + ctx := context.Background() + + // Consume messages from the queue + msgs, err := rabbitMQChannel.Consume( + codeSubmissionQueue.Name, // queue + "", // consumer + true, // auto-ack + false, // exclusive + false, // no-local + false, // no-wait + nil, // args + ) + utils.FailOnError(err, "Failed to register a consumer") + + // Create a channel to block indefinitely + forever := make(chan bool) + + // Start a goroutine to handle incoming messages + go func() { + for d := range msgs { + log.Printf("RabbitMQ: Received a message: %v", d) + + // Parse request + var submissionHistory models.SubmissionHistory + if err := json.Unmarshal(d.Body, &submissionHistory); err != nil { + log.Printf("RabbitMQ: Error decoding JSON: %v", err) + continue + } + + _, err := createSubmission(client, ctx, submissionHistory) + if err != nil { + log.Printf("RabbitMQ: %v", err) + } + } + }() + + log.Printf("RabbitMQ: [*] Waiting for messages.") + <-forever +} diff --git a/apps/history-service/utils/log.go b/apps/history-service/utils/log.go new file mode 100644 index 0000000000..a77b2c29ca --- /dev/null +++ b/apps/history-service/utils/log.go @@ -0,0 +1,9 @@ +package utils + +import "log" + +func FailOnError(err error, msg string) { + if err != nil { + log.Fatalf("%s: %s", msg, err) + } +} From e48bc7ea91cf62bb9661613fefe0194b71ed3525 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Wed, 6 Nov 2024 23:17:41 +0800 Subject: [PATCH 175/258] feat: update docker compose --- apps/docker-compose.yml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/docker-compose.yml b/apps/docker-compose.yml index a0565fe1dd..18a2242be8 100644 --- a/apps/docker-compose.yml +++ b/apps/docker-compose.yml @@ -68,7 +68,7 @@ services: - apps_network volumes: - ./history-service:/history-service - + signalling-service: build: context: ./signalling-service @@ -104,6 +104,19 @@ services: - 6379:6379 container_name: redis-container + rabbit-mq: + image: rabbitmq:3-management + networks: + - apps_network + ports: + - 5672:5672 # Port for RabbitMQ message broker + - 15672:15672 # Port for RabbitMQ Management UI + environment: + RABBITMQ_DEFAULT_USER: guest + RABBITMQ_DEFAULT_PASS: guest + volumes: + - rabbitmq_data:/var/lib/rabbitmq + python-sandbox: build: context: ./execution-service/execution/python @@ -114,3 +127,8 @@ services: networks: apps_network: + +volumes: + # Mounts a volume for RabbitMQ data persistence. + # This ensures that data is not lost when the container is restarted or removed. + rabbitmq_data: From 64a1badcfebdedcef17f31d6539c747b05481588 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Thu, 7 Nov 2024 00:33:50 +0800 Subject: [PATCH 176/258] fix: update docker-compose --- apps/docker-compose.yml | 6 ++- apps/execution-service/.env.example | 2 + apps/execution-service/main.go | 7 ++-- .../messagequeue/rabbitmq.go | 33 +++++++++++++---- apps/history-service/.env.example | 8 +++- apps/history-service/main.go | 5 ++- apps/history-service/messagequeue/rabbitmq.go | 37 ++++++++++++++----- 7 files changed, 73 insertions(+), 25 deletions(-) diff --git a/apps/docker-compose.yml b/apps/docker-compose.yml index 18a2242be8..12d02b5661 100644 --- a/apps/docker-compose.yml +++ b/apps/docker-compose.yml @@ -68,6 +68,8 @@ services: - apps_network volumes: - ./history-service:/history-service + depends_on: + - rabbitmq signalling-service: build: @@ -95,6 +97,8 @@ services: volumes: - ./execution-service:/execution-service - /var/run/docker.sock:/var/run/docker.sock + depends_on: + - rabbitmq redis: image: redis:latest @@ -104,7 +108,7 @@ services: - 6379:6379 container_name: redis-container - rabbit-mq: + rabbitmq: image: rabbitmq:3-management networks: - apps_network diff --git a/apps/execution-service/.env.example b/apps/execution-service/.env.example index 6a1fb0bd86..4122078fbd 100644 --- a/apps/execution-service/.env.example +++ b/apps/execution-service/.env.example @@ -3,6 +3,8 @@ PORT=8083 # If you are NOT USING docker, use the below variables # HISTORY_SERVICE_URL=http://localhost:8082/ +# RABBITMQ_URL=amqp://guest:guest@localhost:5672/ # If you are USING docker, use the below variables HISTORY_SERVICE_URL=http://history-service:8082/ +RABBITMQ_URL=amqp://guest:guest@rabbitmq:5672/ diff --git a/apps/execution-service/main.go b/apps/execution-service/main.go index f5f4bfe4c2..e2da2948be 100644 --- a/apps/execution-service/main.go +++ b/apps/execution-service/main.go @@ -25,9 +25,6 @@ func main() { err := godotenv.Load() utils.FailOnError(err, "Error loading .env file") - amqpChannel := messagequeue.InitRabbitMQServer() - defer amqpChannel.Close() - // Initialize Firestore client ctx := context.Background() client, err := initFirestore(ctx) @@ -36,6 +33,10 @@ func main() { service := &handlers.Service{Client: client} + amqpConnection, amqpChannel := messagequeue.InitRabbitMQServer() + defer amqpConnection.Close() + defer amqpChannel.Close() + r := initChiRouter(service) initRestServer(r) } diff --git a/apps/execution-service/messagequeue/rabbitmq.go b/apps/execution-service/messagequeue/rabbitmq.go index 0eaa731e7f..1a6aafcde7 100644 --- a/apps/execution-service/messagequeue/rabbitmq.go +++ b/apps/execution-service/messagequeue/rabbitmq.go @@ -5,23 +5,23 @@ import ( "fmt" "log" "os" + "time" amqp "github.com/rabbitmq/amqp091-go" ) -const CODE_SUBMISSION_QUEUE_KEY = "code-submission" +const ( + CODE_SUBMISSION_QUEUE_KEY = "code-submission" + NUM_RETRIES = 10 +) var ( codeSubmissionQueue amqp.Queue rabbitMQChannel *amqp.Channel ) -func InitRabbitMQServer() *amqp.Channel { - // Connect to RabbitMQ server - rabbitMQURL := os.Getenv("RABBITMQ_URL") - conn, err := amqp.Dial(rabbitMQURL) - utils.FailOnError(err, "Failed to connect to RabbitMQ") - defer conn.Close() +func InitRabbitMQServer() (*amqp.Connection, *amqp.Channel) { + conn := connectToRabbitMQ() // Create a channel ch, err := conn.Channel() @@ -40,7 +40,24 @@ func InitRabbitMQServer() *amqp.Channel { utils.FailOnError(err, "Failed to declare a queue") codeSubmissionQueue = q - return ch + return conn, ch +} + +func connectToRabbitMQ() *amqp.Connection { + var conn *amqp.Connection + var err error + rabbitMQURL := os.Getenv("RABBITMQ_URL") + for i := 0; i < NUM_RETRIES; i++ { // Retry up to 10 times + conn, err = amqp.Dial(rabbitMQURL) + if err == nil { + log.Println("Connected to RabbitMQ") + return conn + } + log.Printf("Failed to connect to RabbitMQ, retrying in 5 seconds... (Attempt %d/%d)", i+1, NUM_RETRIES) + time.Sleep(5 * time.Second) + } + utils.FailOnError(err, fmt.Sprintf("Failed to connect to RabbitMQ after %d attempts", NUM_RETRIES)) + return nil } func PublishSubmissionMessage(submission []byte) error { diff --git a/apps/history-service/.env.example b/apps/history-service/.env.example index b3bd4db2b4..0f3f18c101 100644 --- a/apps/history-service/.env.example +++ b/apps/history-service/.env.example @@ -1,2 +1,8 @@ FIREBASE_CREDENTIAL_PATH=cs3219-staging-codehisto-bb61c-firebase-adminsdk-egopb-95cfaf9b87.json -PORT=8082 \ No newline at end of file +PORT=8082 + +# If you are NOT USING docker, use the below variables +# RABBITMQ_URL=amqp://guest:guest@localhost:5672/ + +# If you are USING docker, use the below variables +RABBITMQ_URL=amqp://guest:guest@rabbitmq:5672/ \ No newline at end of file diff --git a/apps/history-service/main.go b/apps/history-service/main.go index 9d22656df1..1b79073caf 100644 --- a/apps/history-service/main.go +++ b/apps/history-service/main.go @@ -33,9 +33,10 @@ func main() { service := &handlers.Service{Client: client} - amqpChannel := messagequeue.InitRabbitMQServer() + amqpConnection, amqpChannel := messagequeue.InitRabbitMQServer() + defer amqpConnection.Close() defer amqpChannel.Close() - messagequeue.ConsumeSubmissionMessages(client, databases.CreateHistory) + go messagequeue.ConsumeSubmissionMessages(client, databases.CreateHistory) r := initChiRouter(service) initRestServer(r) diff --git a/apps/history-service/messagequeue/rabbitmq.go b/apps/history-service/messagequeue/rabbitmq.go index 9b42aeed84..3b0e0293af 100644 --- a/apps/history-service/messagequeue/rabbitmq.go +++ b/apps/history-service/messagequeue/rabbitmq.go @@ -3,34 +3,34 @@ package messagequeue import ( "context" "encoding/json" + "fmt" "history-service/models" "history-service/utils" "log" "os" + "time" "cloud.google.com/go/firestore" amqp "github.com/rabbitmq/amqp091-go" ) -const CODE_SUBMISSION_QUEUE_KEY = "code-submission" +const ( + CODE_SUBMISSION_QUEUE_KEY = "code-submission" + NUM_RETRIES = 10 +) var ( codeSubmissionQueue amqp.Queue rabbitMQChannel *amqp.Channel ) -func InitRabbitMQServer() *amqp.Channel { - // Connect to RabbitMQ server - rabbitMQURL := os.Getenv("RABBITMQ_URL") - conn, err := amqp.Dial(rabbitMQURL) - utils.FailOnError(err, "Failed to connect to RabbitMQ") - defer conn.Close() +func InitRabbitMQServer() (*amqp.Connection, *amqp.Channel) { + conn := connectToRabbitMQ() // Create a channel ch, err := conn.Channel() utils.FailOnError(err, "Failed to open a channel") rabbitMQChannel = ch - defer ch.Close() // Declare a queue q, err := ch.QueueDeclare( @@ -44,7 +44,24 @@ func InitRabbitMQServer() *amqp.Channel { utils.FailOnError(err, "Failed to declare a queue") codeSubmissionQueue = q - return ch + return conn, ch +} + +func connectToRabbitMQ() *amqp.Connection { + var conn *amqp.Connection + var err error + rabbitMQURL := os.Getenv("RABBITMQ_URL") + for i := 0; i < NUM_RETRIES; i++ { // Retry up to 10 times + conn, err = amqp.Dial(rabbitMQURL) + if err == nil { + log.Println("Connected to RabbitMQ") + return conn + } + log.Printf("Failed to connect to RabbitMQ, retrying in 5 seconds... (Attempt %d/%d)", i+1, NUM_RETRIES) + time.Sleep(5 * time.Second) + } + utils.FailOnError(err, fmt.Sprintf("Failed to connect to RabbitMQ after %d attempts", NUM_RETRIES)) + return nil } func ConsumeSubmissionMessages(client *firestore.Client, createSubmission func( @@ -62,7 +79,7 @@ func ConsumeSubmissionMessages(client *firestore.Client, createSubmission func( false, // no-wait nil, // args ) - utils.FailOnError(err, "Failed to register a consumer") + utils.FailOnError(err, "RabbitMQ: Failed to register a consumer") // Create a channel to block indefinitely forever := make(chan bool) From fbd3a4de76d4f1254c6943c01dc40f14816d7fde Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Thu, 7 Nov 2024 00:45:09 +0800 Subject: [PATCH 177/258] feat: update log msg --- apps/history-service/messagequeue/rabbitmq.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/history-service/messagequeue/rabbitmq.go b/apps/history-service/messagequeue/rabbitmq.go index 3b0e0293af..f945a866d0 100644 --- a/apps/history-service/messagequeue/rabbitmq.go +++ b/apps/history-service/messagequeue/rabbitmq.go @@ -87,7 +87,7 @@ func ConsumeSubmissionMessages(client *firestore.Client, createSubmission func( // Start a goroutine to handle incoming messages go func() { for d := range msgs { - log.Printf("RabbitMQ: Received a message: %v", d) + log.Printf("RabbitMQ: Received a message") // Parse request var submissionHistory models.SubmissionHistory From 8bd3d10c71bf007fb2723d5fcd81ef45e088e36a Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Thu, 7 Nov 2024 00:52:29 +0800 Subject: [PATCH 178/258] feat: update readme --- apps/execution-service/README.md | 121 +++++++++++++++++++------------ apps/history-service/README.md | 25 +++++++ 2 files changed, 98 insertions(+), 48 deletions(-) diff --git a/apps/execution-service/README.md b/apps/execution-service/README.md index 2961ed152e..51322d38a0 100644 --- a/apps/execution-service/README.md +++ b/apps/execution-service/README.md @@ -74,10 +74,10 @@ The following json format will be returned: ```json [ - { - "input":"hello", - "expected":"olleh" - } + { + "input": "hello", + "expected": "olleh" + } ] ``` @@ -98,16 +98,16 @@ The following json format will be returned: ```json { - "visibleTestResults":[ + "visibleTestResults": [ { - "input":"hello", - "expected":"olleh", - "actual":"olleh", - "passed":true, - "error":"" + "input": "hello", + "expected": "olleh", + "actual": "olleh", + "passed": true, + "error": "" } ], - "customTestResults":null + "customTestResults": null } ``` @@ -127,29 +127,29 @@ The following json format will be returned: ```json { - "visibleTestResults":[ + "visibleTestResults": [ { - "input":"hello", - "expected":"olleh", - "actual":"olleh", - "passed":true, - "error":"" + "input": "hello", + "expected": "olleh", + "actual": "olleh", + "passed": true, + "error": "" } ], - "customTestResults":[ + "customTestResults": [ { - "input":"Hannah", - "expected":"hannaH", - "actual":"hannaH", - "passed":true, - "error":"" + "input": "Hannah", + "expected": "hannaH", + "actual": "hannaH", + "passed": true, + "error": "" }, { - "input":"abcdefg", - "expected":"gfedcba", - "actual":"gfedcba", - "passed":true, - "error":"" + "input": "abcdefg", + "expected": "gfedcba", + "actual": "gfedcba", + "passed": true, + "error": "" } ] } @@ -178,20 +178,20 @@ The following json format will be returned: ```json { - "visibleTestResults":[ + "visibleTestResults": [ { - "input":"hello", - "expected":"olleh", - "actual":"olleh", - "passed":true, - "error":"" + "input": "hello", + "expected": "olleh", + "actual": "olleh", + "passed": true, + "error": "" } ], - "hiddenTestResults":{ - "passed":2, - "total":2 + "hiddenTestResults": { + "passed": 2, + "total": 2 }, - "status":"Accepted" + "status": "Accepted" } ``` @@ -199,19 +199,44 @@ If compilation error exists or any of the tests (visible and hidden) fails, stat ```json { - "visibleTestResults":[ + "visibleTestResults": [ { - "input":"hello", - "expected":"olleh", - "actual":"", - "passed":false, - "error":"Command execution failed: Traceback (most recent call last):\n File \"/tmp/4149249165.py\", line 2, in \u003cmodule\u003e\n prit(name[::-1])\n ^^^^\nNameError: name 'prit' is not defined. Did you mean: 'print'?\n: %!w(*exec.ExitError=\u0026{0x4000364678 []})" + "input": "hello", + "expected": "olleh", + "actual": "", + "passed": false, + "error": "Command execution failed: Traceback (most recent call last):\n File \"/tmp/4149249165.py\", line 2, in \u003cmodule\u003e\n prit(name[::-1])\n ^^^^\nNameError: name 'prit' is not defined. Did you mean: 'print'?\n: %!w(*exec.ExitError=\u0026{0x4000364678 []})" } ], - "hiddenTestResults":{ - "passed":0, - "total":2 + "hiddenTestResults": { + "passed": 0, + "total": 2 }, - "status":"Attempted" + "status": "Attempted" } ``` + +## Setting up message queue with history-service + +A message queue is used to pass submission results asynchronously from the execution-service to the history-service. + +1. In order to do so, we can run the following command to set up a docker container for rabbitmq: + +```bash +docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management +``` + +2. Then we can run the execution-service: + +```bash +go run main.go +``` + +3. We can run the history-service by changing our directory and running the same command: + +```bash +cd ../history-service +go run main.go +``` + +To view more details on the RabbitMQ queue, we can go to `localhost:15672`. diff --git a/apps/history-service/README.md b/apps/history-service/README.md index 681c629bcd..13e416c0c3 100644 --- a/apps/history-service/README.md +++ b/apps/history-service/README.md @@ -73,3 +73,28 @@ The server will be available at http://localhost:8082. ```bash go run main.go ``` + +## Setting up message queue with history-service + +A message queue is used to pass submission results asynchronously from the execution-service to the history-service. + +1. In order to do so, we can run the following command to set up a docker container for rabbitmq: + +```bash +docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management +``` + +2. Then we can run the history-service: + +```bash +go run main.go +``` + +3. We can run the execution-service by changing our directory and running the same command: + +```bash +cd ../execution-service +go run main.go +``` + +To view more details on the RabbitMQ queue, we can go to `localhost:15672`. From b8e3004f8d21268f0f7c42eec4fe3deb83b53203 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Thu, 7 Nov 2024 00:54:53 +0800 Subject: [PATCH 179/258] docs: update readme --- apps/execution-service/README.md | 2 +- apps/history-service/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/execution-service/README.md b/apps/execution-service/README.md index 51322d38a0..434f3e6778 100644 --- a/apps/execution-service/README.md +++ b/apps/execution-service/README.md @@ -216,7 +216,7 @@ If compilation error exists or any of the tests (visible and hidden) fails, stat } ``` -## Setting up message queue with history-service +## Setting up message queue with RabbitMQ A message queue is used to pass submission results asynchronously from the execution-service to the history-service. diff --git a/apps/history-service/README.md b/apps/history-service/README.md index 13e416c0c3..b6dd62e07b 100644 --- a/apps/history-service/README.md +++ b/apps/history-service/README.md @@ -74,7 +74,7 @@ The server will be available at http://localhost:8082. go run main.go ``` -## Setting up message queue with history-service +## Setting up message queue with RabbitMQ A message queue is used to pass submission results asynchronously from the execution-service to the history-service. From bf0c096955050d55b544b487a70f617eb284def6 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Thu, 7 Nov 2024 01:07:32 +0800 Subject: [PATCH 180/258] docs: update readme --- apps/execution-service/README.md | 2 +- apps/history-service/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/execution-service/README.md b/apps/execution-service/README.md index 434f3e6778..f78028505b 100644 --- a/apps/execution-service/README.md +++ b/apps/execution-service/README.md @@ -220,7 +220,7 @@ If compilation error exists or any of the tests (visible and hidden) fails, stat A message queue is used to pass submission results asynchronously from the execution-service to the history-service. -1. In order to do so, we can run the following command to set up a docker container for rabbitmq: +1. In order to do so, we can run the following command to set up a docker container for RabbitMQ: ```bash docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management diff --git a/apps/history-service/README.md b/apps/history-service/README.md index b6dd62e07b..23de7f0e11 100644 --- a/apps/history-service/README.md +++ b/apps/history-service/README.md @@ -78,7 +78,7 @@ go run main.go A message queue is used to pass submission results asynchronously from the execution-service to the history-service. -1. In order to do so, we can run the following command to set up a docker container for rabbitmq: +1. In order to do so, we can run the following command to set up a docker container for RabbitMQ: ```bash docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management From 95a82dc161702934cf68a40368d3a74ab2235fe4 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Thu, 7 Nov 2024 01:10:12 +0800 Subject: [PATCH 181/258] ci: update docker compose test --- .github/workflows/test.yml | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 90408360b4..706ccbed1b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v2 - + - name: Set up .env env: QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} @@ -30,7 +30,7 @@ jobs: echo "FIREBASE_CREDENTIAL_PATH=$QUESTION_FIREBASE_CREDENTIAL_PATH" >> .env echo "JWT_SECRET=$JWT_SECRET" >> .env echo "EXECUTION_SERVICE_URL=$EXECUTION_SERVICE_URL" >> .env - + - name: Set up credentials env: QUESTION_FIREBASE_JSON: ${{ secrets.QUESTION_SERVICE_FIREBASE_CREDENTIAL }} @@ -41,8 +41,8 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 - with: - go-version: '1.23.x' + with: + go-version: "1.23.x" - name: Install Go dependencies run: | @@ -51,7 +51,7 @@ jobs: - name: Install firebase tools run: curl -sL firebase.tools | bash - + - name: Run Go tests with Firebase emulator run: firebase emulators:exec --only firestore 'cd ./apps/question-service; go test -v ./tests' @@ -66,11 +66,11 @@ jobs: run: | cd ./apps/frontend cp .env.example .env - + - name: Set up Node.js uses: actions/setup-node@v2 with: - node-version: '22' + node-version: "22" - name: Install pnpm run: npm i -g pnpm @@ -117,6 +117,7 @@ jobs: EXECUTION_SERVICE_PORT: ${{ vars.EXECUTION_SERVICE_PORT }} MATCHING_SERVICE_TIMEOUT: ${{ vars.MATCHING_SERVICE_TIMEOUT }} REDIS_URL: ${{ vars.REDIS_URL }} + RABBITMQ_URL: ${{ vars.RABBITMQ_URL }} QUESTION_SERVICE_GRPC_URL: ${{ vars.QUESTION_SERVICE_GPRC_URL }} run: | cd ./apps/frontend @@ -147,11 +148,13 @@ jobs: cd ../history-service echo "FIREBASE_CREDENTIAL_PATH=$HISTORY_FIREBASE_CREDENTIAL_PATH" >> .env echo "PORT=$HISTORY_SERVICE_PORT" >> .env - + echo "RABBITMQ_URL=$RABBITMQ_URL" >> .env + cd ../execution-service echo "FIREBASE_CREDENTIAL_PATH=$EXECUTION_FIREBASE_CREDENTIAL_PATH" >> .env echo "PORT=$EXECUTION_SERVICE_PORT" >> .env echo "HISTORY_SERVICE_URL=$HISTORY_SERVICE_URL" >> .env + echo "RABBITMQ_URL=$RABBITMQ_URL" >> .env cd ../signalling-service echo "PORT=$SIGNALLING_SERVICE_PORT" >> .env @@ -170,7 +173,7 @@ jobs: cd ../history-service echo "$HISTORY_FIREBASE_JSON" > "./$HISTORY_FIREBASE_CREDENTIAL_PATH" - + cd ../execution-service echo "$EXECUTION_FIREBASE_JSON" > "./$EXECUTION_FIREBASE_CREDENTIAL_PATH" From 2b2bbd59a6c1be61563db2ee1e0e9ff7fc4b73cb Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Thu, 7 Nov 2024 01:12:41 +0800 Subject: [PATCH 182/258] docs: update readme --- apps/execution-service/README.md | 2 +- apps/history-service/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/execution-service/README.md b/apps/execution-service/README.md index f78028505b..88a6f0be5e 100644 --- a/apps/execution-service/README.md +++ b/apps/execution-service/README.md @@ -239,4 +239,4 @@ cd ../history-service go run main.go ``` -To view more details on the RabbitMQ queue, we can go to `localhost:15672`. +To view more details on the RabbitMQ queue, we can go to `localhost:15672`, and login using `guest` as the username and password. diff --git a/apps/history-service/README.md b/apps/history-service/README.md index 23de7f0e11..1da55307dd 100644 --- a/apps/history-service/README.md +++ b/apps/history-service/README.md @@ -97,4 +97,4 @@ cd ../execution-service go run main.go ``` -To view more details on the RabbitMQ queue, we can go to `localhost:15672`. +To view more details on the RabbitMQ queue, we can go to `localhost:15672`, and login using `guest` as the username and password. From fac44307e888ab2a9c72699fa6a329a847f224a7 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Thu, 7 Nov 2024 01:20:36 +0800 Subject: [PATCH 183/258] docs: update readme --- apps/execution-service/README.md | 52 ++++++++++++++++---------------- apps/history-service/README.md | 48 ++++++++++++++--------------- 2 files changed, 50 insertions(+), 50 deletions(-) diff --git a/apps/execution-service/README.md b/apps/execution-service/README.md index 88a6f0be5e..c53dc3ab9f 100644 --- a/apps/execution-service/README.md +++ b/apps/execution-service/README.md @@ -20,7 +20,32 @@ go run main.go The server will be available at http://localhost:8083. -## Running the Application via Docker +### Setting up message queue with RabbitMQ + +A message queue is used to pass submission results asynchronously from the execution-service to the history-service. + +1. In order to do so, we can run the following command to set up a docker container for RabbitMQ: + +```bash +docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management +``` + +2. Then we can run the execution-service: + +```bash +go run main.go +``` + +3. We can run the history-service by changing our directory and running the same command: + +```bash +cd ../history-service +go run main.go +``` + +To view more details on the RabbitMQ queue, we can go to `localhost:15672`, and login using `guest` as the username and password. + +### Running the Application via Docker To run the application via Docker, run the following command: @@ -215,28 +240,3 @@ If compilation error exists or any of the tests (visible and hidden) fails, stat "status": "Attempted" } ``` - -## Setting up message queue with RabbitMQ - -A message queue is used to pass submission results asynchronously from the execution-service to the history-service. - -1. In order to do so, we can run the following command to set up a docker container for RabbitMQ: - -```bash -docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management -``` - -2. Then we can run the execution-service: - -```bash -go run main.go -``` - -3. We can run the history-service by changing our directory and running the same command: - -```bash -cd ../history-service -go run main.go -``` - -To view more details on the RabbitMQ queue, we can go to `localhost:15672`, and login using `guest` as the username and password. diff --git a/apps/history-service/README.md b/apps/history-service/README.md index 1da55307dd..6fec9e5bbd 100644 --- a/apps/history-service/README.md +++ b/apps/history-service/README.md @@ -47,54 +47,54 @@ To start the server, run the following command: go run main.go ``` -The server will be available at http://localhost:8082. +### Setting up message queue with RabbitMQ -## Running the Application via Docker +A message queue is used to pass submission results asynchronously from the execution-service to the history-service. -To run the application via Docker, run the following command: +1. In order to do so, we can run the following command to set up a docker container for RabbitMQ: ```bash -docker build -t history-service . +docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management ``` +2. Then we can run the history-service: + ```bash -docker run -p 8082:8082 -d history-service +go run main.go ``` -The server will be available at http://localhost:8082. - -## API Endpoints - -- `POST /histories` -- `GET /histories/{docRefId}` -- `PUT /histories/{docRefId}` -- `DELETE /histories/{docRefId}` +3. We can run the execution-service by changing our directory and running the same command: ```bash +cd ../execution-service go run main.go ``` -## Setting up message queue with RabbitMQ +To view more details on the RabbitMQ queue, we can go to `localhost:15672`, and login using `guest` as the username and password. -A message queue is used to pass submission results asynchronously from the execution-service to the history-service. +The server will be available at http://localhost:8082. -1. In order to do so, we can run the following command to set up a docker container for RabbitMQ: +### Running the Application via Docker + +To run the application via Docker, run the following command: ```bash -docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management +docker build -t history-service . ``` -2. Then we can run the history-service: - ```bash -go run main.go +docker run -p 8082:8082 -d history-service ``` -3. We can run the execution-service by changing our directory and running the same command: +The server will be available at http://localhost:8082. + +## API Endpoints + +- `POST /histories` +- `GET /histories/{docRefId}` +- `PUT /histories/{docRefId}` +- `DELETE /histories/{docRefId}` ```bash -cd ../execution-service go run main.go ``` - -To view more details on the RabbitMQ queue, we can go to `localhost:15672`, and login using `guest` as the username and password. From d75215c120d6b03c06ac889be0e769fa4dc8122d Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Thu, 7 Nov 2024 10:40:15 +0800 Subject: [PATCH 184/258] style(execution-service): :fire: remove commented code Revmoes the previous commented implementation of sending the submission to history service via REST API call. --- apps/execution-service/handlers/submit.go | 29 ----------------------- 1 file changed, 29 deletions(-) diff --git a/apps/execution-service/handlers/submit.go b/apps/execution-service/handlers/submit.go index 44cfa3d49e..1411ffcea7 100644 --- a/apps/execution-service/handlers/submit.go +++ b/apps/execution-service/handlers/submit.go @@ -61,7 +61,6 @@ func (s *Service) ExecuteVisibleAndHiddenTestsAndSubmit(w http.ResponseWriter, r } // Save the collaboration history via the history-service - // TODO: convert to message queue submissionReq := models.Submission{ Code: submission.Code, Language: submission.Language, @@ -90,34 +89,6 @@ func (s *Service) ExecuteVisibleAndHiddenTestsAndSubmit(w http.ResponseWriter, r return } - // get history-service url from os env - // historyServiceUrl := os.Getenv("HISTORY_SERVICE_URL") - // if historyServiceUrl == "" { - // http.Error(w, "HISTORY_SERVICE_URL is not set", http.StatusInternalServerError) - // return - // } - - // req, err := http.NewRequest(http.MethodPost, historyServiceUrl+"histories", - // bytes.NewBuffer(jsonData)) - // if err != nil { - // http.Error(w, err.Error(), http.StatusInternalServerError) - // return - // } - - // req.Header.Set("Content-Type", "application/json") - - // client := &http.Client{} - // resp, err := client.Do(req) - // if err != nil { - // http.Error(w, err.Error(), http.StatusInternalServerError) - // return - // } - // defer resp.Body.Close() - - // if resp.StatusCode != http.StatusOK { - // http.Error(w, "Failed to save submission history", http.StatusInternalServerError) - // } - w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(testResults) From e5e41ce92afd50a32eef8e3889315ba4f56d4eaa Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Thu, 7 Nov 2024 14:07:00 +0800 Subject: [PATCH 185/258] fix(frontend): :bug: mounts component before accessing local storage Only access localStorage on the client side (in the browser) after the component has mounted. --- .../src/app/collaboration/[id]/page.tsx | 137 +++++++++++------- .../CollaborativeEditor.tsx | 47 +++--- .../src/components/VideoPanel/VideoPanel.tsx | 18 ++- 3 files changed, 118 insertions(+), 84 deletions(-) diff --git a/apps/frontend/src/app/collaboration/[id]/page.tsx b/apps/frontend/src/app/collaboration/[id]/page.tsx index 15c9c5dcd4..caa7469eea 100644 --- a/apps/frontend/src/app/collaboration/[id]/page.tsx +++ b/apps/frontend/src/app/collaboration/[id]/page.tsx @@ -31,7 +31,18 @@ import CollaborativeEditor, { } from "@/components/CollaborativeEditor/CollaborativeEditor"; import { CreateHistory } from "@/app/services/history"; import { WebrtcProvider } from "y-webrtc"; -import { ExecuteVisibleAndCustomTests, ExecuteVisibleAndHiddenTestsAndSubmit, ExecutionResults, GetVisibleTests, isTestResult, SubmissionHiddenTestResultsAndStatus, SubmissionResults, Test, TestData, TestResult } from "@/app/services/execute"; +import { + ExecuteVisibleAndCustomTests, + ExecuteVisibleAndHiddenTestsAndSubmit, + ExecutionResults, + GetVisibleTests, + isTestResult, + SubmissionHiddenTestResultsAndStatus, + SubmissionResults, + Test, + TestData, + TestResult, +} from "@/app/services/execute"; import { QuestionDetailFull } from "@/components/question/QuestionDetailFull/QuestionDetailFull"; import VideoPanel from "@/components/VideoPanel/VideoPanel"; @@ -69,15 +80,17 @@ export default function CollaborationPage(props: CollaborationProps) { ); const [currentUser, setCurrentUser] = useState(undefined); const [matchedUser, setMatchedUser] = useState("Loading..."); - const [sessionDuration, setSessionDuration] = useState(() => { - const storedTime = localStorage.getItem("session-duration"); - return storedTime ? parseInt(storedTime) : 0; - }); // State for count-up timer (TODO: currently using localstorage to store time, change to db stored time in the future) + const [sessionDuration, setSessionDuration] = useState(0); // State for count-up timer (TODO: currently using localstorage to store time, change to db stored time in the future) const stopwatchRef = useRef(null); const [matchedTopics, setMatchedTopics] = useState( undefined ); + useEffect(() => { + const storedTime = localStorage.getItem("session-duration"); + setSessionDuration(storedTime ? parseInt(storedTime) : 0); + }, []); + // Chat states const [messageToSend, setMessageToSend] = useState( undefined @@ -89,8 +102,12 @@ export default function CollaborationPage(props: CollaborationProps) { ); const [visibleTestCases, setVisibleTestCases] = useState([]); const [isLoadingTestCase, setIsLoadingTestCase] = useState(false); - const [isLoadingSubmission, setIsLoadingSubmission] = useState(false); - const [submissionHiddenTestResultsAndStatus, setSubmissionHiddenTestResultsAndStatus] = useState(undefined); + const [isLoadingSubmission, setIsLoadingSubmission] = + useState(false); + const [ + submissionHiddenTestResultsAndStatus, + setSubmissionHiddenTestResultsAndStatus, + ] = useState(undefined); // End Button Modal state const [isModalOpen, setIsModalOpen] = useState(false); @@ -151,7 +168,7 @@ export default function CollaborationPage(props: CollaborationProps) { type: "info", content: message, }); - } + }; const sendSubmissionResultsToMatchedUser = (data: SubmissionResults) => { if (!providerRef.current) { @@ -161,7 +178,7 @@ export default function CollaborationPage(props: CollaborationProps) { submissionResults: data, id: Date.now(), }); - } + }; const sendExecutingStateToMatchedUser = (executing: boolean) => { if (!providerRef.current) { @@ -171,7 +188,7 @@ export default function CollaborationPage(props: CollaborationProps) { executing: executing, id: Date.now(), }); - } + }; const sendSubmittingStateToMatchedUser = (submitting: boolean) => { if (!providerRef.current) { @@ -181,7 +198,7 @@ export default function CollaborationPage(props: CollaborationProps) { submitting: submitting, id: Date.now(), }); - } + }; const sendExecutionResultsToMatchedUser = (data: ExecutionResults) => { if (!providerRef.current) { @@ -191,7 +208,7 @@ export default function CollaborationPage(props: CollaborationProps) { executionResults: data, id: Date.now(), }); - } + }; const updateSubmissionResults = (data: SubmissionResults) => { setSubmissionHiddenTestResultsAndStatus({ @@ -199,11 +216,11 @@ export default function CollaborationPage(props: CollaborationProps) { status: data.status, }); setVisibleTestCases(data.visibleTestResults); - } + }; const updateExecutionResults = (data: ExecutionResults) => { setVisibleTestCases(data.visibleTestResults); - } + }; const handleRunTestCases = async () => { if (!questionDocRefId) { @@ -211,20 +228,17 @@ export default function CollaborationPage(props: CollaborationProps) { } setIsLoadingTestCase(true); sendExecutingStateToMatchedUser(true); - const data = await ExecuteVisibleAndCustomTests( - questionDocRefId, - { - code: code, - language: selectedLanguage, - customTestCases: "", - } - ); + const data = await ExecuteVisibleAndCustomTests(questionDocRefId, { + code: code, + language: selectedLanguage, + customTestCases: "", + }); setVisibleTestCases(data.visibleTestResults); - infoMessage("Test cases executed. Review the results below.") + infoMessage("Test cases executed. Review the results below."); sendExecutionResultsToMatchedUser(data); setIsLoadingTestCase(false); sendExecutingStateToMatchedUser(false); - } + }; const handleSubmitCode = async () => { if (!questionDocRefId) { @@ -232,19 +246,16 @@ export default function CollaborationPage(props: CollaborationProps) { } setIsLoadingSubmission(true); sendSubmittingStateToMatchedUser(true); - const data = await ExecuteVisibleAndHiddenTestsAndSubmit( - questionDocRefId, - { - code: code, - language: selectedLanguage, - user: currentUser ?? "", - matchedUser: matchedUser ?? "", - matchedTopics: matchedTopics ?? [], - title: questionTitle ?? "", - questionDifficulty: complexity ?? "", - questionTopics: categories, - } - ); + const data = await ExecuteVisibleAndHiddenTestsAndSubmit(questionDocRefId, { + code: code, + language: selectedLanguage, + user: currentUser ?? "", + matchedUser: matchedUser ?? "", + matchedTopics: matchedTopics ?? [], + title: questionTitle ?? "", + questionDifficulty: complexity ?? "", + questionTopics: categories, + }); setVisibleTestCases(data.visibleTestResults); setSubmissionHiddenTestResultsAndStatus({ hiddenTestResults: data.hiddenTestResults, @@ -254,7 +265,7 @@ export default function CollaborationPage(props: CollaborationProps) { successMessage("Code saved successfully!"); setIsLoadingSubmission(false); sendSubmittingStateToMatchedUser(false); - } + }; const handleCodeChange = (code: string) => { setCode(code); @@ -317,9 +328,7 @@ export default function CollaborationPage(props: CollaborationProps) { label: ( Case {index + 1} @@ -335,21 +344,20 @@ export default function CollaborationPage(props: CollaborationProps) { {isTestResult(item) && (
- {item.passed ? "Passed" : "Failed"}
- Actual Output: {item.actual} + Actual Output:{" "} + {item.actual}
{item.error && ( <> Error: -
- {item.error} -
+
{item.error}
)}
@@ -487,31 +495,50 @@ export default function CollaborationPage(props: CollaborationProps) { )}
- - Session Status: {submissionHiddenTestResultsAndStatus ? submissionHiddenTestResultsAndStatus.status : "Not Attempted"} + Session Status:{" "} + {submissionHiddenTestResultsAndStatus + ? submissionHiddenTestResultsAndStatus.status + : "Not Attempted"}
{submissionHiddenTestResultsAndStatus && ( - Passed {submissionHiddenTestResultsAndStatus.hiddenTestResults.passed} / {submissionHiddenTestResultsAndStatus.hiddenTestResults.total} hidden test cases + Passed{" "} + { + submissionHiddenTestResultsAndStatus.hiddenTestResults + .passed + }{" "} + /{" "} + { + submissionHiddenTestResultsAndStatus.hiddenTestResults + .total + }{" "} + hidden test cases )}
diff --git a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx index a7c8051bcf..d32f67612d 100644 --- a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx +++ b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx @@ -15,8 +15,8 @@ import * as Y from "yjs"; import { yCollab } from "y-codemirror.next"; import { WebrtcProvider } from "y-webrtc"; import { EditorView, basicSetup } from "codemirror"; -import { keymap } from "@codemirror/view" -import { indentWithTab } from "@codemirror/commands" +import { keymap } from "@codemirror/view"; +import { indentWithTab } from "@codemirror/commands"; import { EditorState, Compartment } from "@codemirror/state"; import { javascript, javascriptLanguage } from "@codemirror/lang-javascript"; import { python, pythonLanguage } from "@codemirror/lang-python"; @@ -68,15 +68,15 @@ interface Awareness { executionResultsState: { executionResults: ExecutionResults; id: number; - } + }; executingState: { executing: boolean; id: number; - } + }; submittingState: { submitting: boolean; id: number; - } + }; } export const usercolors = [ @@ -111,8 +111,7 @@ const CollaborativeEditor = forwardRef( props.onCodeChange(update.state.doc.toString()); } }); - - + // Referenced: https://codemirror.net/examples/config/#dynamic-configuration // const autoLanguage = EditorState.transactionExtender.of((tr) => { // if (!tr.docChanged) return null; @@ -196,10 +195,10 @@ const CollaborativeEditor = forwardRef( }); }; - let latestExecutionId: number = (new Date(0)).getTime(); - let latestSubmissionId: number = (new Date(0)).getTime(); - let latestExecutingId: number = (new Date(0)).getTime(); - let latestSubmittingId: number = (new Date(0)).getTime(); + let latestExecutionId: number = new Date(0).getTime(); + let latestSubmissionId: number = new Date(0).getTime(); + let latestExecutingId: number = new Date(0).getTime(); + let latestSubmittingId: number = new Date(0).getTime(); useImperativeHandle(ref, () => ({ endSession: () => { @@ -311,12 +310,14 @@ const CollaborativeEditor = forwardRef( .get(clientID) as Awareness; if ( - state && + state && state.submissionResultsState && state.submissionResultsState.id !== latestSubmissionId ) { latestSubmissionId = state.submissionResultsState.id; - props.updateSubmissionResults(state.submissionResultsState.submissionResults); + props.updateSubmissionResults( + state.submissionResultsState.submissionResults + ); messageApi.open({ type: "success", content: `${ @@ -326,12 +327,14 @@ const CollaborativeEditor = forwardRef( } if ( - state && - state.executionResultsState && + state && + state.executionResultsState && state.executionResultsState.id !== latestExecutionId ) { latestExecutionId = state.executionResultsState.id; - props.updateExecutionResults(state.executionResultsState.executionResults); + props.updateExecutionResults( + state.executionResultsState.executionResults + ); messageApi.open({ type: "success", content: `${ @@ -341,8 +344,8 @@ const CollaborativeEditor = forwardRef( } if ( - state && - state.executingState && + state && + state.executingState && state.executingState.id !== latestExecutingId ) { latestExecutingId = state.executingState.id; @@ -358,8 +361,8 @@ const CollaborativeEditor = forwardRef( } if ( - state && - state.submittingState && + state && + state.submittingState && state.submittingState.id !== latestSubmittingId ) { latestSubmittingId = state.submittingState.id; @@ -367,9 +370,7 @@ const CollaborativeEditor = forwardRef( if (state.submittingState.submitting) { messageApi.open({ type: "info", - content: `${ - props.matchedUser ?? "Peer" - } is saving code...`, + content: `${props.matchedUser ?? "Peer"} is saving code...`, }); } } diff --git a/apps/frontend/src/components/VideoPanel/VideoPanel.tsx b/apps/frontend/src/components/VideoPanel/VideoPanel.tsx index 36fdd948e2..4e4f6acf94 100644 --- a/apps/frontend/src/components/VideoPanel/VideoPanel.tsx +++ b/apps/frontend/src/components/VideoPanel/VideoPanel.tsx @@ -11,11 +11,8 @@ import { } from "@ant-design/icons"; const VideoPanel = () => { - const matchId = localStorage.getItem("collabId")?.toString() ?? ""; - const currentUsername = localStorage.getItem("user")?.toString(); - const matchedUsername = localStorage.getItem("matchedUser")?.toString(); - const currentId = currentUsername + "-" + matchId ?? ""; - const partnerId = matchedUsername + "-" + matchId ?? ""; + const [currentId, setCurrentId] = useState(); + const [partnerId, setPartnerId] = useState(); const remoteVideoRef = useRef(null); const currentUserVideoRef = useRef(null); @@ -30,6 +27,15 @@ const VideoPanel = () => { const [muteOn, setMuteOn] = useState(false); const [isCalling, setIsCalling] = useState(false); + useEffect(() => { + const matchId = localStorage.getItem("collabId")?.toString() ?? ""; + const currentUsername = localStorage.getItem("user")?.toString(); + const matchedUsername = localStorage.getItem("matchedUser")?.toString(); + + setCurrentId(currentUsername + "-" + (matchId ?? "")); + setPartnerId(matchedUsername + "-" + (matchId ?? "")); + }, []); + const handleCall = () => { navigator.mediaDevices .getUserMedia({ @@ -120,7 +126,7 @@ const VideoPanel = () => { } }; } - }, []); + }, [currentId]); // When remote peer initiates end call, we set isCalling to false useEffect(() => { From 1bde6007d21b4cbdceb0d597096d7b7389a63a36 Mon Sep 17 00:00:00 2001 From: solomonng2001 Date: Thu, 7 Nov 2024 16:59:20 +0800 Subject: [PATCH 186/258] Fix python sandbox container not found --- apps/execution-service/execution/python/python.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/execution-service/execution/python/python.go b/apps/execution-service/execution/python/python.go index a8383d737f..726bc29d8b 100644 --- a/apps/execution-service/execution/python/python.go +++ b/apps/execution-service/execution/python/python.go @@ -11,7 +11,7 @@ func RunPythonCode(code string, input string) (string, string, error) { cmd := exec.Command( "docker", "run", "--rm", "-i", // allows for standard input to be passed in - "python-sandbox", + "apps-python-sandbox", "python", "-c", code, ) From fdce97ae834ba27204624fa648695b31175c4645 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Fri, 8 Nov 2024 14:17:53 +0800 Subject: [PATCH 187/258] fix(videoPanel): :bug: default for undefined partnerId Include a check to validate if partnerID is not undefined --- apps/frontend/src/components/VideoPanel/VideoPanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/src/components/VideoPanel/VideoPanel.tsx b/apps/frontend/src/components/VideoPanel/VideoPanel.tsx index 4e4f6acf94..2db62642e0 100644 --- a/apps/frontend/src/components/VideoPanel/VideoPanel.tsx +++ b/apps/frontend/src/components/VideoPanel/VideoPanel.tsx @@ -43,7 +43,7 @@ const VideoPanel = () => { audio: true, }) .then((stream) => { - if (peerInstance) { + if (peerInstance && partnerId) { const call = peerInstance?.call(partnerId, stream); setCallInstance(call); setIsCalling(true); // Set isCalling as true since it is the initiator From b4e499ddb0b725a9d5023d8cc8d8480f07d3bf55 Mon Sep 17 00:00:00 2001 From: bensohh Date: Sat, 9 Nov 2024 12:25:52 +0800 Subject: [PATCH 188/258] Ammend styling issues with question page --- apps/frontend/src/app/question/[id]/page.tsx | 46 +++++++++---------- .../src/app/question/[id]/styles.scss | 15 +++--- .../QuestionDetailFull/QuestionDetailFull.tsx | 4 +- .../question/QuestionDetailFull/styles.scss | 8 ++-- .../TestcaseDetail/TestcaseDetail.tsx | 4 +- .../question/TestcaseDetail/styles.scss | 4 +- 6 files changed, 40 insertions(+), 41 deletions(-) diff --git a/apps/frontend/src/app/question/[id]/page.tsx b/apps/frontend/src/app/question/[id]/page.tsx index 277228f5c3..9b5b353ad4 100644 --- a/apps/frontend/src/app/question/[id]/page.tsx +++ b/apps/frontend/src/app/question/[id]/page.tsx @@ -227,7 +227,7 @@ export default function QuestionPage() { visibleTestcases={visibleTestCases} /> -
+
@@ -235,28 +235,28 @@ export default function QuestionPage() { Submission History
-
-
-
{ - return { - onClick: () => handleRowClick(record), - style: { cursor: "pointer" }, - }; - }} - loading={isHistoryLoading} - pagination={{ - size: "small", - current: paginationParams.currentPage, - total: paginationParams.totalCount, - pageSize: paginationParams.limit, - onChange: onPageJump, - }} - scroll={{ y: 200 }} - /> +
+
{ + return { + onClick: () => handleRowClick(record), + style: { cursor: "pointer" }, + }; + }} + loading={isHistoryLoading} + pagination={{ + size: "small", + current: paginationParams.currentPage, + total: paginationParams.totalCount, + pageSize: paginationParams.limit, + onChange: onPageJump, + }} + scroll={{ y: 200 }} + /> + diff --git a/apps/frontend/src/app/question/[id]/styles.scss b/apps/frontend/src/app/question/[id]/styles.scss index 3b73fbcc7d..343f2bd3e9 100644 --- a/apps/frontend/src/app/question/[id]/styles.scss +++ b/apps/frontend/src/app/question/[id]/styles.scss @@ -8,7 +8,7 @@ .question-content { background: white; flex: 1; - overflow-y: auto; + // overflow-y: auto; } .first-col, @@ -21,21 +21,20 @@ } .history-row { - padding: 1rem 0.25rem 0.25rem; + padding: 0.5rem 0.25rem 0.25rem; + height: 40%; } .code-row { flex: 1; - height: 100%; - padding: 1rem 0.25rem 0.25rem; + height: 60%; + padding: 0.5rem 0.25rem 0.25rem; } -.test-top-container, -.code-top-container, -.history-top-container, -.session-top-container { +.test-top-container { display: flex; justify-content: space-between; + height: 50%; } .history-container, diff --git a/apps/frontend/src/components/question/QuestionDetailFull/QuestionDetailFull.tsx b/apps/frontend/src/components/question/QuestionDetailFull/QuestionDetailFull.tsx index d5a22292ec..204f2a9417 100644 --- a/apps/frontend/src/components/question/QuestionDetailFull/QuestionDetailFull.tsx +++ b/apps/frontend/src/components/question/QuestionDetailFull/QuestionDetailFull.tsx @@ -20,7 +20,7 @@ interface QuestionDetailFullProps { export const QuestionDetailFull = (props: QuestionDetailFullProps) => { return ( <> - + { description={props.description} /> - + { ); return ( -
-
+
+
Test Cases diff --git a/apps/frontend/src/components/question/TestcaseDetail/styles.scss b/apps/frontend/src/components/question/TestcaseDetail/styles.scss index 1ffadbb78a..da21b4a001 100644 --- a/apps/frontend/src/components/question/TestcaseDetail/styles.scss +++ b/apps/frontend/src/components/question/TestcaseDetail/styles.scss @@ -1,4 +1,4 @@ -.test-container { +.test-section { border: 2px solid #463f3a; border-radius: 10px; width: 100%; @@ -10,7 +10,7 @@ font-weight: bold; } -.test-top-container { +.test-top-box { display: flex; justify-content: space-between; } From ab4cc476f7ba56be6b9e0ef2106133a6b835ac17 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 10 Nov 2024 11:22:05 +0800 Subject: [PATCH 189/258] try selenium test --- .github/workflows/test.yml | 34 +- .../__tests__/browser-tests/browser.test.ts | 44 ++ .../__tests__/browser-tests/works.test.js | 16 + .../{ => unit-tests}/Datetime.test.ts | 0 .../dependencymocking.test.ts | 0 .../{ => unit-tests}/question.test.ts | 0 apps/frontend/package.json | 6 +- apps/frontend/pnpm-lock.yaml | 512 ++++++++++++++++++ 8 files changed, 610 insertions(+), 2 deletions(-) create mode 100644 apps/frontend/__tests__/browser-tests/browser.test.ts create mode 100644 apps/frontend/__tests__/browser-tests/works.test.js rename apps/frontend/__tests__/{ => unit-tests}/Datetime.test.ts (100%) rename apps/frontend/__tests__/{ => unit-tests}/dependencymocking.test.ts (100%) rename apps/frontend/__tests__/{ => unit-tests}/question.test.ts (100%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 90408360b4..0b843e57a1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -83,10 +83,42 @@ jobs: - name: Run tests run: | cd ./apps/frontend - pnpm test + pnpm test -- __tests__/unit-tests + + browser-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Set up Node.js + uses: actions/setup-node@v2 + with: + node-version: '22' + + - name: Install pnpm + run: npm i -g pnpm + + - name: Install dependencies + run: | + cd ./apps/frontend + pnpm i + + - name: Run tests + run: | + cd ./apps/frontend + node .\__tests__\browser-tests\wtf.test.js + + test-docker-compose: runs-on: ubuntu-latest + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Chrome Driver + run: | steps: - name: Checkout code diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts new file mode 100644 index 0000000000..dee5121683 --- /dev/null +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -0,0 +1,44 @@ +import { Browser, Builder, By, Key, until } from "selenium-webdriver" + +import { path } from "chromedriver" +import { getBinaryPaths } from "selenium-webdriver/common/driverFinder" +import Chrome from "selenium-webdriver/chrome" +describe("base selenium test", () => { + it.skip("works", async () => { + // referenced: https://www.npmjs.com/package/selenium-webdriver + console.log(path) + + let options = new Chrome.Options(); + options.setBrowserVersion("stable") + + let paths = getBinaryPaths(options) + let driverPath = paths.driverPath; + let browserPath = paths.browserPath; + console.log(paths); + + options.setChromeBinaryPath(browserPath) + + let service = new Chrome.ServiceBuilder().setPath(driverPath); + + let driver = await new Builder().forBrowser(Browser.CHROME) + .setChromeOptions(options) + .setChromeService(service) + .build(); + + console.log("got here"); + + try { + await driver.get('https://www.google.com/ncr') + console.log("got here"); + await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN) + console.log("got here"); + await driver.wait(until.titleIs('webdriver - Google Search'), 1000) + console.log("got here"); + } finally { + await driver.quit() + } + }, 60000) +}) + + + diff --git a/apps/frontend/__tests__/browser-tests/works.test.js b/apps/frontend/__tests__/browser-tests/works.test.js new file mode 100644 index 0000000000..4f902bd48b --- /dev/null +++ b/apps/frontend/__tests__/browser-tests/works.test.js @@ -0,0 +1,16 @@ +// require('chromedriver'); +const { Builder, By, Key, until } = require('selenium-webdriver'); +(async function test() { + const builder = new Builder().forBrowser('chrome'); + console.log(builder.getChromeOptions()); + + let driver = await builder.build(); + + try { + await driver.get('http://www.google.com'); + await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); + await driver.wait(until.titleIs('webdriver - Google Search'), 1000); + } finally { + await driver.quit(); + } +})(); \ No newline at end of file diff --git a/apps/frontend/__tests__/Datetime.test.ts b/apps/frontend/__tests__/unit-tests/Datetime.test.ts similarity index 100% rename from apps/frontend/__tests__/Datetime.test.ts rename to apps/frontend/__tests__/unit-tests/Datetime.test.ts diff --git a/apps/frontend/__tests__/dependencymocking.test.ts b/apps/frontend/__tests__/unit-tests/dependencymocking.test.ts similarity index 100% rename from apps/frontend/__tests__/dependencymocking.test.ts rename to apps/frontend/__tests__/unit-tests/dependencymocking.test.ts diff --git a/apps/frontend/__tests__/question.test.ts b/apps/frontend/__tests__/unit-tests/question.test.ts similarity index 100% rename from apps/frontend/__tests__/question.test.ts rename to apps/frontend/__tests__/unit-tests/question.test.ts diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 792fc18474..da143a8b4d 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -37,19 +37,23 @@ "yjs": "^13.6.20" }, "devDependencies": { - "@types/codemirror": "^5.60.15", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.0.1", + "@types/chromedriver": "^81.0.5", + "@types/codemirror": "^5.60.15", "@types/jest": "^29.5.14", "@types/node": "^20", "@types/peerjs": "^1.1.0", "@types/react": "^18.3.8", "@types/react-dom": "^18.3.0", + "@types/selenium-webdriver": "^4.1.27", + "chromedriver": "^130.0.4", "eslint": "^8", "eslint-config-next": "14.2.13", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", + "selenium-webdriver": "^4.26.0", "ts-node": "^10.9.2", "typescript": "^5" }, diff --git a/apps/frontend/pnpm-lock.yaml b/apps/frontend/pnpm-lock.yaml index 413f0c29e3..4a85647726 100644 --- a/apps/frontend/pnpm-lock.yaml +++ b/apps/frontend/pnpm-lock.yaml @@ -93,6 +93,9 @@ importers: '@testing-library/react': specifier: ^16.0.1 version: 16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@types/chromedriver': + specifier: ^81.0.5 + version: 81.0.5 '@types/codemirror': specifier: ^5.60.15 version: 5.60.15 @@ -111,6 +114,12 @@ importers: '@types/react-dom': specifier: ^18.3.0 version: 18.3.0 + '@types/selenium-webdriver': + specifier: ^4.1.27 + version: 4.1.27 + chromedriver: + specifier: ^130.0.4 + version: 130.0.4 eslint: specifier: ^8 version: 8.0.0 @@ -123,6 +132,9 @@ importers: jest-environment-jsdom: specifier: ^29.7.0 version: 29.7.0 + selenium-webdriver: + specifier: ^4.26.0 + version: 4.26.0 ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@20.0.0)(typescript@5.0.2) @@ -344,6 +356,9 @@ packages: resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==} engines: {node: '>=6.9.0'} + '@bazel/runfiles@6.3.1': + resolution: {integrity: sha512-1uLNT5NZsUVIGS4syuHwTzZ8HycMPyr6POA3FCE4GbMtc4rhoJk8aZKtNIRthJYfL+iioppi+rTfH3olMPr9nA==} + '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} @@ -708,6 +723,9 @@ packages: '@swc/helpers@0.5.5': resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} + '@testim/chrome-version@1.1.4': + resolution: {integrity: sha512-kIhULpw9TrGYnHp/8VfdcneIcxKnLixmADtukQRtJUmsVlMg0niMkwV0xZmi8hqa57xqilIHjWFA0GKvEjVU5g==} + '@testing-library/dom@10.4.0': resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==} engines: {node: '>=18'} @@ -735,6 +753,9 @@ packages: resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} + '@tootallnate/quickjs-emscripten@0.23.0': + resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + '@tsconfig/node10@1.0.11': resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} @@ -762,6 +783,9 @@ packages: '@types/babel__traverse@7.20.6': resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + '@types/chromedriver@81.0.5': + resolution: {integrity: sha512-VwV+WTTFHYZotBn57QQ8gd4TE7CGJ15KPM+xJJrKbiQQSccTY7zVXuConSBlyWrO+AFpVxuzmluK3xvzxGmkCw==} + '@types/codemirror@5.60.15': resolution: {integrity: sha512-dTOvwEQ+ouKJ/rE9LT1Ue2hmP6H1mZv5+CCnNWu2qtiOe2LQa9lCprEY20HxiDmV/Bxh+dXjywmy5aKvoGjULA==} @@ -805,6 +829,9 @@ packages: '@types/react@18.3.8': resolution: {integrity: sha512-syBUrW3/XpnW4WJ41Pft+I+aPoDVbrBVQGEnbD7NijDGlVC+8gV/XKRY+7vMDlfPpbwYt0l1vd/Sj8bJGMbs9Q==} + '@types/selenium-webdriver@4.1.27': + resolution: {integrity: sha512-ALqsj8D7Swb6MnBQuAQ58J3KC3yh6fLGtAmpBmnZX8j+0kmP7NaLt56CuzBw2W2bXPrvHFTgn8iekOQFUKXEQA==} + '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} @@ -814,12 +841,18 @@ packages: '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + '@types/ws@8.5.13': + resolution: {integrity: sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==} + '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} '@types/yargs@17.0.33': resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + '@types/yauzl@2.10.3': + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + '@typescript-eslint/eslint-plugin@8.8.0': resolution: {integrity: sha512-wORFWjU30B2WJ/aXBfOm1LX9v9nyt9D3jsSOxC3cCaTQGCW5k4jNpmjFv3U7p/7s4yvdjHzwtv2Sd2dOyhjS0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -902,6 +935,10 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} + agent-base@7.1.1: + resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} + engines: {node: '>= 14'} + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -996,6 +1033,10 @@ packages: ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + ast-types@0.13.4: + resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} + engines: {node: '>=4'} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -1007,6 +1048,9 @@ packages: resolution: {integrity: sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==} engines: {node: '>=4'} + axios@1.7.7: + resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} + axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} @@ -1042,6 +1086,10 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + basic-ftp@5.0.5: + resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} + engines: {node: '>=10.0.0'} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -1060,6 +1108,9 @@ packages: bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -1108,6 +1159,11 @@ packages: resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} engines: {node: '>= 14.16.0'} + chromedriver@130.0.4: + resolution: {integrity: sha512-lpR+PWXszij1k4Ig3t338Zvll9HtCTiwoLM7n4pCCswALHxzmgwaaIFBh3rt9+5wRk9D07oFblrazrBxwaYYAQ==} + engines: {node: '>=18'} + hasBin: true + ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} @@ -1146,6 +1202,9 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + compare-versions@6.1.1: + resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} + compute-scroll-into-view@3.1.0: resolution: {integrity: sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==} @@ -1158,6 +1217,9 @@ packages: copy-to-clipboard@3.3.3: resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + create-jest@29.7.0: resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -1192,6 +1254,10 @@ packages: damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + data-uri-to-buffer@6.0.2: + resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} + engines: {node: '>= 14'} + data-urls@3.0.2: resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==} engines: {node: '>=12'} @@ -1219,6 +1285,15 @@ packages: supports-color: optional: true + debug@4.3.1: + resolution: {integrity: sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.3.7: resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} @@ -1258,6 +1333,10 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + degenerator@5.0.1: + resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} + engines: {node: '>= 14'} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -1313,6 +1392,9 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + enhanced-resolve@5.17.1: resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} engines: {node: '>=10.13.0'} @@ -1519,6 +1601,11 @@ packages: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + extract-zip@2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1538,6 +1625,9 @@ packages: fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -1557,6 +1647,15 @@ packages: flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -1568,6 +1667,10 @@ packages: resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} engines: {node: '>= 6'} + fs-extra@11.2.0: + resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} + engines: {node: '>=14.14'} + fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -1608,6 +1711,10 @@ packages: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -1619,6 +1726,10 @@ packages: get-tsconfig@4.8.1: resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + get-uri@6.0.3: + resolution: {integrity: sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==} + engines: {node: '>= 14'} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1694,10 +1805,18 @@ packages: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} engines: {node: '>= 6'} + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} + https-proxy-agent@7.0.5: + resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==} + engines: {node: '>= 14'} + human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -1717,6 +1836,9 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + immutable@4.3.7: resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} @@ -1748,6 +1870,14 @@ packages: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} + ip-address@9.0.5: + resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} + engines: {node: '>= 12'} + + ip-regex@4.3.0: + resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==} + engines: {node: '>=8'} + is-arguments@1.1.1: resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} engines: {node: '>= 0.4'} @@ -1859,6 +1989,9 @@ packages: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} + is-url@1.2.4: + resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==} + is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} @@ -1870,6 +2003,13 @@ packages: resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} engines: {node: '>= 0.4'} + is2@2.0.9: + resolution: {integrity: sha512-rZkHeBn9Zzq52sd9IUIV3a5mfwBY+o2HePMh0wkGBM4z4qjvy2GwVxQ6nNXSfw6MmVP6gf1QIlWjiOavhM3x5g==} + engines: {node: '>=v0.10.0'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} @@ -2059,6 +2199,9 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true + jsbn@1.1.0: + resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} + jsdom@20.0.3: resolution: {integrity: sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==} engines: {node: '>=14'} @@ -2097,10 +2240,16 @@ packages: engines: {node: '>=6'} hasBin: true + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} + jszip@3.10.1: + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + jwt-decode@4.0.0: resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} engines: {node: '>=18'} @@ -2132,6 +2281,9 @@ packages: engines: {node: '>=16'} hasBin: true + lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} @@ -2155,6 +2307,10 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true @@ -2210,6 +2366,9 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -2221,6 +2380,10 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + netmask@2.0.2: + resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} + engines: {node: '>= 0.4.0'} + next@14.2.13: resolution: {integrity: sha512-BseY9YNw8QJSwLYD7hlZzl6QVDoSFHL/URN5K64kVEVpCsSOWeyjbIGK+dZUaRViHTaMQX8aqmnn0PHBbGZezg==} engines: {node: '>=18.17.0'} @@ -2319,6 +2482,17 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + pac-proxy-agent@7.0.2: + resolution: {integrity: sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==} + engines: {node: '>= 14'} + + pac-resolver@7.0.1: + resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} + engines: {node: '>= 14'} + + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -2357,6 +2531,9 @@ packages: resolution: {integrity: sha512-yFsoLMnurJKlQbx6kVSBpOp+AlNldY1JQS2BrSsHLKCZnq6t7saHleuHM5svuLNbQkUJXHLF3sKOJB1K0xulOw==} engines: {node: '>= 14'} + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + picocolors@1.1.0: resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} @@ -2392,6 +2569,9 @@ packages: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + progress@2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} @@ -2403,9 +2583,19 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + proxy-agent@6.4.0: + resolution: {integrity: sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==} + engines: {node: '>= 14'} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + psl@1.9.0: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + pump@3.0.2: + resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -2676,6 +2866,9 @@ packages: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} engines: {node: '>=0.10.0'} + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} @@ -2756,6 +2949,9 @@ packages: resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} engines: {node: '>=0.4'} + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -2784,6 +2980,10 @@ packages: sdp@3.2.0: resolution: {integrity: sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw==} + selenium-webdriver@4.26.0: + resolution: {integrity: sha512-nA7jMRIPV17mJmAiTDBWN96Sy0Uxrz5CCLb7bLVV6PpL417SyBMPc2Zo/uoREc2EOHlzHwHwAlFtgmSngSY4WQ==} + engines: {node: '>= 14.21.0'} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -2801,6 +3001,9 @@ packages: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -2830,6 +3033,18 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + + socks-proxy-agent@8.0.4: + resolution: {integrity: sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==} + engines: {node: '>= 14'} + + socks@2.8.3: + resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -2844,6 +3059,9 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -2892,6 +3110,9 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} @@ -2961,6 +3182,9 @@ packages: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} + tcp-port-used@1.0.2: + resolution: {integrity: sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA==} + test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} @@ -2972,6 +3196,10 @@ packages: resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} engines: {node: '>=12.22'} + tmp@0.2.3: + resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} + engines: {node: '>=14.14'} + tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} @@ -3063,6 +3291,10 @@ packages: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + update-browserslist-db@1.1.1: resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} hasBin: true @@ -3211,6 +3443,9 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + yjs@13.6.20: resolution: {integrity: sha512-Z2YZI+SYqK7XdWlloI3lhMiKnCdFCVC4PchpdO+mCYwtiTwncjUbnRK9R1JmkNfdmHyDXuWN3ibJAt0wsqTbLQ==} engines: {node: '>=16.0.0', npm: '>=8.0.0'} @@ -3478,6 +3713,8 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 + '@bazel/runfiles@6.3.1': {} + '@bcoe/v8-coverage@0.2.3': {} '@codemirror/autocomplete@6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3)': @@ -3989,6 +4226,8 @@ snapshots: '@swc/counter': 0.1.3 tslib: 2.7.0 + '@testim/chrome-version@1.1.4': {} + '@testing-library/dom@10.4.0': dependencies: '@babel/code-frame': 7.26.2 @@ -4022,6 +4261,8 @@ snapshots: '@tootallnate/once@2.0.0': {} + '@tootallnate/quickjs-emscripten@0.23.0': {} + '@tsconfig/node10@1.0.11': {} '@tsconfig/node12@1.0.11': {} @@ -4053,6 +4294,10 @@ snapshots: dependencies: '@babel/types': 7.26.0 + '@types/chromedriver@81.0.5': + dependencies: + '@types/node': 20.0.0 + '@types/codemirror@5.60.15': dependencies: '@types/tern': 0.23.9 @@ -4103,6 +4348,11 @@ snapshots: '@types/prop-types': 15.7.13 csstype: 3.1.3 + '@types/selenium-webdriver@4.1.27': + dependencies: + '@types/node': 20.0.0 + '@types/ws': 8.5.13 + '@types/stack-utils@2.0.3': {} '@types/tern@0.23.9': @@ -4111,12 +4361,21 @@ snapshots: '@types/tough-cookie@4.0.5': {} + '@types/ws@8.5.13': + dependencies: + '@types/node': 20.0.0 + '@types/yargs-parser@21.0.3': {} '@types/yargs@17.0.33': dependencies: '@types/yargs-parser': 21.0.3 + '@types/yauzl@2.10.3': + dependencies: + '@types/node': 20.0.0 + optional: true + '@typescript-eslint/eslint-plugin@8.8.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint@8.0.0)(typescript@5.0.2)': dependencies: '@eslint-community/regexpp': 4.11.1 @@ -4221,6 +4480,12 @@ snapshots: transitivePeerDependencies: - supports-color + agent-base@7.1.1: + dependencies: + debug: 4.3.7 + transitivePeerDependencies: + - supports-color + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -4394,6 +4659,10 @@ snapshots: ast-types-flow@0.0.8: {} + ast-types@0.13.4: + dependencies: + tslib: 2.7.0 + asynckit@0.4.0: {} available-typed-arrays@1.0.7: @@ -4402,6 +4671,14 @@ snapshots: axe-core@4.10.0: {} + axios@1.7.7: + dependencies: + follow-redirects: 1.15.9 + form-data: 4.0.1 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + axobject-query@4.1.0: {} babel-jest@29.7.0(@babel/core@7.26.0): @@ -4463,6 +4740,8 @@ snapshots: base64-js@1.5.1: {} + basic-ftp@5.0.5: {} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -4487,6 +4766,8 @@ snapshots: dependencies: node-int64: 0.4.0 + buffer-crc32@0.2.13: {} + buffer-from@1.1.2: {} buffer@6.0.3: @@ -4532,6 +4813,19 @@ snapshots: dependencies: readdirp: 4.0.1 + chromedriver@130.0.4: + dependencies: + '@testim/chrome-version': 1.1.4 + axios: 1.7.7 + compare-versions: 6.1.1 + extract-zip: 2.0.1 + proxy-agent: 6.4.0 + proxy-from-env: 1.1.0 + tcp-port-used: 1.0.2 + transitivePeerDependencies: + - debug + - supports-color + ci-info@3.9.0: {} cjs-module-lexer@1.4.1: {} @@ -4572,6 +4866,8 @@ snapshots: dependencies: delayed-stream: 1.0.0 + compare-versions@6.1.1: {} + compute-scroll-into-view@3.1.0: {} concat-map@0.0.1: {} @@ -4582,6 +4878,8 @@ snapshots: dependencies: toggle-selection: 1.0.6 + core-util-is@1.0.3: {} + create-jest@29.7.0(@types/node@20.0.0)(ts-node@10.9.2(@types/node@20.0.0)(typescript@5.0.2)): dependencies: '@jest/types': 29.6.3 @@ -4621,6 +4919,8 @@ snapshots: damerau-levenshtein@1.0.8: {} + data-uri-to-buffer@6.0.2: {} + data-urls@3.0.2: dependencies: abab: 2.0.6 @@ -4651,6 +4951,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.3.1: + dependencies: + ms: 2.1.2 + debug@4.3.7: dependencies: ms: 2.1.3 @@ -4696,6 +5000,12 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + degenerator@5.0.1: + dependencies: + ast-types: 0.13.4 + escodegen: 2.1.0 + esprima: 4.0.1 + delayed-stream@1.0.0: {} dequal@2.0.3: {} @@ -4732,6 +5042,10 @@ snapshots: emoji-regex@9.2.2: {} + end-of-stream@1.4.4: + dependencies: + once: 1.4.0 + enhanced-resolve@5.17.1: dependencies: graceful-fs: 4.2.11 @@ -5101,6 +5415,16 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 + extract-zip@2.0.1: + dependencies: + debug: 4.3.7 + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.3 + transitivePeerDependencies: + - supports-color + fast-deep-equal@3.1.3: {} fast-glob@3.3.2: @@ -5123,6 +5447,10 @@ snapshots: dependencies: bser: 2.1.1 + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + file-entry-cache@6.0.1: dependencies: flat-cache: 3.2.0 @@ -5144,6 +5472,8 @@ snapshots: flatted@3.3.1: {} + follow-redirects@1.15.9: {} + for-each@0.3.3: dependencies: is-callable: 1.2.7 @@ -5159,6 +5489,12 @@ snapshots: combined-stream: 1.0.8 mime-types: 2.1.35 + fs-extra@11.2.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + fs.realpath@1.0.0: {} fsevents@2.3.3: @@ -5193,6 +5529,10 @@ snapshots: get-package-type@0.1.0: {} + get-stream@5.2.0: + dependencies: + pump: 3.0.2 + get-stream@6.0.1: {} get-symbol-description@1.0.2: @@ -5205,6 +5545,15 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + get-uri@6.0.3: + dependencies: + basic-ftp: 5.0.5 + data-uri-to-buffer: 6.0.2 + debug: 4.3.7 + fs-extra: 11.2.0 + transitivePeerDependencies: + - supports-color + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -5283,6 +5632,13 @@ snapshots: transitivePeerDependencies: - supports-color + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.1 + debug: 4.3.7 + transitivePeerDependencies: + - supports-color + https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 @@ -5290,6 +5646,13 @@ snapshots: transitivePeerDependencies: - supports-color + https-proxy-agent@7.0.5: + dependencies: + agent-base: 7.1.1 + debug: 4.3.7 + transitivePeerDependencies: + - supports-color + human-signals@2.1.0: {} iconv-lite@0.6.3: @@ -5302,6 +5665,8 @@ snapshots: ignore@5.3.2: {} + immediate@3.0.6: {} + immutable@4.3.7: {} import-fresh@3.3.0: @@ -5331,6 +5696,13 @@ snapshots: hasown: 2.0.2 side-channel: 1.0.6 + ip-address@9.0.5: + dependencies: + jsbn: 1.1.0 + sprintf-js: 1.1.3 + + ip-regex@4.3.0: {} + is-arguments@1.1.1: dependencies: call-bind: 1.0.7 @@ -5429,6 +5801,8 @@ snapshots: dependencies: which-typed-array: 1.1.15 + is-url@1.2.4: {} + is-weakmap@2.0.2: {} is-weakref@1.0.2: @@ -5440,6 +5814,14 @@ snapshots: call-bind: 1.0.7 get-intrinsic: 1.2.4 + is2@2.0.9: + dependencies: + deep-is: 0.1.4 + ip-regex: 4.3.0 + is-url: 1.2.4 + + isarray@1.0.0: {} + isarray@2.0.5: {} isexe@2.0.0: {} @@ -5836,6 +6218,8 @@ snapshots: dependencies: argparse: 2.0.1 + jsbn@1.1.0: {} + jsdom@20.0.3: dependencies: abab: 2.0.6 @@ -5889,6 +6273,12 @@ snapshots: json5@2.2.3: {} + jsonfile@6.1.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + jsx-ast-utils@3.3.5: dependencies: array-includes: 3.1.8 @@ -5896,6 +6286,13 @@ snapshots: object.assign: 4.1.5 object.values: 1.2.0 + jszip@3.10.1: + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + jwt-decode@4.0.0: {} keyv@4.5.4: @@ -5921,6 +6318,10 @@ snapshots: dependencies: isomorphic.js: 0.2.5 + lie@3.3.0: + dependencies: + immediate: 3.0.6 + lines-and-columns@1.2.4: {} locate-path@5.0.0: @@ -5941,6 +6342,8 @@ snapshots: dependencies: yallist: 3.1.1 + lru-cache@7.18.3: {} + lz-string@1.5.0: {} make-dir@4.0.0: @@ -5984,12 +6387,16 @@ snapshots: minipass@7.1.2: {} + ms@2.1.2: {} + ms@2.1.3: {} nanoid@3.3.7: {} natural-compare@1.4.0: {} + netmask@2.0.2: {} + next@14.2.13(@babel/core@7.26.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2): dependencies: '@next/env': 14.2.13 @@ -6102,6 +6509,26 @@ snapshots: p-try@2.2.0: {} + pac-proxy-agent@7.0.2: + dependencies: + '@tootallnate/quickjs-emscripten': 0.23.0 + agent-base: 7.1.1 + debug: 4.3.7 + get-uri: 6.0.3 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 + pac-resolver: 7.0.1 + socks-proxy-agent: 8.0.4 + transitivePeerDependencies: + - supports-color + + pac-resolver@7.0.1: + dependencies: + degenerator: 5.0.1 + netmask: 2.0.2 + + pako@1.0.11: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -6139,6 +6566,8 @@ snapshots: peerjs-js-binarypack: 2.1.0 webrtc-adapter: 9.0.1 + pend@1.2.0: {} + picocolors@1.1.0: {} picomatch@2.3.1: {} @@ -6171,6 +6600,8 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 + process-nextick-args@2.0.1: {} + progress@2.0.3: {} prompts@2.4.2: @@ -6184,8 +6615,28 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 + proxy-agent@6.4.0: + dependencies: + agent-base: 7.1.1 + debug: 4.3.7 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.5 + lru-cache: 7.18.3 + pac-proxy-agent: 7.0.2 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.4 + transitivePeerDependencies: + - supports-color + + proxy-from-env@1.1.0: {} + psl@1.9.0: {} + pump@3.0.2: + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + punycode@2.3.1: {} pure-rand@6.1.0: {} @@ -6539,6 +6990,16 @@ snapshots: dependencies: loose-envify: 1.4.0 + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + readable-stream@3.6.2: dependencies: inherits: 2.0.4 @@ -6620,6 +7081,8 @@ snapshots: has-symbols: 1.0.3 isarray: 2.0.5 + safe-buffer@5.1.2: {} + safe-buffer@5.2.1: {} safe-regex-test@1.0.3: @@ -6650,6 +7113,16 @@ snapshots: sdp@3.2.0: {} + selenium-webdriver@4.26.0: + dependencies: + '@bazel/runfiles': 6.3.1 + jszip: 3.10.1 + tmp: 0.2.3 + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + semver@6.3.1: {} semver@7.6.3: {} @@ -6670,6 +7143,8 @@ snapshots: functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 + setimmediate@1.0.5: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -6703,6 +7178,21 @@ snapshots: slash@3.0.0: {} + smart-buffer@4.2.0: {} + + socks-proxy-agent@8.0.4: + dependencies: + agent-base: 7.1.1 + debug: 4.3.7 + socks: 2.8.3 + transitivePeerDependencies: + - supports-color + + socks@2.8.3: + dependencies: + ip-address: 9.0.5 + smart-buffer: 4.2.0 + source-map-js@1.2.1: {} source-map-support@0.5.13: @@ -6714,6 +7204,8 @@ snapshots: sprintf-js@1.0.3: {} + sprintf-js@1.1.3: {} + stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 @@ -6787,6 +7279,10 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 @@ -6836,6 +7332,13 @@ snapshots: tapable@2.2.1: {} + tcp-port-used@1.0.2: + dependencies: + debug: 4.3.1 + is2: 2.0.9 + transitivePeerDependencies: + - supports-color + test-exclude@6.0.0: dependencies: '@istanbuljs/schema': 0.1.3 @@ -6846,6 +7349,8 @@ snapshots: throttle-debounce@5.0.2: {} + tmp@0.2.3: {} + tmpl@1.0.5: {} to-regex-range@5.0.1: @@ -6951,6 +7456,8 @@ snapshots: universalify@0.2.0: {} + universalify@2.0.1: {} + update-browserslist-db@1.1.1(browserslist@4.24.2): dependencies: browserslist: 4.24.2 @@ -7115,6 +7622,11 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + yjs@13.6.20: dependencies: lib0: 0.2.98 From 8958cb6151a2423236ab8c5527ddc464b5185079 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 10 Nov 2024 11:23:29 +0800 Subject: [PATCH 190/258] asd --- .github/workflows/test.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0b843e57a1..70da397075 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -114,11 +114,6 @@ jobs: test-docker-compose: runs-on: ubuntu-latest - - name: Checkout code - uses: actions/checkout@v4 - - - name: Install Chrome Driver - run: | steps: - name: Checkout code From 240c839afa0bd5fc4690b9c2e8d0b74f45d69b59 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 10 Nov 2024 11:27:52 +0800 Subject: [PATCH 191/258] asd --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 70da397075..d0b82b8f51 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -108,7 +108,7 @@ jobs: - name: Run tests run: | cd ./apps/frontend - node .\__tests__\browser-tests\wtf.test.js + node ./__tests__/browser-tests\wtf.test.js From 5b79d8be4f25309d4cfe05a61d5a406ddfccf0c6 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 10 Nov 2024 11:28:49 +0800 Subject: [PATCH 192/258] asd --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d0b82b8f51..09d5ad6c0f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -108,7 +108,7 @@ jobs: - name: Run tests run: | cd ./apps/frontend - node ./__tests__/browser-tests\wtf.test.js + node ./__tests__/browser-tests/wtf.test.js From 67960833336c4c9818983f855ad11d72eb03b454 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 10 Nov 2024 11:32:00 +0800 Subject: [PATCH 193/258] asd --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 09d5ad6c0f..6e099d6ab0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -108,7 +108,7 @@ jobs: - name: Run tests run: | cd ./apps/frontend - node ./__tests__/browser-tests/wtf.test.js + node ./__tests__/browser-tests/works.test.js From 9f1efaffdee71440839ca67e2ed7f39e1c0bec9a Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 10 Nov 2024 11:55:18 +0800 Subject: [PATCH 194/258] asd s --- apps/frontend/__tests__/browser-tests/works.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/frontend/__tests__/browser-tests/works.test.js b/apps/frontend/__tests__/browser-tests/works.test.js index 4f902bd48b..fe98294e90 100644 --- a/apps/frontend/__tests__/browser-tests/works.test.js +++ b/apps/frontend/__tests__/browser-tests/works.test.js @@ -1,7 +1,8 @@ -// require('chromedriver'); +require('chromedriver'); const { Builder, By, Key, until } = require('selenium-webdriver'); (async function test() { const builder = new Builder().forBrowser('chrome'); + console.log(builder.getChromeOptions()); let driver = await builder.build(); From cc46721c40d11b60c05287e0facbc9c69a0399a7 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 10 Nov 2024 13:47:37 +0800 Subject: [PATCH 195/258] asd --- .github/workflows/test.yml | 6 +- .../__tests__/browser-tests/browser.test.ts | 43 +- .../__tests__/browser-tests/works.test.js | 17 - apps/frontend/package.json | 1 - apps/frontend/pnpm-lock.yaml | 384 ------------------ 5 files changed, 16 insertions(+), 435 deletions(-) delete mode 100644 apps/frontend/__tests__/browser-tests/works.test.js diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6e099d6ab0..dcb13886eb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -105,10 +105,14 @@ jobs: cd ./apps/frontend pnpm i + - uses: nanasess/setup-chromedriver@v2 + with: + chromedriver-version: '130.0.6723.116' + - name: Run tests run: | cd ./apps/frontend - node ./__tests__/browser-tests/works.test.js + pnpm test -- ./__tests__/browser-tests diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index dee5121683..a8227c6c77 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -1,44 +1,23 @@ import { Browser, Builder, By, Key, until } from "selenium-webdriver" -import { path } from "chromedriver" -import { getBinaryPaths } from "selenium-webdriver/common/driverFinder" import Chrome from "selenium-webdriver/chrome" -describe("base selenium test", () => { - it.skip("works", async () => { - // referenced: https://www.npmjs.com/package/selenium-webdriver - console.log(path) - - let options = new Chrome.Options(); - options.setBrowserVersion("stable") - - let paths = getBinaryPaths(options) - let driverPath = paths.driverPath; - let browserPath = paths.browserPath; - console.log(paths); - - options.setChromeBinaryPath(browserPath) - - let service = new Chrome.ServiceBuilder().setPath(driverPath); - let driver = await new Builder().forBrowser(Browser.CHROME) - .setChromeOptions(options) - .setChromeService(service) - .build(); +describe("chrome webdriver installed correctly", () => { + it("does google search", async function test() { + const options = new Chrome.Options().addArguments("--headless=new") as Chrome.Options; + const builder = new Builder().forBrowser(Browser.CHROME).setChromeOptions(options); - console.log("got here"); + const driver = await builder.build(); try { - await driver.get('https://www.google.com/ncr') - console.log("got here"); - await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN) - console.log("got here"); - await driver.wait(until.titleIs('webdriver - Google Search'), 1000) - console.log("got here"); + await driver.get('http://www.google.com'); + await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); + await driver.wait(until.titleIs('webdriver - Google Search'), 1000); } finally { - await driver.quit() + await driver.quit(); } - }, 60000) -}) + }); +}); diff --git a/apps/frontend/__tests__/browser-tests/works.test.js b/apps/frontend/__tests__/browser-tests/works.test.js deleted file mode 100644 index fe98294e90..0000000000 --- a/apps/frontend/__tests__/browser-tests/works.test.js +++ /dev/null @@ -1,17 +0,0 @@ -require('chromedriver'); -const { Builder, By, Key, until } = require('selenium-webdriver'); -(async function test() { - const builder = new Builder().forBrowser('chrome'); - - console.log(builder.getChromeOptions()); - - let driver = await builder.build(); - - try { - await driver.get('http://www.google.com'); - await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); - await driver.wait(until.titleIs('webdriver - Google Search'), 1000); - } finally { - await driver.quit(); - } -})(); \ No newline at end of file diff --git a/apps/frontend/package.json b/apps/frontend/package.json index da143a8b4d..34cedd361d 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -48,7 +48,6 @@ "@types/react": "^18.3.8", "@types/react-dom": "^18.3.0", "@types/selenium-webdriver": "^4.1.27", - "chromedriver": "^130.0.4", "eslint": "^8", "eslint-config-next": "14.2.13", "jest": "^29.7.0", diff --git a/apps/frontend/pnpm-lock.yaml b/apps/frontend/pnpm-lock.yaml index 4a85647726..5b99c479b6 100644 --- a/apps/frontend/pnpm-lock.yaml +++ b/apps/frontend/pnpm-lock.yaml @@ -117,9 +117,6 @@ importers: '@types/selenium-webdriver': specifier: ^4.1.27 version: 4.1.27 - chromedriver: - specifier: ^130.0.4 - version: 130.0.4 eslint: specifier: ^8 version: 8.0.0 @@ -723,9 +720,6 @@ packages: '@swc/helpers@0.5.5': resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} - '@testim/chrome-version@1.1.4': - resolution: {integrity: sha512-kIhULpw9TrGYnHp/8VfdcneIcxKnLixmADtukQRtJUmsVlMg0niMkwV0xZmi8hqa57xqilIHjWFA0GKvEjVU5g==} - '@testing-library/dom@10.4.0': resolution: {integrity: sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==} engines: {node: '>=18'} @@ -753,9 +747,6 @@ packages: resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} - '@tootallnate/quickjs-emscripten@0.23.0': - resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} - '@tsconfig/node10@1.0.11': resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} @@ -850,9 +841,6 @@ packages: '@types/yargs@17.0.33': resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} - '@types/yauzl@2.10.3': - resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - '@typescript-eslint/eslint-plugin@8.8.0': resolution: {integrity: sha512-wORFWjU30B2WJ/aXBfOm1LX9v9nyt9D3jsSOxC3cCaTQGCW5k4jNpmjFv3U7p/7s4yvdjHzwtv2Sd2dOyhjS0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -935,10 +923,6 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} - agent-base@7.1.1: - resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} - engines: {node: '>= 14'} - ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -1033,10 +1017,6 @@ packages: ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} - ast-types@0.13.4: - resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} - engines: {node: '>=4'} - asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -1048,9 +1028,6 @@ packages: resolution: {integrity: sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==} engines: {node: '>=4'} - axios@1.7.7: - resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} - axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} @@ -1086,10 +1063,6 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - basic-ftp@5.0.5: - resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} - engines: {node: '>=10.0.0'} - brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -1108,9 +1081,6 @@ packages: bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} - buffer-crc32@0.2.13: - resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} - buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -1159,11 +1129,6 @@ packages: resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} engines: {node: '>= 14.16.0'} - chromedriver@130.0.4: - resolution: {integrity: sha512-lpR+PWXszij1k4Ig3t338Zvll9HtCTiwoLM7n4pCCswALHxzmgwaaIFBh3rt9+5wRk9D07oFblrazrBxwaYYAQ==} - engines: {node: '>=18'} - hasBin: true - ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} @@ -1202,9 +1167,6 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} - compare-versions@6.1.1: - resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} - compute-scroll-into-view@3.1.0: resolution: {integrity: sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==} @@ -1254,10 +1216,6 @@ packages: damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} - data-uri-to-buffer@6.0.2: - resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} - engines: {node: '>= 14'} - data-urls@3.0.2: resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==} engines: {node: '>=12'} @@ -1285,15 +1243,6 @@ packages: supports-color: optional: true - debug@4.3.1: - resolution: {integrity: sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.3.7: resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} @@ -1333,10 +1282,6 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - degenerator@5.0.1: - resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} - engines: {node: '>= 14'} - delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -1392,9 +1337,6 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - end-of-stream@1.4.4: - resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} - enhanced-resolve@5.17.1: resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} engines: {node: '>=10.13.0'} @@ -1601,11 +1543,6 @@ packages: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - extract-zip@2.0.1: - resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} - engines: {node: '>= 10.17.0'} - hasBin: true - fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1625,9 +1562,6 @@ packages: fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} - fd-slicer@1.1.0: - resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} - file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -1647,15 +1581,6 @@ packages: flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} - follow-redirects@1.15.9: - resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -1667,10 +1592,6 @@ packages: resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} engines: {node: '>= 6'} - fs-extra@11.2.0: - resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} - engines: {node: '>=14.14'} - fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -1711,10 +1632,6 @@ packages: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} - get-stream@5.2.0: - resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} - engines: {node: '>=8'} - get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -1726,10 +1643,6 @@ packages: get-tsconfig@4.8.1: resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} - get-uri@6.0.3: - resolution: {integrity: sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==} - engines: {node: '>= 14'} - glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1805,18 +1718,10 @@ packages: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} engines: {node: '>= 6'} - http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} - https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} - https-proxy-agent@7.0.5: - resolution: {integrity: sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==} - engines: {node: '>= 14'} - human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -1870,14 +1775,6 @@ packages: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} - ip-address@9.0.5: - resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} - engines: {node: '>= 12'} - - ip-regex@4.3.0: - resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==} - engines: {node: '>=8'} - is-arguments@1.1.1: resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} engines: {node: '>= 0.4'} @@ -1989,9 +1886,6 @@ packages: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} - is-url@1.2.4: - resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==} - is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} @@ -2003,10 +1897,6 @@ packages: resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} engines: {node: '>= 0.4'} - is2@2.0.9: - resolution: {integrity: sha512-rZkHeBn9Zzq52sd9IUIV3a5mfwBY+o2HePMh0wkGBM4z4qjvy2GwVxQ6nNXSfw6MmVP6gf1QIlWjiOavhM3x5g==} - engines: {node: '>=v0.10.0'} - isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} @@ -2199,9 +2089,6 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true - jsbn@1.1.0: - resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} - jsdom@20.0.3: resolution: {integrity: sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==} engines: {node: '>=14'} @@ -2240,9 +2127,6 @@ packages: engines: {node: '>=6'} hasBin: true - jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} - jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} @@ -2307,10 +2191,6 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lru-cache@7.18.3: - resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} - engines: {node: '>=12'} - lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true @@ -2366,9 +2246,6 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} - ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -2380,10 +2257,6 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - netmask@2.0.2: - resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} - engines: {node: '>= 0.4.0'} - next@14.2.13: resolution: {integrity: sha512-BseY9YNw8QJSwLYD7hlZzl6QVDoSFHL/URN5K64kVEVpCsSOWeyjbIGK+dZUaRViHTaMQX8aqmnn0PHBbGZezg==} engines: {node: '>=18.17.0'} @@ -2482,14 +2355,6 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} - pac-proxy-agent@7.0.2: - resolution: {integrity: sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==} - engines: {node: '>= 14'} - - pac-resolver@7.0.1: - resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} - engines: {node: '>= 14'} - pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} @@ -2531,9 +2396,6 @@ packages: resolution: {integrity: sha512-yFsoLMnurJKlQbx6kVSBpOp+AlNldY1JQS2BrSsHLKCZnq6t7saHleuHM5svuLNbQkUJXHLF3sKOJB1K0xulOw==} engines: {node: '>= 14'} - pend@1.2.0: - resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} - picocolors@1.1.0: resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} @@ -2583,19 +2445,9 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - proxy-agent@6.4.0: - resolution: {integrity: sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==} - engines: {node: '>= 14'} - - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - psl@1.9.0: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} - pump@3.0.2: - resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -3033,18 +2885,6 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} - smart-buffer@4.2.0: - resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} - engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - - socks-proxy-agent@8.0.4: - resolution: {integrity: sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==} - engines: {node: '>= 14'} - - socks@2.8.3: - resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==} - engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} - source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -3059,9 +2899,6 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - sprintf-js@1.1.3: - resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} - stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -3182,9 +3019,6 @@ packages: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} - tcp-port-used@1.0.2: - resolution: {integrity: sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA==} - test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} @@ -3291,10 +3125,6 @@ packages: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} - universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} - update-browserslist-db@1.1.1: resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} hasBin: true @@ -3443,9 +3273,6 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} - yauzl@2.10.0: - resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} - yjs@13.6.20: resolution: {integrity: sha512-Z2YZI+SYqK7XdWlloI3lhMiKnCdFCVC4PchpdO+mCYwtiTwncjUbnRK9R1JmkNfdmHyDXuWN3ibJAt0wsqTbLQ==} engines: {node: '>=16.0.0', npm: '>=8.0.0'} @@ -4226,8 +4053,6 @@ snapshots: '@swc/counter': 0.1.3 tslib: 2.7.0 - '@testim/chrome-version@1.1.4': {} - '@testing-library/dom@10.4.0': dependencies: '@babel/code-frame': 7.26.2 @@ -4261,8 +4086,6 @@ snapshots: '@tootallnate/once@2.0.0': {} - '@tootallnate/quickjs-emscripten@0.23.0': {} - '@tsconfig/node10@1.0.11': {} '@tsconfig/node12@1.0.11': {} @@ -4371,11 +4194,6 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@types/yauzl@2.10.3': - dependencies: - '@types/node': 20.0.0 - optional: true - '@typescript-eslint/eslint-plugin@8.8.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint@8.0.0)(typescript@5.0.2)': dependencies: '@eslint-community/regexpp': 4.11.1 @@ -4480,12 +4298,6 @@ snapshots: transitivePeerDependencies: - supports-color - agent-base@7.1.1: - dependencies: - debug: 4.3.7 - transitivePeerDependencies: - - supports-color - ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -4659,10 +4471,6 @@ snapshots: ast-types-flow@0.0.8: {} - ast-types@0.13.4: - dependencies: - tslib: 2.7.0 - asynckit@0.4.0: {} available-typed-arrays@1.0.7: @@ -4671,14 +4479,6 @@ snapshots: axe-core@4.10.0: {} - axios@1.7.7: - dependencies: - follow-redirects: 1.15.9 - form-data: 4.0.1 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - axobject-query@4.1.0: {} babel-jest@29.7.0(@babel/core@7.26.0): @@ -4740,8 +4540,6 @@ snapshots: base64-js@1.5.1: {} - basic-ftp@5.0.5: {} - brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -4766,8 +4564,6 @@ snapshots: dependencies: node-int64: 0.4.0 - buffer-crc32@0.2.13: {} - buffer-from@1.1.2: {} buffer@6.0.3: @@ -4813,19 +4609,6 @@ snapshots: dependencies: readdirp: 4.0.1 - chromedriver@130.0.4: - dependencies: - '@testim/chrome-version': 1.1.4 - axios: 1.7.7 - compare-versions: 6.1.1 - extract-zip: 2.0.1 - proxy-agent: 6.4.0 - proxy-from-env: 1.1.0 - tcp-port-used: 1.0.2 - transitivePeerDependencies: - - debug - - supports-color - ci-info@3.9.0: {} cjs-module-lexer@1.4.1: {} @@ -4866,8 +4649,6 @@ snapshots: dependencies: delayed-stream: 1.0.0 - compare-versions@6.1.1: {} - compute-scroll-into-view@3.1.0: {} concat-map@0.0.1: {} @@ -4919,8 +4700,6 @@ snapshots: damerau-levenshtein@1.0.8: {} - data-uri-to-buffer@6.0.2: {} - data-urls@3.0.2: dependencies: abab: 2.0.6 @@ -4951,10 +4730,6 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.3.1: - dependencies: - ms: 2.1.2 - debug@4.3.7: dependencies: ms: 2.1.3 @@ -5000,12 +4775,6 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 - degenerator@5.0.1: - dependencies: - ast-types: 0.13.4 - escodegen: 2.1.0 - esprima: 4.0.1 - delayed-stream@1.0.0: {} dequal@2.0.3: {} @@ -5042,10 +4811,6 @@ snapshots: emoji-regex@9.2.2: {} - end-of-stream@1.4.4: - dependencies: - once: 1.4.0 - enhanced-resolve@5.17.1: dependencies: graceful-fs: 4.2.11 @@ -5415,16 +5180,6 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 - extract-zip@2.0.1: - dependencies: - debug: 4.3.7 - get-stream: 5.2.0 - yauzl: 2.10.0 - optionalDependencies: - '@types/yauzl': 2.10.3 - transitivePeerDependencies: - - supports-color - fast-deep-equal@3.1.3: {} fast-glob@3.3.2: @@ -5447,10 +5202,6 @@ snapshots: dependencies: bser: 2.1.1 - fd-slicer@1.1.0: - dependencies: - pend: 1.2.0 - file-entry-cache@6.0.1: dependencies: flat-cache: 3.2.0 @@ -5472,8 +5223,6 @@ snapshots: flatted@3.3.1: {} - follow-redirects@1.15.9: {} - for-each@0.3.3: dependencies: is-callable: 1.2.7 @@ -5489,12 +5238,6 @@ snapshots: combined-stream: 1.0.8 mime-types: 2.1.35 - fs-extra@11.2.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 - fs.realpath@1.0.0: {} fsevents@2.3.3: @@ -5529,10 +5272,6 @@ snapshots: get-package-type@0.1.0: {} - get-stream@5.2.0: - dependencies: - pump: 3.0.2 - get-stream@6.0.1: {} get-symbol-description@1.0.2: @@ -5545,15 +5284,6 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 - get-uri@6.0.3: - dependencies: - basic-ftp: 5.0.5 - data-uri-to-buffer: 6.0.2 - debug: 4.3.7 - fs-extra: 11.2.0 - transitivePeerDependencies: - - supports-color - glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -5632,13 +5362,6 @@ snapshots: transitivePeerDependencies: - supports-color - http-proxy-agent@7.0.2: - dependencies: - agent-base: 7.1.1 - debug: 4.3.7 - transitivePeerDependencies: - - supports-color - https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 @@ -5646,13 +5369,6 @@ snapshots: transitivePeerDependencies: - supports-color - https-proxy-agent@7.0.5: - dependencies: - agent-base: 7.1.1 - debug: 4.3.7 - transitivePeerDependencies: - - supports-color - human-signals@2.1.0: {} iconv-lite@0.6.3: @@ -5696,13 +5412,6 @@ snapshots: hasown: 2.0.2 side-channel: 1.0.6 - ip-address@9.0.5: - dependencies: - jsbn: 1.1.0 - sprintf-js: 1.1.3 - - ip-regex@4.3.0: {} - is-arguments@1.1.1: dependencies: call-bind: 1.0.7 @@ -5801,8 +5510,6 @@ snapshots: dependencies: which-typed-array: 1.1.15 - is-url@1.2.4: {} - is-weakmap@2.0.2: {} is-weakref@1.0.2: @@ -5814,12 +5521,6 @@ snapshots: call-bind: 1.0.7 get-intrinsic: 1.2.4 - is2@2.0.9: - dependencies: - deep-is: 0.1.4 - ip-regex: 4.3.0 - is-url: 1.2.4 - isarray@1.0.0: {} isarray@2.0.5: {} @@ -6218,8 +5919,6 @@ snapshots: dependencies: argparse: 2.0.1 - jsbn@1.1.0: {} - jsdom@20.0.3: dependencies: abab: 2.0.6 @@ -6273,12 +5972,6 @@ snapshots: json5@2.2.3: {} - jsonfile@6.1.0: - dependencies: - universalify: 2.0.1 - optionalDependencies: - graceful-fs: 4.2.11 - jsx-ast-utils@3.3.5: dependencies: array-includes: 3.1.8 @@ -6342,8 +6035,6 @@ snapshots: dependencies: yallist: 3.1.1 - lru-cache@7.18.3: {} - lz-string@1.5.0: {} make-dir@4.0.0: @@ -6387,16 +6078,12 @@ snapshots: minipass@7.1.2: {} - ms@2.1.2: {} - ms@2.1.3: {} nanoid@3.3.7: {} natural-compare@1.4.0: {} - netmask@2.0.2: {} - next@14.2.13(@babel/core@7.26.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.79.2): dependencies: '@next/env': 14.2.13 @@ -6509,24 +6196,6 @@ snapshots: p-try@2.2.0: {} - pac-proxy-agent@7.0.2: - dependencies: - '@tootallnate/quickjs-emscripten': 0.23.0 - agent-base: 7.1.1 - debug: 4.3.7 - get-uri: 6.0.3 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.5 - pac-resolver: 7.0.1 - socks-proxy-agent: 8.0.4 - transitivePeerDependencies: - - supports-color - - pac-resolver@7.0.1: - dependencies: - degenerator: 5.0.1 - netmask: 2.0.2 - pako@1.0.11: {} parent-module@1.0.1: @@ -6566,8 +6235,6 @@ snapshots: peerjs-js-binarypack: 2.1.0 webrtc-adapter: 9.0.1 - pend@1.2.0: {} - picocolors@1.1.0: {} picomatch@2.3.1: {} @@ -6615,28 +6282,8 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 - proxy-agent@6.4.0: - dependencies: - agent-base: 7.1.1 - debug: 4.3.7 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.5 - lru-cache: 7.18.3 - pac-proxy-agent: 7.0.2 - proxy-from-env: 1.1.0 - socks-proxy-agent: 8.0.4 - transitivePeerDependencies: - - supports-color - - proxy-from-env@1.1.0: {} - psl@1.9.0: {} - pump@3.0.2: - dependencies: - end-of-stream: 1.4.4 - once: 1.4.0 - punycode@2.3.1: {} pure-rand@6.1.0: {} @@ -7178,21 +6825,6 @@ snapshots: slash@3.0.0: {} - smart-buffer@4.2.0: {} - - socks-proxy-agent@8.0.4: - dependencies: - agent-base: 7.1.1 - debug: 4.3.7 - socks: 2.8.3 - transitivePeerDependencies: - - supports-color - - socks@2.8.3: - dependencies: - ip-address: 9.0.5 - smart-buffer: 4.2.0 - source-map-js@1.2.1: {} source-map-support@0.5.13: @@ -7204,8 +6836,6 @@ snapshots: sprintf-js@1.0.3: {} - sprintf-js@1.1.3: {} - stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 @@ -7332,13 +6962,6 @@ snapshots: tapable@2.2.1: {} - tcp-port-used@1.0.2: - dependencies: - debug: 4.3.1 - is2: 2.0.9 - transitivePeerDependencies: - - supports-color - test-exclude@6.0.0: dependencies: '@istanbuljs/schema': 0.1.3 @@ -7456,8 +7079,6 @@ snapshots: universalify@0.2.0: {} - universalify@2.0.1: {} - update-browserslist-db@1.1.1(browserslist@4.24.2): dependencies: browserslist: 4.24.2 @@ -7622,11 +7243,6 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 - yauzl@2.10.0: - dependencies: - buffer-crc32: 0.2.13 - fd-slicer: 1.1.0 - yjs@13.6.20: dependencies: lib0: 0.2.98 From f5b521a2f4d26ec5207df63c2e128f4d05551801 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 10 Nov 2024 20:08:03 +0800 Subject: [PATCH 196/258] asd --- .../__tests__/browser-tests/browser.test.ts | 56 ++++++++++++++----- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index a8227c6c77..5d5207c6a8 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -1,23 +1,53 @@ -import { Browser, Builder, By, Key, until } from "selenium-webdriver" +import { Actions, Browser, Builder, By, Key, until, WebDriver } from "selenium-webdriver" import Chrome from "selenium-webdriver/chrome" +const URL = 'http://localhost:3000/'; +const ETERNAL_JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjk5OTk5OTk5OTk5fQ.Z4_FVGQ5lIcouP3m4YLMr6pGMF17IJFfo2yOTiN58DY" -describe("chrome webdriver installed correctly", () => { - it("does google search", async function test() { - const options = new Chrome.Options().addArguments("--headless=new") as Chrome.Options; - const builder = new Builder().forBrowser(Browser.CHROME).setChromeOptions(options); - - const driver = await builder.build(); - - try { +describe("chrome browser", () => { + const options = new Chrome.Options() + // .addArguments("--headless=new") as Chrome.Options; + const builder = new Builder().forBrowser(Browser.CHROME).setChromeOptions(options); + let driver: WebDriver; + + beforeEach(async () => { + driver = await builder.build(); + }) + + afterEach(async () => { + await driver.quit(); + }) + + describe.skip("chrome webdriver installed correctly", () => { + it("does google search", async () => { await driver.get('http://www.google.com'); await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); await driver.wait(until.titleIs('webdriver - Google Search'), 1000); - } finally { - await driver.quit(); - } + }); + it("does another google search", async () => { + await driver.get('http://www.google.com'); + await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); + await driver.wait(until.titleIs('webdriver - Google Search'), 1000); + }); }); -}); + + describe("browser-test", () => { + it.skip("accesses and login to peerprep", async () => { + await driver.get(URL); + await driver.wait(until.urlIs(`${URL}login`)); + + const [email, password] = await driver.findElements(By.css("input")) + const submit = await driver.findElement(By.css("button[type=\"submit\"]")) + + await email.sendKeys("admin@gmail.com"); + await password.sendKeys("admin"); + + await submit.click(); + await driver.wait(until.urlIs(`${URL}`)); + }); + }) +}) + From f1e7e40222a3f96cce21e6df3d4596c7f257ee71 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 10 Nov 2024 20:08:35 +0800 Subject: [PATCH 197/258] asd --- apps/frontend/__tests__/browser-tests/browser.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index 5d5207c6a8..b3550af901 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -6,7 +6,7 @@ const ETERNAL_JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3OD describe("chrome browser", () => { const options = new Chrome.Options() - // .addArguments("--headless=new") as Chrome.Options; + .addArguments("--headless=new") as Chrome.Options; const builder = new Builder().forBrowser(Browser.CHROME).setChromeOptions(options); let driver: WebDriver; From 45ebeb433a3ca542a98fd90e1ab31092d5bc49f2 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 10 Nov 2024 20:32:04 +0800 Subject: [PATCH 198/258] asd --- .github/workflows/test.yml | 12 +++++++++++- .../frontend/__tests__/browser-tests/browser.test.ts | 4 ++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index dcb13886eb..123a9dd7b3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -112,7 +112,7 @@ jobs: - name: Run tests run: | cd ./apps/frontend - pnpm test -- ./__tests__/browser-tests + pnpm test -- ./__tests__/browser-tests -t "chrome webdriver installed correctly" @@ -253,3 +253,13 @@ jobs: echo "WebSocket for Signalling Service is live" fi # We can add more tests here + + - Name: Install Chrome WebDriver + uses: nanasess/setup-chromedriver@v2 + with: + chromedriver-version: '130.0.6723.116' + + - name: Run Browser Test + run: | + cd ./apps/frontend + pnpm test -- ./__tests__/browser-tests diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index b3550af901..b715255fbd 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -6,7 +6,7 @@ const ETERNAL_JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3OD describe("chrome browser", () => { const options = new Chrome.Options() - .addArguments("--headless=new") as Chrome.Options; + .addArguments("--headless=new") as Chrome.Options; // uncomment locally to see the steps in action const builder = new Builder().forBrowser(Browser.CHROME).setChromeOptions(options); let driver: WebDriver; @@ -18,7 +18,7 @@ describe("chrome browser", () => { await driver.quit(); }) - describe.skip("chrome webdriver installed correctly", () => { + describe("chrome webdriver installed correctly", () => { it("does google search", async () => { await driver.get('http://www.google.com'); await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); From 3570555db6221f063e29670e9110f5b2dda79bb4 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 10 Nov 2024 20:32:56 +0800 Subject: [PATCH 199/258] asd --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 123a9dd7b3..8dfac54250 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -254,7 +254,7 @@ jobs: fi # We can add more tests here - - Name: Install Chrome WebDriver + - name: Install Chrome WebDriver uses: nanasess/setup-chromedriver@v2 with: chromedriver-version: '130.0.6723.116' From cccfa548c8833c97d17d63f833bd73a1781825a4 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 10 Nov 2024 20:44:24 +0800 Subject: [PATCH 200/258] install pnpm --- .github/workflows/test.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8dfac54250..28b1248e66 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -254,6 +254,12 @@ jobs: fi # We can add more tests here + + - name: Install pnpm + - uses: pnpm/action-setup@v4 + with: + version: 9.1.4 + - name: Install Chrome WebDriver uses: nanasess/setup-chromedriver@v2 with: From 2f97a34c78b31c528b9d95cb247281236114f0a5 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 10 Nov 2024 20:45:26 +0800 Subject: [PATCH 201/258] asd --- .github/workflows/test.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 28b1248e66..bd7a397336 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -254,11 +254,10 @@ jobs: fi # We can add more tests here - - name: Install pnpm - - uses: pnpm/action-setup@v4 - with: - version: 9.1.4 + uses: pnpm/action-setup@v4 + with: + version: 9.1.4 - name: Install Chrome WebDriver uses: nanasess/setup-chromedriver@v2 From c78449683241496b903e01b143093f07c42c7e4c Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 10 Nov 2024 21:00:52 +0800 Subject: [PATCH 202/258] asd --- .github/workflows/test.yml | 9 +++++++-- apps/frontend/package.json | 4 +++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bd7a397336..1d8036ba25 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -83,7 +83,7 @@ jobs: - name: Run tests run: | cd ./apps/frontend - pnpm test -- __tests__/unit-tests + pnpm unit-test browser-test: runs-on: ubuntu-latest @@ -259,6 +259,11 @@ jobs: with: version: 9.1.4 + - name: Install dependencies + run: | + cd ./apps/frontend + pnpm i -D + - name: Install Chrome WebDriver uses: nanasess/setup-chromedriver@v2 with: @@ -267,4 +272,4 @@ jobs: - name: Run Browser Test run: | cd ./apps/frontend - pnpm test -- ./__tests__/browser-tests + pnpm browser-test diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 34cedd361d..bab7a93c21 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -7,7 +7,9 @@ "build": "next build", "start": "next start", "lint": "next lint", - "test": "jest" + "test": "jest", + "unit-test": "jest __tests__/unit-tests", + "browser-test": "jest __tests__/browser-tests" }, "dependencies": { "@ant-design/icons": "^5.5.1", From f58f0351a0f83babfcc755ed4b4fc0909ed3cc09 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 10 Nov 2024 21:13:59 +0800 Subject: [PATCH 203/258] asd --- .github/workflows/test.yml | 2 +- apps/frontend/__tests__/browser-tests/browser.test.ts | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1d8036ba25..7b0716889d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -262,7 +262,7 @@ jobs: - name: Install dependencies run: | cd ./apps/frontend - pnpm i -D + pnpm i - name: Install Chrome WebDriver uses: nanasess/setup-chromedriver@v2 diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index b715255fbd..97dcfe8e30 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -6,7 +6,7 @@ const ETERNAL_JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3OD describe("chrome browser", () => { const options = new Chrome.Options() - .addArguments("--headless=new") as Chrome.Options; // uncomment locally to see the steps in action + // .addArguments("--headless=new") as Chrome.Options; // uncomment locally to see the steps in action const builder = new Builder().forBrowser(Browser.CHROME).setChromeOptions(options); let driver: WebDriver; @@ -32,7 +32,7 @@ describe("chrome browser", () => { }); describe("browser-test", () => { - it.skip("accesses and login to peerprep", async () => { + it("accesses and login to peerprep", async () => { await driver.get(URL); await driver.wait(until.urlIs(`${URL}login`)); @@ -44,6 +44,11 @@ describe("chrome browser", () => { await submit.click(); await driver.wait(until.urlIs(`${URL}`)); + + const slogan1 = await driver.findElement(By.xpath("/html/body/div[1]/main/div/div[1]/div[2]/span[1]")).then(ele => ele.getText()) + const slogan2 = await driver.findElement(By.xpath("/html/body/div[1]/main/div/div[1]/div[2]/span[2]")).then(ele => ele.getText()) + + expect(slogan1 + slogan2).toBe("A better way to prepare for coding interviews withpeers"); }); }) }) From 862051a6c53d75de3255c07deacaa6ed41156367 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 10 Nov 2024 21:16:04 +0800 Subject: [PATCH 204/258] asd --- .github/workflows/test.yml | 2 +- apps/frontend/__tests__/browser-tests/browser.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7b0716889d..9c2bab3ab7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -112,7 +112,7 @@ jobs: - name: Run tests run: | cd ./apps/frontend - pnpm test -- ./__tests__/browser-tests -t "chrome webdriver installed correctly" + pnpm browser-test -- -t "chrome webdriver installed correctly" diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index 97dcfe8e30..1563112b01 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -6,7 +6,7 @@ const ETERNAL_JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3OD describe("chrome browser", () => { const options = new Chrome.Options() - // .addArguments("--headless=new") as Chrome.Options; // uncomment locally to see the steps in action + .addArguments("--headless=new") as Chrome.Options; // uncomment locally to see the steps in action const builder = new Builder().forBrowser(Browser.CHROME).setChromeOptions(options); let driver: WebDriver; From 311be82702e8195abba4dc76b3a085e1f72c163d Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Sun, 10 Nov 2024 21:40:29 +0800 Subject: [PATCH 205/258] set up browser tests for Chrome --- .github/workflows/test.yml | 22 ++- .../__tests__/browser-tests/browser.test.ts | 58 ++++++++ .../{ => unit-tests}/Datetime.test.ts | 0 .../dependencymocking.test.ts | 0 .../{ => unit-tests}/question.test.ts | 0 apps/frontend/package.json | 9 +- apps/frontend/pnpm-lock.yaml | 128 ++++++++++++++++++ apps/signalling-service/.dockerignore | 9 ++ apps/signalling-service/pnpm-lock.yaml | 40 +++--- 9 files changed, 247 insertions(+), 19 deletions(-) create mode 100644 apps/frontend/__tests__/browser-tests/browser.test.ts rename apps/frontend/__tests__/{ => unit-tests}/Datetime.test.ts (100%) rename apps/frontend/__tests__/{ => unit-tests}/dependencymocking.test.ts (100%) rename apps/frontend/__tests__/{ => unit-tests}/question.test.ts (100%) create mode 100644 apps/signalling-service/.dockerignore diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 90408360b4..8d18e13b1c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -83,7 +83,7 @@ jobs: - name: Run tests run: | cd ./apps/frontend - pnpm test + pnpm unit-test test-docker-compose: runs-on: ubuntu-latest @@ -222,3 +222,23 @@ jobs: echo "WebSocket for Signalling Service is live" fi # We can add more tests here + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.1.4 + + - name: Install dependencies + run: | + cd ./apps/frontend + pnpm i + + - name: Install Chrome WebDriver + uses: nanasess/setup-chromedriver@v2 + with: + chromedriver-version: '130.0.6723.116' + + - name: Run Browser Test + run: | + cd ./apps/frontend + pnpm browser-test diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts new file mode 100644 index 0000000000..1563112b01 --- /dev/null +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -0,0 +1,58 @@ +import { Actions, Browser, Builder, By, Key, until, WebDriver } from "selenium-webdriver" + +import Chrome from "selenium-webdriver/chrome" +const URL = 'http://localhost:3000/'; +const ETERNAL_JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjk5OTk5OTk5OTk5fQ.Z4_FVGQ5lIcouP3m4YLMr6pGMF17IJFfo2yOTiN58DY" + +describe("chrome browser", () => { + const options = new Chrome.Options() + .addArguments("--headless=new") as Chrome.Options; // uncomment locally to see the steps in action + const builder = new Builder().forBrowser(Browser.CHROME).setChromeOptions(options); + let driver: WebDriver; + + beforeEach(async () => { + driver = await builder.build(); + }) + + afterEach(async () => { + await driver.quit(); + }) + + describe("chrome webdriver installed correctly", () => { + it("does google search", async () => { + await driver.get('http://www.google.com'); + await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); + await driver.wait(until.titleIs('webdriver - Google Search'), 1000); + }); + it("does another google search", async () => { + await driver.get('http://www.google.com'); + await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); + await driver.wait(until.titleIs('webdriver - Google Search'), 1000); + }); + }); + + describe("browser-test", () => { + it("accesses and login to peerprep", async () => { + await driver.get(URL); + await driver.wait(until.urlIs(`${URL}login`)); + + const [email, password] = await driver.findElements(By.css("input")) + const submit = await driver.findElement(By.css("button[type=\"submit\"]")) + + await email.sendKeys("admin@gmail.com"); + await password.sendKeys("admin"); + + await submit.click(); + await driver.wait(until.urlIs(`${URL}`)); + + const slogan1 = await driver.findElement(By.xpath("/html/body/div[1]/main/div/div[1]/div[2]/span[1]")).then(ele => ele.getText()) + const slogan2 = await driver.findElement(By.xpath("/html/body/div[1]/main/div/div[1]/div[2]/span[2]")).then(ele => ele.getText()) + + expect(slogan1 + slogan2).toBe("A better way to prepare for coding interviews withpeers"); + }); + }) +}) + + + + diff --git a/apps/frontend/__tests__/Datetime.test.ts b/apps/frontend/__tests__/unit-tests/Datetime.test.ts similarity index 100% rename from apps/frontend/__tests__/Datetime.test.ts rename to apps/frontend/__tests__/unit-tests/Datetime.test.ts diff --git a/apps/frontend/__tests__/dependencymocking.test.ts b/apps/frontend/__tests__/unit-tests/dependencymocking.test.ts similarity index 100% rename from apps/frontend/__tests__/dependencymocking.test.ts rename to apps/frontend/__tests__/unit-tests/dependencymocking.test.ts diff --git a/apps/frontend/__tests__/question.test.ts b/apps/frontend/__tests__/unit-tests/question.test.ts similarity index 100% rename from apps/frontend/__tests__/question.test.ts rename to apps/frontend/__tests__/unit-tests/question.test.ts diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 792fc18474..bab7a93c21 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -7,7 +7,9 @@ "build": "next build", "start": "next start", "lint": "next lint", - "test": "jest" + "test": "jest", + "unit-test": "jest __tests__/unit-tests", + "browser-test": "jest __tests__/browser-tests" }, "dependencies": { "@ant-design/icons": "^5.5.1", @@ -37,19 +39,22 @@ "yjs": "^13.6.20" }, "devDependencies": { - "@types/codemirror": "^5.60.15", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.0.1", + "@types/chromedriver": "^81.0.5", + "@types/codemirror": "^5.60.15", "@types/jest": "^29.5.14", "@types/node": "^20", "@types/peerjs": "^1.1.0", "@types/react": "^18.3.8", "@types/react-dom": "^18.3.0", + "@types/selenium-webdriver": "^4.1.27", "eslint": "^8", "eslint-config-next": "14.2.13", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", + "selenium-webdriver": "^4.26.0", "ts-node": "^10.9.2", "typescript": "^5" }, diff --git a/apps/frontend/pnpm-lock.yaml b/apps/frontend/pnpm-lock.yaml index 413f0c29e3..5b99c479b6 100644 --- a/apps/frontend/pnpm-lock.yaml +++ b/apps/frontend/pnpm-lock.yaml @@ -93,6 +93,9 @@ importers: '@testing-library/react': specifier: ^16.0.1 version: 16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.8)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@types/chromedriver': + specifier: ^81.0.5 + version: 81.0.5 '@types/codemirror': specifier: ^5.60.15 version: 5.60.15 @@ -111,6 +114,9 @@ importers: '@types/react-dom': specifier: ^18.3.0 version: 18.3.0 + '@types/selenium-webdriver': + specifier: ^4.1.27 + version: 4.1.27 eslint: specifier: ^8 version: 8.0.0 @@ -123,6 +129,9 @@ importers: jest-environment-jsdom: specifier: ^29.7.0 version: 29.7.0 + selenium-webdriver: + specifier: ^4.26.0 + version: 4.26.0 ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@20.0.0)(typescript@5.0.2) @@ -344,6 +353,9 @@ packages: resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==} engines: {node: '>=6.9.0'} + '@bazel/runfiles@6.3.1': + resolution: {integrity: sha512-1uLNT5NZsUVIGS4syuHwTzZ8HycMPyr6POA3FCE4GbMtc4rhoJk8aZKtNIRthJYfL+iioppi+rTfH3olMPr9nA==} + '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} @@ -762,6 +774,9 @@ packages: '@types/babel__traverse@7.20.6': resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + '@types/chromedriver@81.0.5': + resolution: {integrity: sha512-VwV+WTTFHYZotBn57QQ8gd4TE7CGJ15KPM+xJJrKbiQQSccTY7zVXuConSBlyWrO+AFpVxuzmluK3xvzxGmkCw==} + '@types/codemirror@5.60.15': resolution: {integrity: sha512-dTOvwEQ+ouKJ/rE9LT1Ue2hmP6H1mZv5+CCnNWu2qtiOe2LQa9lCprEY20HxiDmV/Bxh+dXjywmy5aKvoGjULA==} @@ -805,6 +820,9 @@ packages: '@types/react@18.3.8': resolution: {integrity: sha512-syBUrW3/XpnW4WJ41Pft+I+aPoDVbrBVQGEnbD7NijDGlVC+8gV/XKRY+7vMDlfPpbwYt0l1vd/Sj8bJGMbs9Q==} + '@types/selenium-webdriver@4.1.27': + resolution: {integrity: sha512-ALqsj8D7Swb6MnBQuAQ58J3KC3yh6fLGtAmpBmnZX8j+0kmP7NaLt56CuzBw2W2bXPrvHFTgn8iekOQFUKXEQA==} + '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} @@ -814,6 +832,9 @@ packages: '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + '@types/ws@8.5.13': + resolution: {integrity: sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==} + '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} @@ -1158,6 +1179,9 @@ packages: copy-to-clipboard@3.3.3: resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + create-jest@29.7.0: resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -1717,6 +1741,9 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + immutable@4.3.7: resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} @@ -1870,6 +1897,9 @@ packages: resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} engines: {node: '>= 0.4'} + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} @@ -2101,6 +2131,9 @@ packages: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} + jszip@3.10.1: + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + jwt-decode@4.0.0: resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} engines: {node: '>=18'} @@ -2132,6 +2165,9 @@ packages: engines: {node: '>=16'} hasBin: true + lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} @@ -2319,6 +2355,9 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -2392,6 +2431,9 @@ packages: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + progress@2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} @@ -2676,6 +2718,9 @@ packages: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} engines: {node: '>=0.10.0'} + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} @@ -2756,6 +2801,9 @@ packages: resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} engines: {node: '>=0.4'} + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -2784,6 +2832,10 @@ packages: sdp@3.2.0: resolution: {integrity: sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw==} + selenium-webdriver@4.26.0: + resolution: {integrity: sha512-nA7jMRIPV17mJmAiTDBWN96Sy0Uxrz5CCLb7bLVV6PpL417SyBMPc2Zo/uoREc2EOHlzHwHwAlFtgmSngSY4WQ==} + engines: {node: '>= 14.21.0'} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -2801,6 +2853,9 @@ packages: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -2892,6 +2947,9 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} @@ -2972,6 +3030,10 @@ packages: resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} engines: {node: '>=12.22'} + tmp@0.2.3: + resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} + engines: {node: '>=14.14'} + tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} @@ -3478,6 +3540,8 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 + '@bazel/runfiles@6.3.1': {} + '@bcoe/v8-coverage@0.2.3': {} '@codemirror/autocomplete@6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.3)': @@ -4053,6 +4117,10 @@ snapshots: dependencies: '@babel/types': 7.26.0 + '@types/chromedriver@81.0.5': + dependencies: + '@types/node': 20.0.0 + '@types/codemirror@5.60.15': dependencies: '@types/tern': 0.23.9 @@ -4103,6 +4171,11 @@ snapshots: '@types/prop-types': 15.7.13 csstype: 3.1.3 + '@types/selenium-webdriver@4.1.27': + dependencies: + '@types/node': 20.0.0 + '@types/ws': 8.5.13 + '@types/stack-utils@2.0.3': {} '@types/tern@0.23.9': @@ -4111,6 +4184,10 @@ snapshots: '@types/tough-cookie@4.0.5': {} + '@types/ws@8.5.13': + dependencies: + '@types/node': 20.0.0 + '@types/yargs-parser@21.0.3': {} '@types/yargs@17.0.33': @@ -4582,6 +4659,8 @@ snapshots: dependencies: toggle-selection: 1.0.6 + core-util-is@1.0.3: {} + create-jest@29.7.0(@types/node@20.0.0)(ts-node@10.9.2(@types/node@20.0.0)(typescript@5.0.2)): dependencies: '@jest/types': 29.6.3 @@ -5302,6 +5381,8 @@ snapshots: ignore@5.3.2: {} + immediate@3.0.6: {} + immutable@4.3.7: {} import-fresh@3.3.0: @@ -5440,6 +5521,8 @@ snapshots: call-bind: 1.0.7 get-intrinsic: 1.2.4 + isarray@1.0.0: {} + isarray@2.0.5: {} isexe@2.0.0: {} @@ -5896,6 +5979,13 @@ snapshots: object.assign: 4.1.5 object.values: 1.2.0 + jszip@3.10.1: + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + jwt-decode@4.0.0: {} keyv@4.5.4: @@ -5921,6 +6011,10 @@ snapshots: dependencies: isomorphic.js: 0.2.5 + lie@3.3.0: + dependencies: + immediate: 3.0.6 + lines-and-columns@1.2.4: {} locate-path@5.0.0: @@ -6102,6 +6196,8 @@ snapshots: p-try@2.2.0: {} + pako@1.0.11: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -6171,6 +6267,8 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 + process-nextick-args@2.0.1: {} + progress@2.0.3: {} prompts@2.4.2: @@ -6539,6 +6637,16 @@ snapshots: dependencies: loose-envify: 1.4.0 + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + readable-stream@3.6.2: dependencies: inherits: 2.0.4 @@ -6620,6 +6728,8 @@ snapshots: has-symbols: 1.0.3 isarray: 2.0.5 + safe-buffer@5.1.2: {} + safe-buffer@5.2.1: {} safe-regex-test@1.0.3: @@ -6650,6 +6760,16 @@ snapshots: sdp@3.2.0: {} + selenium-webdriver@4.26.0: + dependencies: + '@bazel/runfiles': 6.3.1 + jszip: 3.10.1 + tmp: 0.2.3 + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + semver@6.3.1: {} semver@7.6.3: {} @@ -6670,6 +6790,8 @@ snapshots: functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 + setimmediate@1.0.5: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -6787,6 +6909,10 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 @@ -6846,6 +6972,8 @@ snapshots: throttle-debounce@5.0.2: {} + tmp@0.2.3: {} + tmpl@1.0.5: {} to-regex-range@5.0.1: diff --git a/apps/signalling-service/.dockerignore b/apps/signalling-service/.dockerignore new file mode 100644 index 0000000000..3f214be645 --- /dev/null +++ b/apps/signalling-service/.dockerignore @@ -0,0 +1,9 @@ +node_modules +.git +.gitignore +README.md +LICENSE +.env +.env* +Dockerfile +.dockerignore \ No newline at end of file diff --git a/apps/signalling-service/pnpm-lock.yaml b/apps/signalling-service/pnpm-lock.yaml index cd6e4916a0..04ce15c614 100644 --- a/apps/signalling-service/pnpm-lock.yaml +++ b/apps/signalling-service/pnpm-lock.yaml @@ -1,32 +1,31 @@ -lockfileVersion: '6.0' +lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -dependencies: - lib0: - specifier: ^0.2.98 - version: 0.2.98 - ws: - specifier: ^8.18.0 - version: 8.18.0 +importers: + + .: + dependencies: + lib0: + specifier: ^0.2.98 + version: 0.2.98 + ws: + specifier: ^8.18.0 + version: 8.18.0 packages: - /isomorphic.js@0.2.5: + isomorphic.js@0.2.5: resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} - dev: false - /lib0@0.2.98: + lib0@0.2.98: resolution: {integrity: sha512-XteTiNO0qEXqqweWx+b21p/fBnNHUA1NwAtJNJek1oPrewEZs2uiT4gWivHKr9GqCjDPAhchz0UQO8NwU3bBNA==} engines: {node: '>=16'} hasBin: true - dependencies: - isomorphic.js: 0.2.5 - dev: false - /ws@8.18.0: + ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} peerDependencies: @@ -37,4 +36,13 @@ packages: optional: true utf-8-validate: optional: true - dev: false + +snapshots: + + isomorphic.js@0.2.5: {} + + lib0@0.2.98: + dependencies: + isomorphic.js: 0.2.5 + + ws@8.18.0: {} From f86888bacd25e2770fc6cb0fbfdaab4f728b8272 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Mon, 11 Nov 2024 05:34:02 +0800 Subject: [PATCH 206/258] Increase timeout for browser tests, verbosify jest --- .../frontend/__tests__/browser-tests/browser.test.ts | 9 +++++---- apps/frontend/__tests__/unit-tests/question.test.ts | 12 ++++++------ apps/frontend/package.json | 4 ++-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index 1563112b01..22257250c3 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -23,12 +23,12 @@ describe("chrome browser", () => { await driver.get('http://www.google.com'); await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); await driver.wait(until.titleIs('webdriver - Google Search'), 1000); - }); + }, 10000); it("does another google search", async () => { await driver.get('http://www.google.com'); await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); await driver.wait(until.titleIs('webdriver - Google Search'), 1000); - }); + }, 10000); }); describe("browser-test", () => { @@ -48,8 +48,9 @@ describe("chrome browser", () => { const slogan1 = await driver.findElement(By.xpath("/html/body/div[1]/main/div/div[1]/div[2]/span[1]")).then(ele => ele.getText()) const slogan2 = await driver.findElement(By.xpath("/html/body/div[1]/main/div/div[1]/div[2]/span[2]")).then(ele => ele.getText()) - expect(slogan1 + slogan2).toBe("A better way to prepare for coding interviews withpeers"); - }); + expect(slogan1).toBe("A better way to prepare for coding interviews with"); + expect(slogan2).toBe("peers"); + }, 10000); }) }) diff --git a/apps/frontend/__tests__/unit-tests/question.test.ts b/apps/frontend/__tests__/unit-tests/question.test.ts index 417b4cc7aa..66e22635e3 100644 --- a/apps/frontend/__tests__/unit-tests/question.test.ts +++ b/apps/frontend/__tests__/unit-tests/question.test.ts @@ -126,7 +126,7 @@ describe("GetQuestions", () => { }); - it("gets all questions on the 2nd page with (2) call", async () => { + it("formats (page=2) params correctly", async () => { const res = await GetQuestions(2) @@ -138,7 +138,7 @@ describe("GetQuestions", () => { }]]) }); - it("gets all questions on the 2nd page with (limit=3) call", async () => { + it("formats (limit=3) params correctly", async () => { await GetQuestions(undefined, 3) @@ -150,7 +150,7 @@ describe("GetQuestions", () => { }]]) }); - it("gets all questions on the 2nd page with (limit=3) call", async () => { + it("formats (difficulty asc) params correctly", async () => { await GetQuestions(undefined, undefined, "difficulty asc") @@ -162,7 +162,7 @@ describe("GetQuestions", () => { }]]) }); - it("gets all questions on the 2nd page with (limit=3) call", async () => { + it("formats ([\"easy\", \"hard\"]) params correctly", async () => { await GetQuestions(undefined, undefined, undefined, ["easy", "hard"]) @@ -174,7 +174,7 @@ describe("GetQuestions", () => { }]]) }); - it("formats urls for categories", async () => { + it("formats cat params correctly", async () => { await GetQuestions(undefined, undefined, undefined, undefined, ["CatA", "CatB"]) @@ -189,7 +189,7 @@ describe("GetQuestions", () => { ]]) }); - it("formats url for title", async () => { + it("formats title params correctly", async () => { await GetQuestions(undefined, undefined, undefined, undefined, undefined, "The Title Name") diff --git a/apps/frontend/package.json b/apps/frontend/package.json index bab7a93c21..72690ce9c6 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -8,8 +8,8 @@ "start": "next start", "lint": "next lint", "test": "jest", - "unit-test": "jest __tests__/unit-tests", - "browser-test": "jest __tests__/browser-tests" + "unit-test": "jest --verbose __tests__/unit-tests", + "browser-test": "jest --verbose __tests__/browser-tests" }, "dependencies": { "@ant-design/icons": "^5.5.1", From 96636881de0af527908c2a9b97694940c74ad806 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Tue, 12 Nov 2024 14:19:17 +0800 Subject: [PATCH 207/258] asd add browsers --- .github/workflows/test.yml | 8 +++++ .../__tests__/browser-tests/browser.test.ts | 33 ++++++++++++++----- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8d18e13b1c..205f1b2af5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -237,6 +237,14 @@ jobs: uses: nanasess/setup-chromedriver@v2 with: chromedriver-version: '130.0.6723.116' + + - name: Install Edge + uses: browser-actions/setup-edge@v1 + with: + edge-version: stable + + - name: Install Geckodriver + uses: browser-actions/setup-geckodriver@latest - name: Run Browser Test run: | diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index 22257250c3..a3b44024c9 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -1,14 +1,30 @@ -import { Actions, Browser, Builder, By, Key, until, WebDriver } from "selenium-webdriver" +import { Actions, Browser, Builder, By, Capabilities, Key, until, WebDriver } from "selenium-webdriver" + +import {Options as ChromeOptions} from "selenium-webdriver/chrome" +import {Options as EdgeOptions} from "selenium-webdriver/edge" +import {Options as FirefoxOptions} from "selenium-webdriver/firefox" -import Chrome from "selenium-webdriver/chrome" const URL = 'http://localhost:3000/'; const ETERNAL_JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjk5OTk5OTk5OTk5fQ.Z4_FVGQ5lIcouP3m4YLMr6pGMF17IJFfo2yOTiN58DY" -describe("chrome browser", () => { - const options = new Chrome.Options() - .addArguments("--headless=new") as Chrome.Options; // uncomment locally to see the steps in action - const builder = new Builder().forBrowser(Browser.CHROME).setChromeOptions(options); +const CHROME_OPTIONS = new ChromeOptions() + .addArguments("--headless=new") as ChromeOptions; // uncomment locally to see the steps in action +const EDGE_OPTIONS = new EdgeOptions() + .addArguments("--headless=new") as EdgeOptions; +const FIREFOX_OPTIONS = new FirefoxOptions() + .addArguments("--headless") as FirefoxOptions; + +const builder = new Builder() + .setChromeOptions(CHROME_OPTIONS) + .setEdgeOptions(EDGE_OPTIONS) + .setFirefoxOptions(FIREFOX_OPTIONS) + +describe.each([Browser.CHROME, Browser.EDGE, Browser.FIREFOX])("%s driver test", (browser) => { let driver: WebDriver; + beforeAll(() => { + const cap = new Capabilities().setBrowserName(browser) + builder.withCapabilities(cap); + }) beforeEach(async () => { driver = await builder.build(); @@ -18,13 +34,14 @@ describe("chrome browser", () => { await driver.quit(); }) - describe("chrome webdriver installed correctly", () => { + describe.skip("webdriver installed correctly", () => { it("does google search", async () => { await driver.get('http://www.google.com'); await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); await driver.wait(until.titleIs('webdriver - Google Search'), 1000); }, 10000); - it("does another google search", async () => { + + it.skip("does another google search", async () => { await driver.get('http://www.google.com'); await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); await driver.wait(until.titleIs('webdriver - Google Search'), 1000); From 3a975ffd4232f436bc9c817df17cd7312086e66f Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Tue, 12 Nov 2024 14:37:56 +0800 Subject: [PATCH 208/258] asd --- .github/workflows/test.yml | 37 +++++++++++++++++++ .../__tests__/browser-tests/browser.test.ts | 5 ++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 205f1b2af5..4a63c918a2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -85,6 +85,43 @@ jobs: cd ./apps/frontend pnpm unit-test + + test-webdriver-working: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.1.4 + + - name: Install dependencies + run: | + cd ./apps/frontend + pnpm i + + - name: Install Chrome WebDriver + uses: nanasess/setup-chromedriver@v2 + with: + chromedriver-version: '130.0.6723.116' + + - name: Install Edge + uses: browser-actions/setup-edge@v1 + with: + edge-version: stable + + - name: Install Geckodriver + uses: browser-actions/setup-geckodriver@latest + + + - name: Run Browser Test + run: | + cd ./apps/frontend + pnpm browser-test -- -t "webdriver installed correctly" + test-docker-compose: runs-on: ubuntu-latest diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index a3b44024c9..bc19217b25 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -10,8 +10,11 @@ const ETERNAL_JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3OD const CHROME_OPTIONS = new ChromeOptions() .addArguments("--headless=new") as ChromeOptions; // uncomment locally to see the steps in action const EDGE_OPTIONS = new EdgeOptions() + .setBinaryPath("/opt/hostedtoolcache/msedge/stable/x64/msedge") .addArguments("--headless=new") as EdgeOptions; + const FIREFOX_OPTIONS = new FirefoxOptions() + .setBinary("/opt/hostedtoolcache/geckodriver/0.35.0/x64/geckodriver") .addArguments("--headless") as FirefoxOptions; const builder = new Builder() @@ -34,7 +37,7 @@ describe.each([Browser.CHROME, Browser.EDGE, Browser.FIREFOX])("%s driver test", await driver.quit(); }) - describe.skip("webdriver installed correctly", () => { + describe("webdriver installed correctly", () => { it("does google search", async () => { await driver.get('http://www.google.com'); await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); From e92e18608afc9a882da7568bfffbe0b96cf01146 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Tue, 12 Nov 2024 14:47:29 +0800 Subject: [PATCH 209/258] asd --- .github/workflows/test.yml | 321 ++++++++++++++++++------------------- 1 file changed, 160 insertions(+), 161 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4a63c918a2..1be8c49c8c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -85,7 +85,6 @@ jobs: cd ./apps/frontend pnpm unit-test - test-webdriver-working: runs-on: ubuntu-latest @@ -120,170 +119,170 @@ jobs: - name: Run Browser Test run: | cd ./apps/frontend - pnpm browser-test -- -t "webdriver installed correctly" - - test-docker-compose: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Docker Compose - run: | - sudo apt-get update - sudo apt-get install -y docker-compose - - - name: Create Environment Files - env: - QUESTION_SERVICE_URL: ${{ vars.QUESTION_SERVICE_URL }} - USER_SERVICE_URL: ${{ vars.USER_SERVICE_URL }} - MATCHING_SERVICE_URL: ${{ vars.MATCHING_SERVICE_URL }} - HISTORY_SERVICE_URL: ${{ vars.HISTORY_SERVICE_URL }} - SIGNALLING_SERVICE_URL: ${{ vars.SIGNALLING_SERVICE_URL }} - EXECUTION_SERVICE_URL: ${{ vars.EXECUTION_SERVICE_URL }} - JWT_SECRET: ${{ secrets.JWT_SECRET }} - QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} - HISTORY_FIREBASE_CREDENTIAL_PATH: ${{ vars.HISTORY_SERVICE_FIREBASE_CREDENTIAL_PATH }} - EXECUTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.EXECUTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} - DB_CLOUD_URI: ${{ secrets.USER_SERVICE_DB_CLOUD_URI }} - USER_SERVICE_PORT: ${{ vars.USER_SERVICE_PORT }} - MATCHING_SERVICE_PORT: ${{ vars.MATCHING_SERVICE_PORT }} - HISTORY_SERVICE_PORT: ${{ vars.HISTORY_SERVICE_PORT }} - SIGNALLING_SERVICE_PORT: ${{ vars.SIGNALLING_SERVICE_PORT }} - EXECUTION_SERVICE_PORT: ${{ vars.EXECUTION_SERVICE_PORT }} - MATCHING_SERVICE_TIMEOUT: ${{ vars.MATCHING_SERVICE_TIMEOUT }} - REDIS_URL: ${{ vars.REDIS_URL }} - QUESTION_SERVICE_GRPC_URL: ${{ vars.QUESTION_SERVICE_GPRC_URL }} - run: | - cd ./apps/frontend - echo "NEXT_PUBLIC_QUESTION_SERVICE_URL=$QUESTION_SERVICE_URL" >> .env - echo "NEXT_PUBLIC_USER_SERVICE_URL=$USER_SERVICE_URL" >> .env - echo "NEXT_PUBLIC_MATCHING_SERVICE_URL=$MATCHING_SERVICE_URL" >> .env - echo "NEXT_PUBLIC_HISTORY_SERVICE_URL=$HISTORY_SERVICE_URL" >> .env - echo "NEXT_PUBLIC_SIGNALLING_SERVICE_URL=$SIGNALLING_SERVICE_URL" >> .env - echo "NEXT_PUBLIC_EXECUTION_SERVICE_URL=EXECUTION_SERVICE_URL" >> .env - - cd ../question-service - echo "FIREBASE_CREDENTIAL_PATH=$QUESTION_FIREBASE_CREDENTIAL_PATH" >> .env - echo "JWT_SECRET=$JWT_SECRET" >> .env - echo "EXECUTION_SERVICE_URL=$EXECUTION_SERVICE_URL" >> .env - - cd ../user-service - echo "DB_CLOUD_URI=$DB_CLOUD_URI" >> .env - echo "PORT=$USER_SERVICE_PORT" >> .env - echo "JWT_SECRET=$JWT_SECRET" >> .env - - cd ../matching-service - echo "PORT=$MATCHING_SERVICE_PORT" >> .env - echo "MATCH_TIMEOUT=$MATCHING_SERVICE_TIMEOUT" >> .env - echo "JWT_SECRET=$JWT_SECRET" >> .env - echo "REDIS_URL=$REDIS_URL" >> .env - echo "QUESTION_SERVICE_GRPC_URL=$QUESTION_SERVICE_GRPC_URL" >> .env - - cd ../history-service - echo "FIREBASE_CREDENTIAL_PATH=$HISTORY_FIREBASE_CREDENTIAL_PATH" >> .env - echo "PORT=$HISTORY_SERVICE_PORT" >> .env + pnpm browser-test -t "webdriver installed correctly" + + # test-docker-compose: + # runs-on: ubuntu-latest + + # steps: + # - name: Checkout code + # uses: actions/checkout@v4 + + # - name: Set up Docker Compose + # run: | + # sudo apt-get update + # sudo apt-get install -y docker-compose + + # - name: Create Environment Files + # env: + # QUESTION_SERVICE_URL: ${{ vars.QUESTION_SERVICE_URL }} + # USER_SERVICE_URL: ${{ vars.USER_SERVICE_URL }} + # MATCHING_SERVICE_URL: ${{ vars.MATCHING_SERVICE_URL }} + # HISTORY_SERVICE_URL: ${{ vars.HISTORY_SERVICE_URL }} + # SIGNALLING_SERVICE_URL: ${{ vars.SIGNALLING_SERVICE_URL }} + # EXECUTION_SERVICE_URL: ${{ vars.EXECUTION_SERVICE_URL }} + # JWT_SECRET: ${{ secrets.JWT_SECRET }} + # QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} + # HISTORY_FIREBASE_CREDENTIAL_PATH: ${{ vars.HISTORY_SERVICE_FIREBASE_CREDENTIAL_PATH }} + # EXECUTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.EXECUTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} + # DB_CLOUD_URI: ${{ secrets.USER_SERVICE_DB_CLOUD_URI }} + # USER_SERVICE_PORT: ${{ vars.USER_SERVICE_PORT }} + # MATCHING_SERVICE_PORT: ${{ vars.MATCHING_SERVICE_PORT }} + # HISTORY_SERVICE_PORT: ${{ vars.HISTORY_SERVICE_PORT }} + # SIGNALLING_SERVICE_PORT: ${{ vars.SIGNALLING_SERVICE_PORT }} + # EXECUTION_SERVICE_PORT: ${{ vars.EXECUTION_SERVICE_PORT }} + # MATCHING_SERVICE_TIMEOUT: ${{ vars.MATCHING_SERVICE_TIMEOUT }} + # REDIS_URL: ${{ vars.REDIS_URL }} + # QUESTION_SERVICE_GRPC_URL: ${{ vars.QUESTION_SERVICE_GPRC_URL }} + # run: | + # cd ./apps/frontend + # echo "NEXT_PUBLIC_QUESTION_SERVICE_URL=$QUESTION_SERVICE_URL" >> .env + # echo "NEXT_PUBLIC_USER_SERVICE_URL=$USER_SERVICE_URL" >> .env + # echo "NEXT_PUBLIC_MATCHING_SERVICE_URL=$MATCHING_SERVICE_URL" >> .env + # echo "NEXT_PUBLIC_HISTORY_SERVICE_URL=$HISTORY_SERVICE_URL" >> .env + # echo "NEXT_PUBLIC_SIGNALLING_SERVICE_URL=$SIGNALLING_SERVICE_URL" >> .env + # echo "NEXT_PUBLIC_EXECUTION_SERVICE_URL=EXECUTION_SERVICE_URL" >> .env + + # cd ../question-service + # echo "FIREBASE_CREDENTIAL_PATH=$QUESTION_FIREBASE_CREDENTIAL_PATH" >> .env + # echo "JWT_SECRET=$JWT_SECRET" >> .env + # echo "EXECUTION_SERVICE_URL=$EXECUTION_SERVICE_URL" >> .env + + # cd ../user-service + # echo "DB_CLOUD_URI=$DB_CLOUD_URI" >> .env + # echo "PORT=$USER_SERVICE_PORT" >> .env + # echo "JWT_SECRET=$JWT_SECRET" >> .env + + # cd ../matching-service + # echo "PORT=$MATCHING_SERVICE_PORT" >> .env + # echo "MATCH_TIMEOUT=$MATCHING_SERVICE_TIMEOUT" >> .env + # echo "JWT_SECRET=$JWT_SECRET" >> .env + # echo "REDIS_URL=$REDIS_URL" >> .env + # echo "QUESTION_SERVICE_GRPC_URL=$QUESTION_SERVICE_GRPC_URL" >> .env + + # cd ../history-service + # echo "FIREBASE_CREDENTIAL_PATH=$HISTORY_FIREBASE_CREDENTIAL_PATH" >> .env + # echo "PORT=$HISTORY_SERVICE_PORT" >> .env - cd ../execution-service - echo "FIREBASE_CREDENTIAL_PATH=$EXECUTION_FIREBASE_CREDENTIAL_PATH" >> .env - echo "PORT=$EXECUTION_SERVICE_PORT" >> .env - echo "HISTORY_SERVICE_URL=$HISTORY_SERVICE_URL" >> .env - - cd ../signalling-service - echo "PORT=$SIGNALLING_SERVICE_PORT" >> .env - - - name: Create Database Credential Files - env: - QUESTION_FIREBASE_JSON: ${{ secrets.QUESTION_SERVICE_FIREBASE_CREDENTIAL }} - QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} - HISTORY_FIREBASE_JSON: ${{ secrets.HISTORY_SERVICE_FIREBASE_CREDENTIAL }} - HISTORY_FIREBASE_CREDENTIAL_PATH: ${{ vars.HISTORY_SERVICE_FIREBASE_CREDENTIAL_PATH }} - EXECUTION_FIREBASE_JSON: ${{ secrets.EXECUTION_SERVICE_FIREBASE_CREDENTIAL }} - EXECUTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.EXECUTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} - run: | - cd ./apps/question-service - echo "$QUESTION_FIREBASE_JSON" > "./$QUESTION_FIREBASE_CREDENTIAL_PATH" - - cd ../history-service - echo "$HISTORY_FIREBASE_JSON" > "./$HISTORY_FIREBASE_CREDENTIAL_PATH" + # cd ../execution-service + # echo "FIREBASE_CREDENTIAL_PATH=$EXECUTION_FIREBASE_CREDENTIAL_PATH" >> .env + # echo "PORT=$EXECUTION_SERVICE_PORT" >> .env + # echo "HISTORY_SERVICE_URL=$HISTORY_SERVICE_URL" >> .env + + # cd ../signalling-service + # echo "PORT=$SIGNALLING_SERVICE_PORT" >> .env + + # - name: Create Database Credential Files + # env: + # QUESTION_FIREBASE_JSON: ${{ secrets.QUESTION_SERVICE_FIREBASE_CREDENTIAL }} + # QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} + # HISTORY_FIREBASE_JSON: ${{ secrets.HISTORY_SERVICE_FIREBASE_CREDENTIAL }} + # HISTORY_FIREBASE_CREDENTIAL_PATH: ${{ vars.HISTORY_SERVICE_FIREBASE_CREDENTIAL_PATH }} + # EXECUTION_FIREBASE_JSON: ${{ secrets.EXECUTION_SERVICE_FIREBASE_CREDENTIAL }} + # EXECUTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.EXECUTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} + # run: | + # cd ./apps/question-service + # echo "$QUESTION_FIREBASE_JSON" > "./$QUESTION_FIREBASE_CREDENTIAL_PATH" + + # cd ../history-service + # echo "$HISTORY_FIREBASE_JSON" > "./$HISTORY_FIREBASE_CREDENTIAL_PATH" - cd ../execution-service - echo "$EXECUTION_FIREBASE_JSON" > "./$EXECUTION_FIREBASE_CREDENTIAL_PATH" - - - name: Build and Run Services - run: | - cd ./apps - docker-compose up --build -d - - - name: Wait for services to be ready - run: sleep 30 - - - name: Install websocat - run: | - sudo wget -qO /usr/local/bin/websocat https://github.com/vi/websocat/releases/latest/download/websocat.x86_64-unknown-linux-musl - sudo chmod a+x /usr/local/bin/websocat - websocat --version - - - name: Run Tests - env: - FRONTEND_URL: ${{ vars.FRONTEND_URL }} - USER_SERVICE_URL: ${{ vars.USER_SERVICE_URL }} - QUESTION_SERVICE_URL: ${{ vars.QUESTION_SERVICE_URL }} - MATCHING_SERVICE_URL: ${{ vars.MATCHING_SERVICE_URL }} - HISTORY_SERVICE_URL: ${{ vars.HISTORY_SERVICE_URL }} - SIGNALLING_SERVICE_URL: ${{ vars.SIGNALLING_SERVICE_URL }} - EXECUTION_SERVICE_URL: ${{ vars.EXECUTION_SERVICE_URL }} - run: | - echo "Testing Question Service..." - curl -sSL -o /dev/null $QUESTION_SERVICE_URL && echo "Question Service is up" - echo "Testing User Service..." - curl -fsSL -o /dev/null $USER_SERVICE_URL && echo "User Service is up" - echo "Testing Frontend..." - curl -fsSL -o /dev/null $FRONTEND_URL && echo "Frontend is up" - echo "Testing History Service..." - curl -fsSL -o /dev/null $HISTORY_SERVICE_URL && echo "History Service is up" - echo "Testing Execution Service..." - curl -fsSL -o /dev/null $EXECUTION_SERVICE_URL && echo "Execution Service is up" - echo "Testing Matching Service..." - if ! (echo "Hello" | websocat $MATCHING_SERVICE_URL); then - echo "WebSocket for Matching Service is not live" - else - echo "WebSocket for Matching Service is live" - fi - # Add in test for matching service in the future - echo "Testing Signalling Service..." - if ! (echo "Hello" | websocat $SIGNALLING_SERVICE_URL); then - echo "WebSocket for Signalling Service is not live" - else - echo "WebSocket for Signalling Service is live" - fi - # We can add more tests here + # cd ../execution-service + # echo "$EXECUTION_FIREBASE_JSON" > "./$EXECUTION_FIREBASE_CREDENTIAL_PATH" + + # - name: Build and Run Services + # run: | + # cd ./apps + # docker-compose up --build -d + + # - name: Wait for services to be ready + # run: sleep 30 + + # - name: Install websocat + # run: | + # sudo wget -qO /usr/local/bin/websocat https://github.com/vi/websocat/releases/latest/download/websocat.x86_64-unknown-linux-musl + # sudo chmod a+x /usr/local/bin/websocat + # websocat --version + + # - name: Run Tests + # env: + # FRONTEND_URL: ${{ vars.FRONTEND_URL }} + # USER_SERVICE_URL: ${{ vars.USER_SERVICE_URL }} + # QUESTION_SERVICE_URL: ${{ vars.QUESTION_SERVICE_URL }} + # MATCHING_SERVICE_URL: ${{ vars.MATCHING_SERVICE_URL }} + # HISTORY_SERVICE_URL: ${{ vars.HISTORY_SERVICE_URL }} + # SIGNALLING_SERVICE_URL: ${{ vars.SIGNALLING_SERVICE_URL }} + # EXECUTION_SERVICE_URL: ${{ vars.EXECUTION_SERVICE_URL }} + # run: | + # echo "Testing Question Service..." + # curl -sSL -o /dev/null $QUESTION_SERVICE_URL && echo "Question Service is up" + # echo "Testing User Service..." + # curl -fsSL -o /dev/null $USER_SERVICE_URL && echo "User Service is up" + # echo "Testing Frontend..." + # curl -fsSL -o /dev/null $FRONTEND_URL && echo "Frontend is up" + # echo "Testing History Service..." + # curl -fsSL -o /dev/null $HISTORY_SERVICE_URL && echo "History Service is up" + # echo "Testing Execution Service..." + # curl -fsSL -o /dev/null $EXECUTION_SERVICE_URL && echo "Execution Service is up" + # echo "Testing Matching Service..." + # if ! (echo "Hello" | websocat $MATCHING_SERVICE_URL); then + # echo "WebSocket for Matching Service is not live" + # else + # echo "WebSocket for Matching Service is live" + # fi + # # Add in test for matching service in the future + # echo "Testing Signalling Service..." + # if ! (echo "Hello" | websocat $SIGNALLING_SERVICE_URL); then + # echo "WebSocket for Signalling Service is not live" + # else + # echo "WebSocket for Signalling Service is live" + # fi + # # We can add more tests here - - name: Install pnpm - uses: pnpm/action-setup@v4 - with: - version: 9.1.4 - - - name: Install dependencies - run: | - cd ./apps/frontend - pnpm i + # - name: Install pnpm + # uses: pnpm/action-setup@v4 + # with: + # version: 9.1.4 + + # - name: Install dependencies + # run: | + # cd ./apps/frontend + # pnpm i - - name: Install Chrome WebDriver - uses: nanasess/setup-chromedriver@v2 - with: - chromedriver-version: '130.0.6723.116' + # - name: Install Chrome WebDriver + # uses: nanasess/setup-chromedriver@v2 + # with: + # chromedriver-version: '130.0.6723.116' - - name: Install Edge - uses: browser-actions/setup-edge@v1 - with: - edge-version: stable + # - name: Install Edge + # uses: browser-actions/setup-edge@v1 + # with: + # edge-version: stable - - name: Install Geckodriver - uses: browser-actions/setup-geckodriver@latest + # - name: Install Geckodriver + # uses: browser-actions/setup-geckodriver@latest - - name: Run Browser Test - run: | - cd ./apps/frontend - pnpm browser-test + # - name: Run Browser Test + # run: | + # cd ./apps/frontend + # pnpm browser-test From e400a7176baaa4e272963760be97de84c9bf943a Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Tue, 12 Nov 2024 14:53:23 +0800 Subject: [PATCH 210/258] asd --- .github/workflows/test.yml | 165 ------------------------------------- 1 file changed, 165 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1be8c49c8c..530eb00e7f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -121,168 +121,3 @@ jobs: cd ./apps/frontend pnpm browser-test -t "webdriver installed correctly" - # test-docker-compose: - # runs-on: ubuntu-latest - - # steps: - # - name: Checkout code - # uses: actions/checkout@v4 - - # - name: Set up Docker Compose - # run: | - # sudo apt-get update - # sudo apt-get install -y docker-compose - - # - name: Create Environment Files - # env: - # QUESTION_SERVICE_URL: ${{ vars.QUESTION_SERVICE_URL }} - # USER_SERVICE_URL: ${{ vars.USER_SERVICE_URL }} - # MATCHING_SERVICE_URL: ${{ vars.MATCHING_SERVICE_URL }} - # HISTORY_SERVICE_URL: ${{ vars.HISTORY_SERVICE_URL }} - # SIGNALLING_SERVICE_URL: ${{ vars.SIGNALLING_SERVICE_URL }} - # EXECUTION_SERVICE_URL: ${{ vars.EXECUTION_SERVICE_URL }} - # JWT_SECRET: ${{ secrets.JWT_SECRET }} - # QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} - # HISTORY_FIREBASE_CREDENTIAL_PATH: ${{ vars.HISTORY_SERVICE_FIREBASE_CREDENTIAL_PATH }} - # EXECUTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.EXECUTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} - # DB_CLOUD_URI: ${{ secrets.USER_SERVICE_DB_CLOUD_URI }} - # USER_SERVICE_PORT: ${{ vars.USER_SERVICE_PORT }} - # MATCHING_SERVICE_PORT: ${{ vars.MATCHING_SERVICE_PORT }} - # HISTORY_SERVICE_PORT: ${{ vars.HISTORY_SERVICE_PORT }} - # SIGNALLING_SERVICE_PORT: ${{ vars.SIGNALLING_SERVICE_PORT }} - # EXECUTION_SERVICE_PORT: ${{ vars.EXECUTION_SERVICE_PORT }} - # MATCHING_SERVICE_TIMEOUT: ${{ vars.MATCHING_SERVICE_TIMEOUT }} - # REDIS_URL: ${{ vars.REDIS_URL }} - # QUESTION_SERVICE_GRPC_URL: ${{ vars.QUESTION_SERVICE_GPRC_URL }} - # run: | - # cd ./apps/frontend - # echo "NEXT_PUBLIC_QUESTION_SERVICE_URL=$QUESTION_SERVICE_URL" >> .env - # echo "NEXT_PUBLIC_USER_SERVICE_URL=$USER_SERVICE_URL" >> .env - # echo "NEXT_PUBLIC_MATCHING_SERVICE_URL=$MATCHING_SERVICE_URL" >> .env - # echo "NEXT_PUBLIC_HISTORY_SERVICE_URL=$HISTORY_SERVICE_URL" >> .env - # echo "NEXT_PUBLIC_SIGNALLING_SERVICE_URL=$SIGNALLING_SERVICE_URL" >> .env - # echo "NEXT_PUBLIC_EXECUTION_SERVICE_URL=EXECUTION_SERVICE_URL" >> .env - - # cd ../question-service - # echo "FIREBASE_CREDENTIAL_PATH=$QUESTION_FIREBASE_CREDENTIAL_PATH" >> .env - # echo "JWT_SECRET=$JWT_SECRET" >> .env - # echo "EXECUTION_SERVICE_URL=$EXECUTION_SERVICE_URL" >> .env - - # cd ../user-service - # echo "DB_CLOUD_URI=$DB_CLOUD_URI" >> .env - # echo "PORT=$USER_SERVICE_PORT" >> .env - # echo "JWT_SECRET=$JWT_SECRET" >> .env - - # cd ../matching-service - # echo "PORT=$MATCHING_SERVICE_PORT" >> .env - # echo "MATCH_TIMEOUT=$MATCHING_SERVICE_TIMEOUT" >> .env - # echo "JWT_SECRET=$JWT_SECRET" >> .env - # echo "REDIS_URL=$REDIS_URL" >> .env - # echo "QUESTION_SERVICE_GRPC_URL=$QUESTION_SERVICE_GRPC_URL" >> .env - - # cd ../history-service - # echo "FIREBASE_CREDENTIAL_PATH=$HISTORY_FIREBASE_CREDENTIAL_PATH" >> .env - # echo "PORT=$HISTORY_SERVICE_PORT" >> .env - - # cd ../execution-service - # echo "FIREBASE_CREDENTIAL_PATH=$EXECUTION_FIREBASE_CREDENTIAL_PATH" >> .env - # echo "PORT=$EXECUTION_SERVICE_PORT" >> .env - # echo "HISTORY_SERVICE_URL=$HISTORY_SERVICE_URL" >> .env - - # cd ../signalling-service - # echo "PORT=$SIGNALLING_SERVICE_PORT" >> .env - - # - name: Create Database Credential Files - # env: - # QUESTION_FIREBASE_JSON: ${{ secrets.QUESTION_SERVICE_FIREBASE_CREDENTIAL }} - # QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} - # HISTORY_FIREBASE_JSON: ${{ secrets.HISTORY_SERVICE_FIREBASE_CREDENTIAL }} - # HISTORY_FIREBASE_CREDENTIAL_PATH: ${{ vars.HISTORY_SERVICE_FIREBASE_CREDENTIAL_PATH }} - # EXECUTION_FIREBASE_JSON: ${{ secrets.EXECUTION_SERVICE_FIREBASE_CREDENTIAL }} - # EXECUTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.EXECUTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} - # run: | - # cd ./apps/question-service - # echo "$QUESTION_FIREBASE_JSON" > "./$QUESTION_FIREBASE_CREDENTIAL_PATH" - - # cd ../history-service - # echo "$HISTORY_FIREBASE_JSON" > "./$HISTORY_FIREBASE_CREDENTIAL_PATH" - - # cd ../execution-service - # echo "$EXECUTION_FIREBASE_JSON" > "./$EXECUTION_FIREBASE_CREDENTIAL_PATH" - - # - name: Build and Run Services - # run: | - # cd ./apps - # docker-compose up --build -d - - # - name: Wait for services to be ready - # run: sleep 30 - - # - name: Install websocat - # run: | - # sudo wget -qO /usr/local/bin/websocat https://github.com/vi/websocat/releases/latest/download/websocat.x86_64-unknown-linux-musl - # sudo chmod a+x /usr/local/bin/websocat - # websocat --version - - # - name: Run Tests - # env: - # FRONTEND_URL: ${{ vars.FRONTEND_URL }} - # USER_SERVICE_URL: ${{ vars.USER_SERVICE_URL }} - # QUESTION_SERVICE_URL: ${{ vars.QUESTION_SERVICE_URL }} - # MATCHING_SERVICE_URL: ${{ vars.MATCHING_SERVICE_URL }} - # HISTORY_SERVICE_URL: ${{ vars.HISTORY_SERVICE_URL }} - # SIGNALLING_SERVICE_URL: ${{ vars.SIGNALLING_SERVICE_URL }} - # EXECUTION_SERVICE_URL: ${{ vars.EXECUTION_SERVICE_URL }} - # run: | - # echo "Testing Question Service..." - # curl -sSL -o /dev/null $QUESTION_SERVICE_URL && echo "Question Service is up" - # echo "Testing User Service..." - # curl -fsSL -o /dev/null $USER_SERVICE_URL && echo "User Service is up" - # echo "Testing Frontend..." - # curl -fsSL -o /dev/null $FRONTEND_URL && echo "Frontend is up" - # echo "Testing History Service..." - # curl -fsSL -o /dev/null $HISTORY_SERVICE_URL && echo "History Service is up" - # echo "Testing Execution Service..." - # curl -fsSL -o /dev/null $EXECUTION_SERVICE_URL && echo "Execution Service is up" - # echo "Testing Matching Service..." - # if ! (echo "Hello" | websocat $MATCHING_SERVICE_URL); then - # echo "WebSocket for Matching Service is not live" - # else - # echo "WebSocket for Matching Service is live" - # fi - # # Add in test for matching service in the future - # echo "Testing Signalling Service..." - # if ! (echo "Hello" | websocat $SIGNALLING_SERVICE_URL); then - # echo "WebSocket for Signalling Service is not live" - # else - # echo "WebSocket for Signalling Service is live" - # fi - # # We can add more tests here - - # - name: Install pnpm - # uses: pnpm/action-setup@v4 - # with: - # version: 9.1.4 - - # - name: Install dependencies - # run: | - # cd ./apps/frontend - # pnpm i - - # - name: Install Chrome WebDriver - # uses: nanasess/setup-chromedriver@v2 - # with: - # chromedriver-version: '130.0.6723.116' - - # - name: Install Edge - # uses: browser-actions/setup-edge@v1 - # with: - # edge-version: stable - - # - name: Install Geckodriver - # uses: browser-actions/setup-geckodriver@latest - - # - name: Run Browser Test - # run: | - # cd ./apps/frontend - # pnpm browser-test From 4c405f4abeea7037ee8e00793d304fd0cc852b04 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Tue, 12 Nov 2024 14:57:22 +0800 Subject: [PATCH 211/258] asd --- apps/frontend/__tests__/browser-tests/browser.test.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index bc19217b25..51b36aec2d 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -27,9 +27,11 @@ describe.each([Browser.CHROME, Browser.EDGE, Browser.FIREFOX])("%s driver test", beforeAll(() => { const cap = new Capabilities().setBrowserName(browser) builder.withCapabilities(cap); + console.log("got here"); }) beforeEach(async () => { + console.log("got here"); driver = await builder.build(); }) @@ -39,6 +41,7 @@ describe.each([Browser.CHROME, Browser.EDGE, Browser.FIREFOX])("%s driver test", describe("webdriver installed correctly", () => { it("does google search", async () => { + console.log("got here"); await driver.get('http://www.google.com'); await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); await driver.wait(until.titleIs('webdriver - Google Search'), 1000); @@ -51,7 +54,7 @@ describe.each([Browser.CHROME, Browser.EDGE, Browser.FIREFOX])("%s driver test", }, 10000); }); - describe("browser-test", () => { + describe.skip("browser-test", () => { it("accesses and login to peerprep", async () => { await driver.get(URL); await driver.wait(until.urlIs(`${URL}login`)); From 64e2651e87df7f34a684b2fadba6b5f2b8a1a0b0 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Tue, 12 Nov 2024 15:00:01 +0800 Subject: [PATCH 212/258] asd --- apps/frontend/__tests__/browser-tests/browser.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index 51b36aec2d..fe93068c29 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -27,11 +27,9 @@ describe.each([Browser.CHROME, Browser.EDGE, Browser.FIREFOX])("%s driver test", beforeAll(() => { const cap = new Capabilities().setBrowserName(browser) builder.withCapabilities(cap); - console.log("got here"); }) beforeEach(async () => { - console.log("got here"); driver = await builder.build(); }) @@ -41,10 +39,12 @@ describe.each([Browser.CHROME, Browser.EDGE, Browser.FIREFOX])("%s driver test", describe("webdriver installed correctly", () => { it("does google search", async () => { - console.log("got here"); + console.log("getting url"); await driver.get('http://www.google.com'); + console.log("got url"); await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); await driver.wait(until.titleIs('webdriver - Google Search'), 1000); + console.log("did search"); }, 10000); it.skip("does another google search", async () => { From 3657a9c493956ca91a3a6f40ecb624c0c1e7edf4 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Tue, 12 Nov 2024 15:05:03 +0800 Subject: [PATCH 213/258] asd --- apps/frontend/__tests__/browser-tests/browser.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index fe93068c29..8715fb7a10 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -30,7 +30,9 @@ describe.each([Browser.CHROME, Browser.EDGE, Browser.FIREFOX])("%s driver test", }) beforeEach(async () => { + console.log(browser + ": building..."); driver = await builder.build(); + console.log(browser + ": built"); }) afterEach(async () => { From 75559763d8bba422279f725250eab82bcd8e29e0 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Tue, 12 Nov 2024 15:07:33 +0800 Subject: [PATCH 214/258] asd --- apps/frontend/__tests__/browser-tests/browser.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index 8715fb7a10..32e108a755 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -14,7 +14,7 @@ const EDGE_OPTIONS = new EdgeOptions() .addArguments("--headless=new") as EdgeOptions; const FIREFOX_OPTIONS = new FirefoxOptions() - .setBinary("/opt/hostedtoolcache/geckodriver/0.35.0/x64/geckodriver") + .setBinary("/opt/hostedfasdjhflkajsdlkjfhalsdj") .addArguments("--headless") as FirefoxOptions; const builder = new Builder() From d3eb518711444100d107b53dff555735a18a5cc4 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Tue, 12 Nov 2024 15:21:42 +0800 Subject: [PATCH 215/258] asd --- apps/frontend/__tests__/browser-tests/browser.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index 32e108a755..de5af9335a 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -14,7 +14,7 @@ const EDGE_OPTIONS = new EdgeOptions() .addArguments("--headless=new") as EdgeOptions; const FIREFOX_OPTIONS = new FirefoxOptions() - .setBinary("/opt/hostedfasdjhflkajsdlkjfhalsdj") + // .setBinary("/opt/hostedtoolcache/geckodriver/0.35.0/x64/geckodriver") .addArguments("--headless") as FirefoxOptions; const builder = new Builder() From e0c62de5608652a6ad501119c3e74cecbf23b1c8 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Tue, 12 Nov 2024 15:23:44 +0800 Subject: [PATCH 216/258] asd --- apps/frontend/__tests__/browser-tests/browser.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index de5af9335a..20b49ba1bd 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -10,11 +10,10 @@ const ETERNAL_JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3OD const CHROME_OPTIONS = new ChromeOptions() .addArguments("--headless=new") as ChromeOptions; // uncomment locally to see the steps in action const EDGE_OPTIONS = new EdgeOptions() - .setBinaryPath("/opt/hostedtoolcache/msedge/stable/x64/msedge") + .setBinaryPath("/opt/hostedtoolcache/msedge/stable/x64/msedge") // need to point to the correct path .addArguments("--headless=new") as EdgeOptions; const FIREFOX_OPTIONS = new FirefoxOptions() - // .setBinary("/opt/hostedtoolcache/geckodriver/0.35.0/x64/geckodriver") .addArguments("--headless") as FirefoxOptions; const builder = new Builder() From 266971d9fb642ca5dfc8692cb427720b8f2cb188 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Tue, 12 Nov 2024 15:26:30 +0800 Subject: [PATCH 217/258] Squashed commit of the following: commit e0c62de5608652a6ad501119c3e74cecbf23b1c8 Author: Ryan Chia Date: Tue Nov 12 15:23:44 2024 +0800 asd commit d3eb518711444100d107b53dff555735a18a5cc4 Author: Ryan Chia Date: Tue Nov 12 15:21:42 2024 +0800 asd commit 75559763d8bba422279f725250eab82bcd8e29e0 Author: Ryan Chia Date: Tue Nov 12 15:07:33 2024 +0800 asd commit 3657a9c493956ca91a3a6f40ecb624c0c1e7edf4 Author: Ryan Chia Date: Tue Nov 12 15:05:03 2024 +0800 asd commit 64e2651e87df7f34a684b2fadba6b5f2b8a1a0b0 Author: Ryan Chia Date: Tue Nov 12 15:00:01 2024 +0800 asd commit 4c405f4abeea7037ee8e00793d304fd0cc852b04 Author: Ryan Chia Date: Tue Nov 12 14:57:22 2024 +0800 asd commit c4ccd113e48496d0c397e6dc74b15fc4d004c56d Merge: e400a71 31a6bd1 Author: chiaryan <53717471+chiaryan@users.noreply.github.com> Date: Tue Nov 12 14:54:30 2024 +0800 Merge branch 'staging' into browser-tests commit e400a7176baaa4e272963760be97de84c9bf943a Author: Ryan Chia Date: Tue Nov 12 14:53:23 2024 +0800 asd commit e92e18608afc9a882da7568bfffbe0b96cf01146 Author: Ryan Chia Date: Tue Nov 12 14:47:29 2024 +0800 asd commit 3a975ffd4232f436bc9c817df17cd7312086e66f Author: Ryan Chia Date: Tue Nov 12 14:37:56 2024 +0800 asd commit 96636881de0af527908c2a9b97694940c74ad806 Author: Ryan Chia Date: Tue Nov 12 14:19:17 2024 +0800 asd add browsers commit b0b9fb5e1a4b6440e7e48015daa2cde648fae3c3 Merge: bf9f160 f86888b Author: Ryan Chia Date: Tue Nov 12 14:18:56 2024 +0800 Merge branch 'browser-compatibility-tests' into browser-tests commit 31a6bd1f882c4776b60029b1c1d1852f39201824 Merge: 7d931ee 3fd5752 Author: Benjamin Soh Zikang <97374822+bensohh@users.noreply.github.com> Date: Tue Nov 12 10:20:13 2024 +0800 Merge pull request #71 from CS3219-AY2425S1/titus/fix-local-storage-bug fix(frontend): :bug: mount component before accessing local storage commit 3fd5752dc19a7eca8be962f2dcaa2d13c7c61167 Merge: fdce97a 7d931ee Author: Benjamin Soh Zikang <97374822+bensohh@users.noreply.github.com> Date: Mon Nov 11 12:40:38 2024 +0800 Merge branch 'staging' into titus/fix-local-storage-bug commit 7d931eebf8b778a540b23fb49a524b30b3b8787e Merge: 439b410 d75215c Author: Benjamin Soh Zikang <97374822+bensohh@users.noreply.github.com> Date: Mon Nov 11 12:20:10 2024 +0800 Merge pull request #70 from CS3219-AY2425S1/titus/add-message-queue feat: add message queue commit bf9f160e2b80ac46cb3ac3baf817866f2dd7a6b3 Merge: 862051a 311be82 Author: Ryan Chia Date: Mon Nov 11 04:56:37 2024 +0800 Merge branch 'browser-compatibility-tests' into browser-tests commit 862051a6c53d75de3255c07deacaa6ed41156367 Author: Ryan Chia Date: Sun Nov 10 21:16:04 2024 +0800 asd commit f58f0351a0f83babfcc755ed4b4fc0909ed3cc09 Author: Ryan Chia Date: Sun Nov 10 21:13:59 2024 +0800 asd commit c78449683241496b903e01b143093f07c42c7e4c Author: Ryan Chia Date: Sun Nov 10 21:00:52 2024 +0800 asd commit 2f97a34c78b31c528b9d95cb247281236114f0a5 Author: Ryan Chia Date: Sun Nov 10 20:45:26 2024 +0800 asd commit cccfa548c8833c97d17d63f833bd73a1781825a4 Author: Ryan Chia Date: Sun Nov 10 20:44:24 2024 +0800 install pnpm commit 3570555db6221f063e29670e9110f5b2dda79bb4 Author: Ryan Chia Date: Sun Nov 10 20:32:56 2024 +0800 asd commit 45ebeb433a3ca542a98fd90e1ab31092d5bc49f2 Author: Ryan Chia Date: Sun Nov 10 20:32:04 2024 +0800 asd commit f1e7e40222a3f96cce21e6df3d4596c7f257ee71 Author: Ryan Chia Date: Sun Nov 10 20:08:35 2024 +0800 asd commit f5b521a2f4d26ec5207df63c2e128f4d05551801 Author: Ryan Chia Date: Sun Nov 10 20:08:03 2024 +0800 asd commit cc46721c40d11b60c05287e0facbc9c69a0399a7 Author: Ryan Chia Date: Sun Nov 10 13:47:37 2024 +0800 asd commit 9f1efaffdee71440839ca67e2ed7f39e1c0bec9a Author: Ryan Chia Date: Sun Nov 10 11:55:18 2024 +0800 asd s commit 67960833336c4c9818983f855ad11d72eb03b454 Author: Ryan Chia Date: Sun Nov 10 11:32:00 2024 +0800 asd commit 5b79d8be4f25309d4cfe05a61d5a406ddfccf0c6 Author: Ryan Chia Date: Sun Nov 10 11:28:49 2024 +0800 asd commit 240c839afa0bd5fc4690b9c2e8d0b74f45d69b59 Author: Ryan Chia Date: Sun Nov 10 11:27:52 2024 +0800 asd commit 8958cb6151a2423236ab8c5527ddc464b5185079 Author: Ryan Chia Date: Sun Nov 10 11:23:29 2024 +0800 asd commit ab4cc476f7ba56be6b9e0ef2106133a6b835ac17 Author: Ryan Chia Date: Sun Nov 10 11:22:05 2024 +0800 try selenium test commit 9656decd3259bcc36511e47b5e4800571c3c56bb Merge: 439b410 324463e Author: Ryan Chia Date: Sat Nov 9 16:14:56 2024 +0800 Merge branch 'commit-signalling-.dockerignore' into browser-tests commit fdce97ae834ba27204624fa648695b31175c4645 Author: tituschewxj Date: Fri Nov 8 14:17:53 2024 +0800 fix(videoPanel): :bug: default for undefined partnerId Include a check to validate if partnerID is not undefined commit e5e41ce92afd50a32eef8e3889315ba4f56d4eaa Author: tituschewxj Date: Thu Nov 7 14:07:00 2024 +0800 fix(frontend): :bug: mounts component before accessing local storage Only access localStorage on the client side (in the browser) after the component has mounted. commit d75215c120d6b03c06ac889be0e769fa4dc8122d Author: tituschewxj Date: Thu Nov 7 10:40:15 2024 +0800 style(execution-service): :fire: remove commented code Revmoes the previous commented implementation of sending the submission to history service via REST API call. commit fac44307e888ab2a9c72699fa6a329a847f224a7 Author: tituschewxj Date: Thu Nov 7 01:20:36 2024 +0800 docs: update readme commit 2b2bbd59a6c1be61563db2ee1e0e9ff7fc4b73cb Author: tituschewxj Date: Thu Nov 7 01:12:41 2024 +0800 docs: update readme commit 95a82dc161702934cf68a40368d3a74ab2235fe4 Author: tituschewxj Date: Thu Nov 7 01:10:12 2024 +0800 ci: update docker compose test commit bf0c096955050d55b544b487a70f617eb284def6 Author: tituschewxj Date: Thu Nov 7 01:07:32 2024 +0800 docs: update readme commit b8e3004f8d21268f0f7c42eec4fe3deb83b53203 Author: tituschewxj Date: Thu Nov 7 00:54:53 2024 +0800 docs: update readme commit 8bd3d10c71bf007fb2723d5fcd81ef45e088e36a Author: tituschewxj Date: Thu Nov 7 00:52:29 2024 +0800 feat: update readme commit fbd3a4de76d4f1254c6943c01dc40f14816d7fde Author: tituschewxj Date: Thu Nov 7 00:45:09 2024 +0800 feat: update log msg commit 64a1badcfebdedcef17f31d6539c747b05481588 Author: tituschewxj Date: Thu Nov 7 00:33:50 2024 +0800 fix: update docker-compose commit e48bc7ea91cf62bb9661613fefe0194b71ed3525 Author: tituschewxj Date: Wed Nov 6 23:17:41 2024 +0800 feat: update docker compose commit 8a0e046576e4469d485ca3f11128d3419d330069 Author: tituschewxj Date: Wed Nov 6 23:17:35 2024 +0800 feat: implement rabbitmq msg queue commit 324463e3b1ae0812202668ebeacdd1f13c4b7b64 Author: Ryan Chia Date: Wed Nov 6 01:33:41 2024 +0800 branch name --- .github/workflows/test.yml | 28 ++-- apps/docker-compose.yml | 24 +++- apps/execution-service/.env.example | 2 + apps/execution-service/README.md | 123 +++++++++++------- apps/execution-service/go.mod | 1 + apps/execution-service/go.sum | 2 + apps/execution-service/handlers/submit.go | 33 +---- apps/execution-service/main.go | 18 +-- .../messagequeue/rabbitmq.go | 78 +++++++++++ apps/execution-service/utils/log.go | 9 ++ .../__tests__/browser-tests/browser.test.ts | 42 ++++-- .../src/app/collaboration/[id]/page.tsx | 59 ++++++++- .../CollaborativeEditor.tsx | 47 +++---- .../src/components/VideoPanel/VideoPanel.tsx | 20 ++- apps/history-service/.env.example | 8 +- apps/history-service/README.md | 27 +++- apps/history-service/databases/history.go | 32 +++++ apps/history-service/go.mod | 1 + apps/history-service/go.sum | 2 + apps/history-service/handlers/create.go | 19 +-- apps/history-service/main.go | 16 ++- apps/history-service/messagequeue/rabbitmq.go | 108 +++++++++++++++ apps/history-service/utils/log.go | 9 ++ 23 files changed, 543 insertions(+), 165 deletions(-) create mode 100644 apps/execution-service/messagequeue/rabbitmq.go create mode 100644 apps/execution-service/utils/log.go create mode 100644 apps/history-service/databases/history.go create mode 100644 apps/history-service/messagequeue/rabbitmq.go create mode 100644 apps/history-service/utils/log.go diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8d18e13b1c..fe4ee21edc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v2 - + - name: Set up .env env: QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} @@ -30,7 +30,7 @@ jobs: echo "FIREBASE_CREDENTIAL_PATH=$QUESTION_FIREBASE_CREDENTIAL_PATH" >> .env echo "JWT_SECRET=$JWT_SECRET" >> .env echo "EXECUTION_SERVICE_URL=$EXECUTION_SERVICE_URL" >> .env - + - name: Set up credentials env: QUESTION_FIREBASE_JSON: ${{ secrets.QUESTION_SERVICE_FIREBASE_CREDENTIAL }} @@ -41,8 +41,8 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 - with: - go-version: '1.23.x' + with: + go-version: "1.23.x" - name: Install Go dependencies run: | @@ -51,7 +51,7 @@ jobs: - name: Install firebase tools run: curl -sL firebase.tools | bash - + - name: Run Go tests with Firebase emulator run: firebase emulators:exec --only firestore 'cd ./apps/question-service; go test -v ./tests' @@ -66,11 +66,11 @@ jobs: run: | cd ./apps/frontend cp .env.example .env - + - name: Set up Node.js uses: actions/setup-node@v2 with: - node-version: '22' + node-version: "22" - name: Install pnpm run: npm i -g pnpm @@ -227,17 +227,25 @@ jobs: uses: pnpm/action-setup@v4 with: version: 9.1.4 - + - name: Install dependencies run: | cd ./apps/frontend pnpm i - + - name: Install Chrome WebDriver uses: nanasess/setup-chromedriver@v2 with: chromedriver-version: '130.0.6723.116' - + + - name: Install Edge + uses: browser-actions/setup-edge@v1 + with: + edge-version: stable + + - name: Install Geckodriver + uses: browser-actions/setup-geckodriver@latest + - name: Run Browser Test run: | cd ./apps/frontend diff --git a/apps/docker-compose.yml b/apps/docker-compose.yml index a0565fe1dd..12d02b5661 100644 --- a/apps/docker-compose.yml +++ b/apps/docker-compose.yml @@ -68,7 +68,9 @@ services: - apps_network volumes: - ./history-service:/history-service - + depends_on: + - rabbitmq + signalling-service: build: context: ./signalling-service @@ -95,6 +97,8 @@ services: volumes: - ./execution-service:/execution-service - /var/run/docker.sock:/var/run/docker.sock + depends_on: + - rabbitmq redis: image: redis:latest @@ -104,6 +108,19 @@ services: - 6379:6379 container_name: redis-container + rabbitmq: + image: rabbitmq:3-management + networks: + - apps_network + ports: + - 5672:5672 # Port for RabbitMQ message broker + - 15672:15672 # Port for RabbitMQ Management UI + environment: + RABBITMQ_DEFAULT_USER: guest + RABBITMQ_DEFAULT_PASS: guest + volumes: + - rabbitmq_data:/var/lib/rabbitmq + python-sandbox: build: context: ./execution-service/execution/python @@ -114,3 +131,8 @@ services: networks: apps_network: + +volumes: + # Mounts a volume for RabbitMQ data persistence. + # This ensures that data is not lost when the container is restarted or removed. + rabbitmq_data: diff --git a/apps/execution-service/.env.example b/apps/execution-service/.env.example index 6a1fb0bd86..4122078fbd 100644 --- a/apps/execution-service/.env.example +++ b/apps/execution-service/.env.example @@ -3,6 +3,8 @@ PORT=8083 # If you are NOT USING docker, use the below variables # HISTORY_SERVICE_URL=http://localhost:8082/ +# RABBITMQ_URL=amqp://guest:guest@localhost:5672/ # If you are USING docker, use the below variables HISTORY_SERVICE_URL=http://history-service:8082/ +RABBITMQ_URL=amqp://guest:guest@rabbitmq:5672/ diff --git a/apps/execution-service/README.md b/apps/execution-service/README.md index 2961ed152e..c53dc3ab9f 100644 --- a/apps/execution-service/README.md +++ b/apps/execution-service/README.md @@ -20,7 +20,32 @@ go run main.go The server will be available at http://localhost:8083. -## Running the Application via Docker +### Setting up message queue with RabbitMQ + +A message queue is used to pass submission results asynchronously from the execution-service to the history-service. + +1. In order to do so, we can run the following command to set up a docker container for RabbitMQ: + +```bash +docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management +``` + +2. Then we can run the execution-service: + +```bash +go run main.go +``` + +3. We can run the history-service by changing our directory and running the same command: + +```bash +cd ../history-service +go run main.go +``` + +To view more details on the RabbitMQ queue, we can go to `localhost:15672`, and login using `guest` as the username and password. + +### Running the Application via Docker To run the application via Docker, run the following command: @@ -74,10 +99,10 @@ The following json format will be returned: ```json [ - { - "input":"hello", - "expected":"olleh" - } + { + "input": "hello", + "expected": "olleh" + } ] ``` @@ -98,16 +123,16 @@ The following json format will be returned: ```json { - "visibleTestResults":[ + "visibleTestResults": [ { - "input":"hello", - "expected":"olleh", - "actual":"olleh", - "passed":true, - "error":"" + "input": "hello", + "expected": "olleh", + "actual": "olleh", + "passed": true, + "error": "" } ], - "customTestResults":null + "customTestResults": null } ``` @@ -127,29 +152,29 @@ The following json format will be returned: ```json { - "visibleTestResults":[ + "visibleTestResults": [ { - "input":"hello", - "expected":"olleh", - "actual":"olleh", - "passed":true, - "error":"" + "input": "hello", + "expected": "olleh", + "actual": "olleh", + "passed": true, + "error": "" } ], - "customTestResults":[ + "customTestResults": [ { - "input":"Hannah", - "expected":"hannaH", - "actual":"hannaH", - "passed":true, - "error":"" + "input": "Hannah", + "expected": "hannaH", + "actual": "hannaH", + "passed": true, + "error": "" }, { - "input":"abcdefg", - "expected":"gfedcba", - "actual":"gfedcba", - "passed":true, - "error":"" + "input": "abcdefg", + "expected": "gfedcba", + "actual": "gfedcba", + "passed": true, + "error": "" } ] } @@ -178,20 +203,20 @@ The following json format will be returned: ```json { - "visibleTestResults":[ + "visibleTestResults": [ { - "input":"hello", - "expected":"olleh", - "actual":"olleh", - "passed":true, - "error":"" + "input": "hello", + "expected": "olleh", + "actual": "olleh", + "passed": true, + "error": "" } ], - "hiddenTestResults":{ - "passed":2, - "total":2 + "hiddenTestResults": { + "passed": 2, + "total": 2 }, - "status":"Accepted" + "status": "Accepted" } ``` @@ -199,19 +224,19 @@ If compilation error exists or any of the tests (visible and hidden) fails, stat ```json { - "visibleTestResults":[ + "visibleTestResults": [ { - "input":"hello", - "expected":"olleh", - "actual":"", - "passed":false, - "error":"Command execution failed: Traceback (most recent call last):\n File \"/tmp/4149249165.py\", line 2, in \u003cmodule\u003e\n prit(name[::-1])\n ^^^^\nNameError: name 'prit' is not defined. Did you mean: 'print'?\n: %!w(*exec.ExitError=\u0026{0x4000364678 []})" + "input": "hello", + "expected": "olleh", + "actual": "", + "passed": false, + "error": "Command execution failed: Traceback (most recent call last):\n File \"/tmp/4149249165.py\", line 2, in \u003cmodule\u003e\n prit(name[::-1])\n ^^^^\nNameError: name 'prit' is not defined. Did you mean: 'print'?\n: %!w(*exec.ExitError=\u0026{0x4000364678 []})" } ], - "hiddenTestResults":{ - "passed":0, - "total":2 + "hiddenTestResults": { + "passed": 0, + "total": 2 }, - "status":"Attempted" + "status": "Attempted" } ``` diff --git a/apps/execution-service/go.mod b/apps/execution-service/go.mod index 32a516cf23..aff484d2a7 100644 --- a/apps/execution-service/go.mod +++ b/apps/execution-service/go.mod @@ -31,6 +31,7 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/googleapis/gax-go/v2 v2.13.0 // indirect + github.com/rabbitmq/amqp091-go v1.10.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect diff --git a/apps/execution-service/go.sum b/apps/execution-service/go.sum index 7d3c75e147..8a595690fa 100644 --- a/apps/execution-service/go.sum +++ b/apps/execution-service/go.sum @@ -85,6 +85,8 @@ github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwA github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw= +github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/apps/execution-service/handlers/submit.go b/apps/execution-service/handlers/submit.go index 0bd06656a3..1411ffcea7 100644 --- a/apps/execution-service/handlers/submit.go +++ b/apps/execution-service/handlers/submit.go @@ -1,16 +1,16 @@ package handlers import ( - "bytes" "encoding/json" "execution-service/constants" + "execution-service/messagequeue" "execution-service/models" "execution-service/utils" "fmt" + "net/http" + "github.com/go-chi/chi/v5" "google.golang.org/api/iterator" - "net/http" - "os" ) func (s *Service) ExecuteVisibleAndHiddenTestsAndSubmit(w http.ResponseWriter, r *http.Request) { @@ -61,7 +61,6 @@ func (s *Service) ExecuteVisibleAndHiddenTestsAndSubmit(w http.ResponseWriter, r } // Save the collaboration history via the history-service - // TODO: convert to message queue submissionReq := models.Submission{ Code: submission.Code, Language: submission.Language, @@ -84,34 +83,12 @@ func (s *Service) ExecuteVisibleAndHiddenTestsAndSubmit(w http.ResponseWriter, r return } - // get history-service url from os env - historyServiceUrl := os.Getenv("HISTORY_SERVICE_URL") - if historyServiceUrl == "" { - http.Error(w, "HISTORY_SERVICE_URL is not set", http.StatusInternalServerError) - return - } - - req, err := http.NewRequest(http.MethodPost, historyServiceUrl+"histories", - bytes.NewBuffer(jsonData)) + err = messagequeue.PublishSubmissionMessage(jsonData) if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, fmt.Sprintf("Failed to save submission history: %v", err), http.StatusInternalServerError) return } - req.Header.Set("Content-Type", "application/json") - - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - http.Error(w, "Failed to save submission history", http.StatusInternalServerError) - } - w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(testResults) diff --git a/apps/execution-service/main.go b/apps/execution-service/main.go index 706d0afcd6..e2da2948be 100644 --- a/apps/execution-service/main.go +++ b/apps/execution-service/main.go @@ -3,6 +3,8 @@ package main import ( "context" "execution-service/handlers" + "execution-service/messagequeue" + "execution-service/utils" "fmt" "log" "net/http" @@ -21,20 +23,20 @@ import ( func main() { // Load .env file err := godotenv.Load() - if err != nil { - log.Fatal("Error loading .env file") - } + utils.FailOnError(err, "Error loading .env file") // Initialize Firestore client ctx := context.Background() client, err := initFirestore(ctx) - if err != nil { - log.Fatalf("Failed to initialize Firestore client: %v", err) - } + utils.FailOnError(err, "Failed to initialize Firestore client") defer client.Close() service := &handlers.Service{Client: client} + amqpConnection, amqpChannel := messagequeue.InitRabbitMQServer() + defer amqpConnection.Close() + defer amqpChannel.Close() + r := initChiRouter(service) initRestServer(r) } @@ -107,7 +109,5 @@ func initRestServer(r *chi.Mux) { // Start the server log.Printf("Starting REST server on http://localhost:%s", port) err := http.ListenAndServe(fmt.Sprintf(":%s", port), r) - if err != nil { - log.Fatalf("Failed to start server: %v", err) - } + utils.FailOnError(err, "Failed to start REST server") } diff --git a/apps/execution-service/messagequeue/rabbitmq.go b/apps/execution-service/messagequeue/rabbitmq.go new file mode 100644 index 0000000000..1a6aafcde7 --- /dev/null +++ b/apps/execution-service/messagequeue/rabbitmq.go @@ -0,0 +1,78 @@ +package messagequeue + +import ( + "execution-service/utils" + "fmt" + "log" + "os" + "time" + + amqp "github.com/rabbitmq/amqp091-go" +) + +const ( + CODE_SUBMISSION_QUEUE_KEY = "code-submission" + NUM_RETRIES = 10 +) + +var ( + codeSubmissionQueue amqp.Queue + rabbitMQChannel *amqp.Channel +) + +func InitRabbitMQServer() (*amqp.Connection, *amqp.Channel) { + conn := connectToRabbitMQ() + + // Create a channel + ch, err := conn.Channel() + utils.FailOnError(err, "Failed to open a channel") + rabbitMQChannel = ch + + // Declare a queue + q, err := ch.QueueDeclare( + CODE_SUBMISSION_QUEUE_KEY, // name + false, // durable + false, // delete when unused + false, // exclusive + false, // no-wait + nil, // arguments + ) + utils.FailOnError(err, "Failed to declare a queue") + codeSubmissionQueue = q + + return conn, ch +} + +func connectToRabbitMQ() *amqp.Connection { + var conn *amqp.Connection + var err error + rabbitMQURL := os.Getenv("RABBITMQ_URL") + for i := 0; i < NUM_RETRIES; i++ { // Retry up to 10 times + conn, err = amqp.Dial(rabbitMQURL) + if err == nil { + log.Println("Connected to RabbitMQ") + return conn + } + log.Printf("Failed to connect to RabbitMQ, retrying in 5 seconds... (Attempt %d/%d)", i+1, NUM_RETRIES) + time.Sleep(5 * time.Second) + } + utils.FailOnError(err, fmt.Sprintf("Failed to connect to RabbitMQ after %d attempts", NUM_RETRIES)) + return nil +} + +func PublishSubmissionMessage(submission []byte) error { + err := rabbitMQChannel.Publish( + "", // exchange + codeSubmissionQueue.Name, // routing key + false, // mandatory + false, // immediate + amqp.Publishing{ + ContentType: "application/json", + Body: submission, + }) + if err != nil { + return fmt.Errorf("Failed to publish a message: %v", err) + } + log.Printf("RabbitMQ: [x] Sent %s", submission) + return nil +} diff --git a/apps/execution-service/utils/log.go b/apps/execution-service/utils/log.go new file mode 100644 index 0000000000..a77b2c29ca --- /dev/null +++ b/apps/execution-service/utils/log.go @@ -0,0 +1,9 @@ +package utils + +import "log" + +func FailOnError(err error, msg string) { + if err != nil { + log.Fatalf("%s: %s", msg, err) + } +} diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index 22257250c3..20b49ba1bd 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -1,37 +1,61 @@ -import { Actions, Browser, Builder, By, Key, until, WebDriver } from "selenium-webdriver" +import { Actions, Browser, Builder, By, Capabilities, Key, until, WebDriver } from "selenium-webdriver" + +import {Options as ChromeOptions} from "selenium-webdriver/chrome" +import {Options as EdgeOptions} from "selenium-webdriver/edge" +import {Options as FirefoxOptions} from "selenium-webdriver/firefox" -import Chrome from "selenium-webdriver/chrome" const URL = 'http://localhost:3000/'; const ETERNAL_JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjk5OTk5OTk5OTk5fQ.Z4_FVGQ5lIcouP3m4YLMr6pGMF17IJFfo2yOTiN58DY" -describe("chrome browser", () => { - const options = new Chrome.Options() - .addArguments("--headless=new") as Chrome.Options; // uncomment locally to see the steps in action - const builder = new Builder().forBrowser(Browser.CHROME).setChromeOptions(options); +const CHROME_OPTIONS = new ChromeOptions() + .addArguments("--headless=new") as ChromeOptions; // uncomment locally to see the steps in action +const EDGE_OPTIONS = new EdgeOptions() + .setBinaryPath("/opt/hostedtoolcache/msedge/stable/x64/msedge") // need to point to the correct path + .addArguments("--headless=new") as EdgeOptions; + +const FIREFOX_OPTIONS = new FirefoxOptions() + .addArguments("--headless") as FirefoxOptions; + +const builder = new Builder() + .setChromeOptions(CHROME_OPTIONS) + .setEdgeOptions(EDGE_OPTIONS) + .setFirefoxOptions(FIREFOX_OPTIONS) + +describe.each([Browser.CHROME, Browser.EDGE, Browser.FIREFOX])("%s driver test", (browser) => { let driver: WebDriver; + beforeAll(() => { + const cap = new Capabilities().setBrowserName(browser) + builder.withCapabilities(cap); + }) beforeEach(async () => { + console.log(browser + ": building..."); driver = await builder.build(); + console.log(browser + ": built"); }) afterEach(async () => { await driver.quit(); }) - describe("chrome webdriver installed correctly", () => { + describe("webdriver installed correctly", () => { it("does google search", async () => { + console.log("getting url"); await driver.get('http://www.google.com'); + console.log("got url"); await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); await driver.wait(until.titleIs('webdriver - Google Search'), 1000); + console.log("did search"); }, 10000); - it("does another google search", async () => { + + it.skip("does another google search", async () => { await driver.get('http://www.google.com'); await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); await driver.wait(until.titleIs('webdriver - Google Search'), 1000); }, 10000); }); - describe("browser-test", () => { + describe.skip("browser-test", () => { it("accesses and login to peerprep", async () => { await driver.get(URL); await driver.wait(until.urlIs(`${URL}login`)); diff --git a/apps/frontend/src/app/collaboration/[id]/page.tsx b/apps/frontend/src/app/collaboration/[id]/page.tsx index 6ae67427ef..739eac08a6 100644 --- a/apps/frontend/src/app/collaboration/[id]/page.tsx +++ b/apps/frontend/src/app/collaboration/[id]/page.tsx @@ -34,9 +34,12 @@ import { ExecuteVisibleAndHiddenTestsAndSubmit, ExecutionResults, GetVisibleTests, + isTestResult, SubmissionHiddenTestResultsAndStatus, SubmissionResults, Test, + TestData, + TestResult, } from "@/app/services/execute"; import { QuestionDetailFull } from "@/components/question/QuestionDetailFull/QuestionDetailFull"; import VideoPanel from "@/components/VideoPanel/VideoPanel"; @@ -75,15 +78,17 @@ export default function CollaborationPage(props: CollaborationProps) { ); const [currentUser, setCurrentUser] = useState(undefined); const [matchedUser, setMatchedUser] = useState("Loading..."); - const [sessionDuration, setSessionDuration] = useState(() => { - const storedTime = localStorage.getItem("session-duration"); - return storedTime ? parseInt(storedTime) : 0; - }); // State for count-up timer (TODO: currently using localstorage to store time, change to db stored time in the future) + const [sessionDuration, setSessionDuration] = useState(0); // State for count-up timer (TODO: currently using localstorage to store time, change to db stored time in the future) const stopwatchRef = useRef(null); const [matchedTopics, setMatchedTopics] = useState( undefined ); + useEffect(() => { + const storedTime = localStorage.getItem("session-duration"); + setSessionDuration(storedTime ? parseInt(storedTime) : 0); + }, []); + // Chat states const [messageToSend, setMessageToSend] = useState( undefined @@ -314,6 +319,52 @@ export default function CollaborationPage(props: CollaborationProps) { } }, [isSessionEndModalOpen, countDown]); + // Tabs component items for visibleTestCases + var items: TabsProps["items"] = visibleTestCases.map((item, index) => { + return { + key: index.toString(), + label: ( + + Case {index + 1} + + ), + children: ( +
+ + {isTestResult(item) && ( +
+ + + {item.passed ? "Passed" : "Failed"} + +
+ Actual Output:{" "} + {item.actual} +
+ {item.error && ( + <> + Error: +
{item.error}
+ + )} +
+ )} +
+ ), + }; + }); + // Handles the cleaning of localstorage variables, stopping the timer & signalling collab user on webrtc // type: "initiator" | "peer" const handleCloseCollaboration = (type: string) => { diff --git a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx index a7c8051bcf..d32f67612d 100644 --- a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx +++ b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx @@ -15,8 +15,8 @@ import * as Y from "yjs"; import { yCollab } from "y-codemirror.next"; import { WebrtcProvider } from "y-webrtc"; import { EditorView, basicSetup } from "codemirror"; -import { keymap } from "@codemirror/view" -import { indentWithTab } from "@codemirror/commands" +import { keymap } from "@codemirror/view"; +import { indentWithTab } from "@codemirror/commands"; import { EditorState, Compartment } from "@codemirror/state"; import { javascript, javascriptLanguage } from "@codemirror/lang-javascript"; import { python, pythonLanguage } from "@codemirror/lang-python"; @@ -68,15 +68,15 @@ interface Awareness { executionResultsState: { executionResults: ExecutionResults; id: number; - } + }; executingState: { executing: boolean; id: number; - } + }; submittingState: { submitting: boolean; id: number; - } + }; } export const usercolors = [ @@ -111,8 +111,7 @@ const CollaborativeEditor = forwardRef( props.onCodeChange(update.state.doc.toString()); } }); - - + // Referenced: https://codemirror.net/examples/config/#dynamic-configuration // const autoLanguage = EditorState.transactionExtender.of((tr) => { // if (!tr.docChanged) return null; @@ -196,10 +195,10 @@ const CollaborativeEditor = forwardRef( }); }; - let latestExecutionId: number = (new Date(0)).getTime(); - let latestSubmissionId: number = (new Date(0)).getTime(); - let latestExecutingId: number = (new Date(0)).getTime(); - let latestSubmittingId: number = (new Date(0)).getTime(); + let latestExecutionId: number = new Date(0).getTime(); + let latestSubmissionId: number = new Date(0).getTime(); + let latestExecutingId: number = new Date(0).getTime(); + let latestSubmittingId: number = new Date(0).getTime(); useImperativeHandle(ref, () => ({ endSession: () => { @@ -311,12 +310,14 @@ const CollaborativeEditor = forwardRef( .get(clientID) as Awareness; if ( - state && + state && state.submissionResultsState && state.submissionResultsState.id !== latestSubmissionId ) { latestSubmissionId = state.submissionResultsState.id; - props.updateSubmissionResults(state.submissionResultsState.submissionResults); + props.updateSubmissionResults( + state.submissionResultsState.submissionResults + ); messageApi.open({ type: "success", content: `${ @@ -326,12 +327,14 @@ const CollaborativeEditor = forwardRef( } if ( - state && - state.executionResultsState && + state && + state.executionResultsState && state.executionResultsState.id !== latestExecutionId ) { latestExecutionId = state.executionResultsState.id; - props.updateExecutionResults(state.executionResultsState.executionResults); + props.updateExecutionResults( + state.executionResultsState.executionResults + ); messageApi.open({ type: "success", content: `${ @@ -341,8 +344,8 @@ const CollaborativeEditor = forwardRef( } if ( - state && - state.executingState && + state && + state.executingState && state.executingState.id !== latestExecutingId ) { latestExecutingId = state.executingState.id; @@ -358,8 +361,8 @@ const CollaborativeEditor = forwardRef( } if ( - state && - state.submittingState && + state && + state.submittingState && state.submittingState.id !== latestSubmittingId ) { latestSubmittingId = state.submittingState.id; @@ -367,9 +370,7 @@ const CollaborativeEditor = forwardRef( if (state.submittingState.submitting) { messageApi.open({ type: "info", - content: `${ - props.matchedUser ?? "Peer" - } is saving code...`, + content: `${props.matchedUser ?? "Peer"} is saving code...`, }); } } diff --git a/apps/frontend/src/components/VideoPanel/VideoPanel.tsx b/apps/frontend/src/components/VideoPanel/VideoPanel.tsx index 36fdd948e2..2db62642e0 100644 --- a/apps/frontend/src/components/VideoPanel/VideoPanel.tsx +++ b/apps/frontend/src/components/VideoPanel/VideoPanel.tsx @@ -11,11 +11,8 @@ import { } from "@ant-design/icons"; const VideoPanel = () => { - const matchId = localStorage.getItem("collabId")?.toString() ?? ""; - const currentUsername = localStorage.getItem("user")?.toString(); - const matchedUsername = localStorage.getItem("matchedUser")?.toString(); - const currentId = currentUsername + "-" + matchId ?? ""; - const partnerId = matchedUsername + "-" + matchId ?? ""; + const [currentId, setCurrentId] = useState(); + const [partnerId, setPartnerId] = useState(); const remoteVideoRef = useRef(null); const currentUserVideoRef = useRef(null); @@ -30,6 +27,15 @@ const VideoPanel = () => { const [muteOn, setMuteOn] = useState(false); const [isCalling, setIsCalling] = useState(false); + useEffect(() => { + const matchId = localStorage.getItem("collabId")?.toString() ?? ""; + const currentUsername = localStorage.getItem("user")?.toString(); + const matchedUsername = localStorage.getItem("matchedUser")?.toString(); + + setCurrentId(currentUsername + "-" + (matchId ?? "")); + setPartnerId(matchedUsername + "-" + (matchId ?? "")); + }, []); + const handleCall = () => { navigator.mediaDevices .getUserMedia({ @@ -37,7 +43,7 @@ const VideoPanel = () => { audio: true, }) .then((stream) => { - if (peerInstance) { + if (peerInstance && partnerId) { const call = peerInstance?.call(partnerId, stream); setCallInstance(call); setIsCalling(true); // Set isCalling as true since it is the initiator @@ -120,7 +126,7 @@ const VideoPanel = () => { } }; } - }, []); + }, [currentId]); // When remote peer initiates end call, we set isCalling to false useEffect(() => { diff --git a/apps/history-service/.env.example b/apps/history-service/.env.example index b3bd4db2b4..0f3f18c101 100644 --- a/apps/history-service/.env.example +++ b/apps/history-service/.env.example @@ -1,2 +1,8 @@ FIREBASE_CREDENTIAL_PATH=cs3219-staging-codehisto-bb61c-firebase-adminsdk-egopb-95cfaf9b87.json -PORT=8082 \ No newline at end of file +PORT=8082 + +# If you are NOT USING docker, use the below variables +# RABBITMQ_URL=amqp://guest:guest@localhost:5672/ + +# If you are USING docker, use the below variables +RABBITMQ_URL=amqp://guest:guest@rabbitmq:5672/ \ No newline at end of file diff --git a/apps/history-service/README.md b/apps/history-service/README.md index 681c629bcd..6fec9e5bbd 100644 --- a/apps/history-service/README.md +++ b/apps/history-service/README.md @@ -47,9 +47,34 @@ To start the server, run the following command: go run main.go ``` +### Setting up message queue with RabbitMQ + +A message queue is used to pass submission results asynchronously from the execution-service to the history-service. + +1. In order to do so, we can run the following command to set up a docker container for RabbitMQ: + +```bash +docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management +``` + +2. Then we can run the history-service: + +```bash +go run main.go +``` + +3. We can run the execution-service by changing our directory and running the same command: + +```bash +cd ../execution-service +go run main.go +``` + +To view more details on the RabbitMQ queue, we can go to `localhost:15672`, and login using `guest` as the username and password. + The server will be available at http://localhost:8082. -## Running the Application via Docker +### Running the Application via Docker To run the application via Docker, run the following command: diff --git a/apps/history-service/databases/history.go b/apps/history-service/databases/history.go new file mode 100644 index 0000000000..e9b41e4b14 --- /dev/null +++ b/apps/history-service/databases/history.go @@ -0,0 +1,32 @@ +package databases + +import ( + "context" + "history-service/models" + + "cloud.google.com/go/firestore" +) + +func CreateHistory(client *firestore.Client, ctx context.Context, submissionHistory models.SubmissionHistory) (*firestore.DocumentRef, error) { + // Document reference ID in firestore mapped to the match ID in model + collection := client.Collection("collaboration-history") + + docRef, _, err := collection.Add(ctx, map[string]interface{}{ + "title": submissionHistory.Title, + "code": submissionHistory.Code, + "language": submissionHistory.Language, + "user": submissionHistory.User, + "matchedUser": submissionHistory.MatchedUser, + "matchedTopics": submissionHistory.MatchedTopics, + "questionDocRefId": submissionHistory.QuestionDocRefID, + "questionDifficulty": submissionHistory.QuestionDifficulty, + "questionTopics": submissionHistory.QuestionTopics, + "status": submissionHistory.Status, + "createdAt": firestore.ServerTimestamp, + "updatedAt": firestore.ServerTimestamp, + }) + if err != nil { + return nil, err + } + return docRef, nil +} diff --git a/apps/history-service/go.mod b/apps/history-service/go.mod index 37d6005bf1..2bdb4f0c8a 100644 --- a/apps/history-service/go.mod +++ b/apps/history-service/go.mod @@ -31,6 +31,7 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/googleapis/gax-go/v2 v2.13.0 // indirect + github.com/rabbitmq/amqp091-go v1.10.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect diff --git a/apps/history-service/go.sum b/apps/history-service/go.sum index ce7234e8f6..fbc00bcfaa 100644 --- a/apps/history-service/go.sum +++ b/apps/history-service/go.sum @@ -85,6 +85,8 @@ github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwA github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw= +github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= diff --git a/apps/history-service/handlers/create.go b/apps/history-service/handlers/create.go index 3dc635d0dd..e4868730b7 100644 --- a/apps/history-service/handlers/create.go +++ b/apps/history-service/handlers/create.go @@ -2,11 +2,11 @@ package handlers import ( "encoding/json" + "history-service/databases" "history-service/models" "history-service/utils" "net/http" - "cloud.google.com/go/firestore" "google.golang.org/api/iterator" ) @@ -22,22 +22,7 @@ func (s *Service) CreateHistory(w http.ResponseWriter, r *http.Request) { } // Document reference ID in firestore mapped to the match ID in model - collection := s.Client.Collection("collaboration-history") - - docRef, _, err := collection.Add(ctx, map[string]interface{}{ - "title": submissionHistory.Title, - "code": submissionHistory.Code, - "language": submissionHistory.Language, - "user": submissionHistory.User, - "matchedUser": submissionHistory.MatchedUser, - "matchedTopics": submissionHistory.MatchedTopics, - "questionDocRefId": submissionHistory.QuestionDocRefID, - "questionDifficulty": submissionHistory.QuestionDifficulty, - "questionTopics": submissionHistory.QuestionTopics, - "status": submissionHistory.Status, - "createdAt": firestore.ServerTimestamp, - "updatedAt": firestore.ServerTimestamp, - }) + docRef, err := databases.CreateHistory(s.Client, ctx, submissionHistory) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/apps/history-service/main.go b/apps/history-service/main.go index 751f2ed525..1b79073caf 100644 --- a/apps/history-service/main.go +++ b/apps/history-service/main.go @@ -3,7 +3,10 @@ package main import ( "context" "fmt" + "history-service/databases" "history-service/handlers" + "history-service/messagequeue" + "history-service/utils" "log" "net/http" "os" @@ -20,20 +23,21 @@ import ( func main() { err := godotenv.Load() - if err != nil { - log.Fatal("Error loading .env file") - } + utils.FailOnError(err, "Error loading .env file") // Initialize Firestore client ctx := context.Background() client, err := initFirestore(ctx) - if err != nil { - log.Fatalf("Failed to initialize Firestore client: %v", err) - } + utils.FailOnError(err, "Failed to initialize Firestore client") defer client.Close() service := &handlers.Service{Client: client} + amqpConnection, amqpChannel := messagequeue.InitRabbitMQServer() + defer amqpConnection.Close() + defer amqpChannel.Close() + go messagequeue.ConsumeSubmissionMessages(client, databases.CreateHistory) + r := initChiRouter(service) initRestServer(r) } diff --git a/apps/history-service/messagequeue/rabbitmq.go b/apps/history-service/messagequeue/rabbitmq.go new file mode 100644 index 0000000000..f945a866d0 --- /dev/null +++ b/apps/history-service/messagequeue/rabbitmq.go @@ -0,0 +1,108 @@ +package messagequeue + +import ( + "context" + "encoding/json" + "fmt" + "history-service/models" + "history-service/utils" + "log" + "os" + "time" + + "cloud.google.com/go/firestore" + amqp "github.com/rabbitmq/amqp091-go" +) + +const ( + CODE_SUBMISSION_QUEUE_KEY = "code-submission" + NUM_RETRIES = 10 +) + +var ( + codeSubmissionQueue amqp.Queue + rabbitMQChannel *amqp.Channel +) + +func InitRabbitMQServer() (*amqp.Connection, *amqp.Channel) { + conn := connectToRabbitMQ() + + // Create a channel + ch, err := conn.Channel() + utils.FailOnError(err, "Failed to open a channel") + rabbitMQChannel = ch + + // Declare a queue + q, err := ch.QueueDeclare( + "code-submission", // name + false, // durable + false, // delete when unused + false, // exclusive + false, // no-wait + nil, // arguments + ) + utils.FailOnError(err, "Failed to declare a queue") + codeSubmissionQueue = q + + return conn, ch +} + +func connectToRabbitMQ() *amqp.Connection { + var conn *amqp.Connection + var err error + rabbitMQURL := os.Getenv("RABBITMQ_URL") + for i := 0; i < NUM_RETRIES; i++ { // Retry up to 10 times + conn, err = amqp.Dial(rabbitMQURL) + if err == nil { + log.Println("Connected to RabbitMQ") + return conn + } + log.Printf("Failed to connect to RabbitMQ, retrying in 5 seconds... (Attempt %d/%d)", i+1, NUM_RETRIES) + time.Sleep(5 * time.Second) + } + utils.FailOnError(err, fmt.Sprintf("Failed to connect to RabbitMQ after %d attempts", NUM_RETRIES)) + return nil +} + +func ConsumeSubmissionMessages(client *firestore.Client, createSubmission func( + *firestore.Client, context.Context, models.SubmissionHistory) ( + *firestore.DocumentRef, error)) { + ctx := context.Background() + + // Consume messages from the queue + msgs, err := rabbitMQChannel.Consume( + codeSubmissionQueue.Name, // queue + "", // consumer + true, // auto-ack + false, // exclusive + false, // no-local + false, // no-wait + nil, // args + ) + utils.FailOnError(err, "RabbitMQ: Failed to register a consumer") + + // Create a channel to block indefinitely + forever := make(chan bool) + + // Start a goroutine to handle incoming messages + go func() { + for d := range msgs { + log.Printf("RabbitMQ: Received a message") + + // Parse request + var submissionHistory models.SubmissionHistory + if err := json.Unmarshal(d.Body, &submissionHistory); err != nil { + log.Printf("RabbitMQ: Error decoding JSON: %v", err) + continue + } + + _, err := createSubmission(client, ctx, submissionHistory) + if err != nil { + log.Printf("RabbitMQ: %v", err) + } + } + }() + + log.Printf("RabbitMQ: [*] Waiting for messages.") + <-forever +} diff --git a/apps/history-service/utils/log.go b/apps/history-service/utils/log.go new file mode 100644 index 0000000000..a77b2c29ca --- /dev/null +++ b/apps/history-service/utils/log.go @@ -0,0 +1,9 @@ +package utils + +import "log" + +func FailOnError(err error, msg string) { + if err != nil { + log.Fatalf("%s: %s", msg, err) + } +} From d3ad549122eeecef76c0ccb5d907df6e94636075 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Tue, 12 Nov 2024 15:37:43 +0800 Subject: [PATCH 218/258] quit driver only if present --- apps/frontend/__tests__/browser-tests/browser.test.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index 20b49ba1bd..2225308278 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -29,23 +29,20 @@ describe.each([Browser.CHROME, Browser.EDGE, Browser.FIREFOX])("%s driver test", }) beforeEach(async () => { - console.log(browser + ": building..."); driver = await builder.build(); - console.log(browser + ": built"); }) afterEach(async () => { - await driver.quit(); + if (driver) { + await driver.quit(); + } }) describe("webdriver installed correctly", () => { it("does google search", async () => { - console.log("getting url"); await driver.get('http://www.google.com'); - console.log("got url"); await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); await driver.wait(until.titleIs('webdriver - Google Search'), 1000); - console.log("did search"); }, 10000); it.skip("does another google search", async () => { @@ -55,7 +52,7 @@ describe.each([Browser.CHROME, Browser.EDGE, Browser.FIREFOX])("%s driver test", }, 10000); }); - describe.skip("browser-test", () => { + describe("browser-test", () => { it("accesses and login to peerprep", async () => { await driver.get(URL); await driver.wait(until.urlIs(`${URL}login`)); From e3a384ea66346a330f73206b7378f25a608da6bf Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Tue, 12 Nov 2024 15:48:19 +0800 Subject: [PATCH 219/258] asd --- apps/frontend/__tests__/browser-tests/browser.test.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index 0c6c03c187..6d55979cb4 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -42,12 +42,9 @@ describe.each([Browser.CHROME, Browser.EDGE, Browser.FIREFOX])("%s driver test", describe("webdriver installed correctly", () => { it("does google search", async () => { - console.log("getting url"); await driver.get('http://www.google.com'); - console.log("got url"); await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); await driver.wait(until.titleIs('webdriver - Google Search'), 1000); - console.log("did search"); }, 10000); it.skip("does another google search", async () => { @@ -78,7 +75,7 @@ describe.each([Browser.CHROME, Browser.EDGE, Browser.FIREFOX])("%s driver test", expect(slogan2).toBe("peers"); }, 10000); }) -}) +}, 20000) From 77f62dbeabb27686232fe543c18b0eb4ca157b2d Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Tue, 12 Nov 2024 15:54:07 +0800 Subject: [PATCH 220/258] Squashed commit of the following: commit 5dbc8a083ddd10f7ba2065843e88feea63df9e6e Author: Ryan Chia Date: Tue Nov 12 15:50:20 2024 +0800 --- apps/frontend/__tests__/browser-tests/browser.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index 6d55979cb4..46fa946f63 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -32,7 +32,7 @@ describe.each([Browser.CHROME, Browser.EDGE, Browser.FIREFOX])("%s driver test", console.log(browser + ": building..."); driver = await builder.build(); console.log(browser + ": built"); - }) + }, 10000) afterEach(async () => { if (driver) { From 1be60da0858de200ad1e6fa0817a45e29f2e0ed1 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Tue, 12 Nov 2024 16:06:25 +0800 Subject: [PATCH 221/258] revert to chrome whoops --- .github/workflows/test.yml | 164 +++++++++++++++--- .../__tests__/browser-tests/browser.test.ts | 48 ++--- 2 files changed, 155 insertions(+), 57 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 45d5fcf341..13bcff8e10 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v2 - + - name: Set up .env env: QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} @@ -30,7 +30,7 @@ jobs: echo "FIREBASE_CREDENTIAL_PATH=$QUESTION_FIREBASE_CREDENTIAL_PATH" >> .env echo "JWT_SECRET=$JWT_SECRET" >> .env echo "EXECUTION_SERVICE_URL=$EXECUTION_SERVICE_URL" >> .env - + - name: Set up credentials env: QUESTION_FIREBASE_JSON: ${{ secrets.QUESTION_SERVICE_FIREBASE_CREDENTIAL }} @@ -41,8 +41,8 @@ jobs: - name: Setup Go uses: actions/setup-go@v5 - with: - go-version: "1.23.x" + with: + go-version: '1.23.x' - name: Install Go dependencies run: | @@ -51,7 +51,7 @@ jobs: - name: Install firebase tools run: curl -sL firebase.tools | bash - + - name: Run Go tests with Firebase emulator run: firebase emulators:exec --only firestore 'cd ./apps/question-service; go test -v ./tests' @@ -66,11 +66,11 @@ jobs: run: | cd ./apps/frontend cp .env.example .env - + - name: Set up Node.js uses: actions/setup-node@v2 with: - node-version: "22" + node-version: '22' - name: Install pnpm run: npm i -g pnpm @@ -85,38 +85,160 @@ jobs: cd ./apps/frontend pnpm unit-test - test-webdriver-working: + test-docker-compose: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 + - name: Set up Docker Compose + run: | + sudo apt-get update + sudo apt-get install -y docker-compose + + - name: Create Environment Files + env: + QUESTION_SERVICE_URL: ${{ vars.QUESTION_SERVICE_URL }} + USER_SERVICE_URL: ${{ vars.USER_SERVICE_URL }} + MATCHING_SERVICE_URL: ${{ vars.MATCHING_SERVICE_URL }} + HISTORY_SERVICE_URL: ${{ vars.HISTORY_SERVICE_URL }} + SIGNALLING_SERVICE_URL: ${{ vars.SIGNALLING_SERVICE_URL }} + EXECUTION_SERVICE_URL: ${{ vars.EXECUTION_SERVICE_URL }} + JWT_SECRET: ${{ secrets.JWT_SECRET }} + QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} + HISTORY_FIREBASE_CREDENTIAL_PATH: ${{ vars.HISTORY_SERVICE_FIREBASE_CREDENTIAL_PATH }} + EXECUTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.EXECUTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} + DB_CLOUD_URI: ${{ secrets.USER_SERVICE_DB_CLOUD_URI }} + USER_SERVICE_PORT: ${{ vars.USER_SERVICE_PORT }} + MATCHING_SERVICE_PORT: ${{ vars.MATCHING_SERVICE_PORT }} + HISTORY_SERVICE_PORT: ${{ vars.HISTORY_SERVICE_PORT }} + SIGNALLING_SERVICE_PORT: ${{ vars.SIGNALLING_SERVICE_PORT }} + EXECUTION_SERVICE_PORT: ${{ vars.EXECUTION_SERVICE_PORT }} + MATCHING_SERVICE_TIMEOUT: ${{ vars.MATCHING_SERVICE_TIMEOUT }} + REDIS_URL: ${{ vars.REDIS_URL }} + QUESTION_SERVICE_GRPC_URL: ${{ vars.QUESTION_SERVICE_GPRC_URL }} + run: | + cd ./apps/frontend + echo "NEXT_PUBLIC_QUESTION_SERVICE_URL=$QUESTION_SERVICE_URL" >> .env + echo "NEXT_PUBLIC_USER_SERVICE_URL=$USER_SERVICE_URL" >> .env + echo "NEXT_PUBLIC_MATCHING_SERVICE_URL=$MATCHING_SERVICE_URL" >> .env + echo "NEXT_PUBLIC_HISTORY_SERVICE_URL=$HISTORY_SERVICE_URL" >> .env + echo "NEXT_PUBLIC_SIGNALLING_SERVICE_URL=$SIGNALLING_SERVICE_URL" >> .env + echo "NEXT_PUBLIC_EXECUTION_SERVICE_URL=EXECUTION_SERVICE_URL" >> .env + + cd ../question-service + echo "FIREBASE_CREDENTIAL_PATH=$QUESTION_FIREBASE_CREDENTIAL_PATH" >> .env + echo "JWT_SECRET=$JWT_SECRET" >> .env + echo "EXECUTION_SERVICE_URL=$EXECUTION_SERVICE_URL" >> .env + + cd ../user-service + echo "DB_CLOUD_URI=$DB_CLOUD_URI" >> .env + echo "PORT=$USER_SERVICE_PORT" >> .env + echo "JWT_SECRET=$JWT_SECRET" >> .env + + cd ../matching-service + echo "PORT=$MATCHING_SERVICE_PORT" >> .env + echo "MATCH_TIMEOUT=$MATCHING_SERVICE_TIMEOUT" >> .env + echo "JWT_SECRET=$JWT_SECRET" >> .env + echo "REDIS_URL=$REDIS_URL" >> .env + echo "QUESTION_SERVICE_GRPC_URL=$QUESTION_SERVICE_GRPC_URL" >> .env + + cd ../history-service + echo "FIREBASE_CREDENTIAL_PATH=$HISTORY_FIREBASE_CREDENTIAL_PATH" >> .env + echo "PORT=$HISTORY_SERVICE_PORT" >> .env + + cd ../execution-service + echo "FIREBASE_CREDENTIAL_PATH=$EXECUTION_FIREBASE_CREDENTIAL_PATH" >> .env + echo "PORT=$EXECUTION_SERVICE_PORT" >> .env + echo "HISTORY_SERVICE_URL=$HISTORY_SERVICE_URL" >> .env + + cd ../signalling-service + echo "PORT=$SIGNALLING_SERVICE_PORT" >> .env + + - name: Create Database Credential Files + env: + QUESTION_FIREBASE_JSON: ${{ secrets.QUESTION_SERVICE_FIREBASE_CREDENTIAL }} + QUESTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.QUESTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} + HISTORY_FIREBASE_JSON: ${{ secrets.HISTORY_SERVICE_FIREBASE_CREDENTIAL }} + HISTORY_FIREBASE_CREDENTIAL_PATH: ${{ vars.HISTORY_SERVICE_FIREBASE_CREDENTIAL_PATH }} + EXECUTION_FIREBASE_JSON: ${{ secrets.EXECUTION_SERVICE_FIREBASE_CREDENTIAL }} + EXECUTION_FIREBASE_CREDENTIAL_PATH: ${{ vars.EXECUTION_SERVICE_FIREBASE_CREDENTIAL_PATH }} + run: | + cd ./apps/question-service + echo "$QUESTION_FIREBASE_JSON" > "./$QUESTION_FIREBASE_CREDENTIAL_PATH" + + cd ../history-service + echo "$HISTORY_FIREBASE_JSON" > "./$HISTORY_FIREBASE_CREDENTIAL_PATH" + + cd ../execution-service + echo "$EXECUTION_FIREBASE_JSON" > "./$EXECUTION_FIREBASE_CREDENTIAL_PATH" + + - name: Build and Run Services + run: | + cd ./apps + docker-compose up --build -d + + - name: Wait for services to be ready + run: sleep 30 + + - name: Install websocat + run: | + sudo wget -qO /usr/local/bin/websocat https://github.com/vi/websocat/releases/latest/download/websocat.x86_64-unknown-linux-musl + sudo chmod a+x /usr/local/bin/websocat + websocat --version + + - name: Run Tests + env: + FRONTEND_URL: ${{ vars.FRONTEND_URL }} + USER_SERVICE_URL: ${{ vars.USER_SERVICE_URL }} + QUESTION_SERVICE_URL: ${{ vars.QUESTION_SERVICE_URL }} + MATCHING_SERVICE_URL: ${{ vars.MATCHING_SERVICE_URL }} + HISTORY_SERVICE_URL: ${{ vars.HISTORY_SERVICE_URL }} + SIGNALLING_SERVICE_URL: ${{ vars.SIGNALLING_SERVICE_URL }} + EXECUTION_SERVICE_URL: ${{ vars.EXECUTION_SERVICE_URL }} + run: | + echo "Testing Question Service..." + curl -sSL -o /dev/null $QUESTION_SERVICE_URL && echo "Question Service is up" + echo "Testing User Service..." + curl -fsSL -o /dev/null $USER_SERVICE_URL && echo "User Service is up" + echo "Testing Frontend..." + curl -fsSL -o /dev/null $FRONTEND_URL && echo "Frontend is up" + echo "Testing History Service..." + curl -fsSL -o /dev/null $HISTORY_SERVICE_URL && echo "History Service is up" + echo "Testing Execution Service..." + curl -fsSL -o /dev/null $EXECUTION_SERVICE_URL && echo "Execution Service is up" + echo "Testing Matching Service..." + if ! (echo "Hello" | websocat $MATCHING_SERVICE_URL); then + echo "WebSocket for Matching Service is not live" + else + echo "WebSocket for Matching Service is live" + fi + # Add in test for matching service in the future + echo "Testing Signalling Service..." + if ! (echo "Hello" | websocat $SIGNALLING_SERVICE_URL); then + echo "WebSocket for Signalling Service is not live" + else + echo "WebSocket for Signalling Service is live" + fi + # We can add more tests here + - name: Install pnpm uses: pnpm/action-setup@v4 with: version: 9.1.4 - + - name: Install dependencies run: | cd ./apps/frontend pnpm i - + - name: Install Chrome WebDriver uses: nanasess/setup-chromedriver@v2 with: chromedriver-version: '130.0.6723.116' - - - name: Install Edge - uses: browser-actions/setup-edge@v1 - with: - edge-version: stable - - - name: Install Geckodriver - uses: browser-actions/setup-geckodriver@latest - + - name: Run Browser Test run: | cd ./apps/frontend - pnpm browser-test -t "webdriver installed correctly" - + pnpm browser-test \ No newline at end of file diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index 46fa946f63..a80c55d645 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -1,60 +1,37 @@ -import { Actions, Browser, Builder, By, Capabilities, Key, until, WebDriver } from "selenium-webdriver" - -import {Options as ChromeOptions} from "selenium-webdriver/chrome" -import {Options as EdgeOptions} from "selenium-webdriver/edge" -import {Options as FirefoxOptions} from "selenium-webdriver/firefox" +import { Actions, Browser, Builder, By, Key, until, WebDriver } from "selenium-webdriver" +import Chrome from "selenium-webdriver/chrome" const URL = 'http://localhost:3000/'; const ETERNAL_JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjk5OTk5OTk5OTk5fQ.Z4_FVGQ5lIcouP3m4YLMr6pGMF17IJFfo2yOTiN58DY" -const CHROME_OPTIONS = new ChromeOptions() - .addArguments("--headless=new") as ChromeOptions; // uncomment locally to see the steps in action -const EDGE_OPTIONS = new EdgeOptions() - .setBinaryPath("/opt/hostedtoolcache/msedge/stable/x64/msedge") // need to point to the correct path - .addArguments("--headless=new") as EdgeOptions; - -const FIREFOX_OPTIONS = new FirefoxOptions() - .addArguments("--headless") as FirefoxOptions; - -const builder = new Builder() - .setChromeOptions(CHROME_OPTIONS) - .setEdgeOptions(EDGE_OPTIONS) - .setFirefoxOptions(FIREFOX_OPTIONS) - -describe.each([Browser.CHROME, Browser.EDGE, Browser.FIREFOX])("%s driver test", (browser) => { +describe("chrome browser", () => { + const options = new Chrome.Options() + .addArguments("--headless=new") as Chrome.Options; // uncomment locally to see the steps in action + const builder = new Builder().forBrowser(Browser.CHROME).setChromeOptions(options); let driver: WebDriver; - beforeAll(() => { - const cap = new Capabilities().setBrowserName(browser) - builder.withCapabilities(cap); - }) beforeEach(async () => { - console.log(browser + ": building..."); driver = await builder.build(); - console.log(browser + ": built"); - }, 10000) + }) afterEach(async () => { - if (driver) { - await driver.quit(); - } + await driver.quit(); }) - describe("webdriver installed correctly", () => { + describe("chrome webdriver installed correctly", () => { it("does google search", async () => { await driver.get('http://www.google.com'); await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); await driver.wait(until.titleIs('webdriver - Google Search'), 1000); }, 10000); - - it.skip("does another google search", async () => { + it("does another google search", async () => { await driver.get('http://www.google.com'); await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); await driver.wait(until.titleIs('webdriver - Google Search'), 1000); }, 10000); }); - describe.skip("browser-test", () => { + describe("browser-test", () => { it("accesses and login to peerprep", async () => { await driver.get(URL); await driver.wait(until.urlIs(`${URL}login`)); @@ -75,8 +52,7 @@ describe.each([Browser.CHROME, Browser.EDGE, Browser.FIREFOX])("%s driver test", expect(slogan2).toBe("peers"); }, 10000); }) -}, 20000) - +}) From 4b50754ed2490ab425f5467c49b23a64200b7181 Mon Sep 17 00:00:00 2001 From: Ryan Chia Date: Tue, 12 Nov 2024 17:35:37 +0800 Subject: [PATCH 222/258] Squashed commit of the following: commit 196329a8a96e5a5742e8e4c733133388719e8b43 Author: Ryan Chia Date: Tue Nov 12 17:25:34 2024 +0800 remove webdriver working workflow commit 1add73da99db880d598f11dd2164d7c9346cdbd1 Author: Ryan Chia Date: Tue Nov 12 17:16:25 2024 +0800 asd commit 974caa60ad0657ddcb2e8c35f3a9136d16901f54 Author: Ryan Chia Date: Tue Nov 12 16:09:05 2024 +0800 asad commit f1e3deb88ffb4d02ea53d77785d1477aaef6e7c9 Merge: 5dbc8a0 77f62db Author: Ryan Chia Date: Tue Nov 12 16:04:54 2024 +0800 Merge branch 'browser-compatibility-tests' into browser-tests commit 5dbc8a083ddd10f7ba2065843e88feea63df9e6e Author: Ryan Chia Date: Tue Nov 12 15:50:20 2024 +0800 asd --- .github/workflows/test.yml | 9 +++- .../__tests__/browser-tests/browser.test.ts | 46 ++++++++++++++----- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 13bcff8e10..06afbd05a0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -237,8 +237,15 @@ jobs: uses: nanasess/setup-chromedriver@v2 with: chromedriver-version: '130.0.6723.116' + - name: Install Edge + uses: browser-actions/setup-edge@v1 + with: + edge-version: stable + - name: Install Geckodriver + uses: browser-actions/setup-geckodriver@latest + - name: Run Browser Test run: | cd ./apps/frontend - pnpm browser-test \ No newline at end of file + pnpm browser-test diff --git a/apps/frontend/__tests__/browser-tests/browser.test.ts b/apps/frontend/__tests__/browser-tests/browser.test.ts index a80c55d645..145c036b81 100644 --- a/apps/frontend/__tests__/browser-tests/browser.test.ts +++ b/apps/frontend/__tests__/browser-tests/browser.test.ts @@ -1,30 +1,53 @@ -import { Actions, Browser, Builder, By, Key, until, WebDriver } from "selenium-webdriver" +import { Actions, Browser, Builder, By, Capabilities, Key, until, WebDriver } from "selenium-webdriver" + +import {Options as ChromeOptions} from "selenium-webdriver/chrome" +import {Options as EdgeOptions} from "selenium-webdriver/edge" +import {Options as FirefoxOptions} from "selenium-webdriver/firefox" -import Chrome from "selenium-webdriver/chrome" const URL = 'http://localhost:3000/'; const ETERNAL_JWT = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjk5OTk5OTk5OTk5fQ.Z4_FVGQ5lIcouP3m4YLMr6pGMF17IJFfo2yOTiN58DY" -describe("chrome browser", () => { - const options = new Chrome.Options() - .addArguments("--headless=new") as Chrome.Options; // uncomment locally to see the steps in action - const builder = new Builder().forBrowser(Browser.CHROME).setChromeOptions(options); +const CHROME_OPTIONS = new ChromeOptions() + .addArguments("--headless=new") as ChromeOptions; // uncomment locally to see the steps in action +const EDGE_OPTIONS = new EdgeOptions() + .setBinaryPath("/opt/hostedtoolcache/msedge/stable/x64/msedge") // need to point to the correct path + .addArguments("--headless=new") as EdgeOptions; + +const FIREFOX_OPTIONS = new FirefoxOptions() + .addArguments("--headless") as FirefoxOptions; + +const builder = new Builder() + .setChromeOptions(CHROME_OPTIONS) + .setEdgeOptions(EDGE_OPTIONS) + .setFirefoxOptions(FIREFOX_OPTIONS) + +describe.each([Browser.CHROME, Browser.EDGE, Browser.FIREFOX])("%s driver test", (browser) => { let driver: WebDriver; + beforeAll(() => { + const cap = new Capabilities().setBrowserName(browser) + builder.withCapabilities(cap); + }) beforeEach(async () => { + console.log(browser + ": building..."); driver = await builder.build(); - }) + console.log(browser + ": built"); + }, 20000) afterEach(async () => { - await driver.quit(); + if (driver) { + await driver.quit(); + } }) - describe("chrome webdriver installed correctly", () => { + describe("webdriver installed correctly", () => { it("does google search", async () => { await driver.get('http://www.google.com'); await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); await driver.wait(until.titleIs('webdriver - Google Search'), 1000); }, 10000); - it("does another google search", async () => { + + it.skip("does another google search", async () => { await driver.get('http://www.google.com'); await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN); await driver.wait(until.titleIs('webdriver - Google Search'), 1000); @@ -52,7 +75,8 @@ describe("chrome browser", () => { expect(slogan2).toBe("peers"); }, 10000); }) -}) +}, 60000) + From 55a424b3d0fd4aa0f3dc54758c9493aff4de648e Mon Sep 17 00:00:00 2001 From: solomonng2001 Date: Tue, 12 Nov 2024 18:15:28 +0800 Subject: [PATCH 223/258] Add create test --- apps/execution-service/go.mod | 2 +- apps/execution-service/go.sum | 2 + apps/execution-service/handlers/create.go | 90 +++++++++++++++++++++++ apps/execution-service/main.go | 2 +- apps/execution-service/utils/populate.go | 6 ++ 5 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 apps/execution-service/handlers/create.go diff --git a/apps/execution-service/go.mod b/apps/execution-service/go.mod index aff484d2a7..fa974a5550 100644 --- a/apps/execution-service/go.mod +++ b/apps/execution-service/go.mod @@ -8,6 +8,7 @@ require ( github.com/go-chi/chi/v5 v5.1.0 github.com/go-chi/cors v1.2.1 github.com/joho/godotenv v1.5.1 + github.com/rabbitmq/amqp091-go v1.10.0 github.com/traefik/yaegi v0.16.1 google.golang.org/api v0.203.0 ) @@ -31,7 +32,6 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect github.com/googleapis/gax-go/v2 v2.13.0 // indirect - github.com/rabbitmq/amqp091-go v1.10.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect diff --git a/apps/execution-service/go.sum b/apps/execution-service/go.sum index 8a595690fa..4733d88abb 100644 --- a/apps/execution-service/go.sum +++ b/apps/execution-service/go.sum @@ -111,6 +111,8 @@ go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHy go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= diff --git a/apps/execution-service/handlers/create.go b/apps/execution-service/handlers/create.go new file mode 100644 index 0000000000..5b9839fc04 --- /dev/null +++ b/apps/execution-service/handlers/create.go @@ -0,0 +1,90 @@ +package handlers + +import ( + "cloud.google.com/go/firestore" + "encoding/json" + "execution-service/models" + "execution-service/utils" + "google.golang.org/api/iterator" + "net/http" +) + +func (s *Service) CreateTest(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + var test models.Test + if err := utils.DecodeJSONBody(w, r, &test); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + // Basic validation for question title and question ID + if test.QuestionDocRefId == "" || test.QuestionTitle == "" { + http.Error(w, "QuestionDocRefId and QuestionTitle are required", http.StatusBadRequest) + return + } + + // Automatically populate validation for input and output in test case + test.InputValidation = utils.GetDefaultValidation() + test.OutputValidation = utils.GetDefaultValidation() + + // Validate test case format + if _, err := utils.ValidateTestCaseFormat(test.VisibleTestCases, test.InputValidation, + test.OutputValidation); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + if _, err := utils.ValidateTestCaseFormat(test.HiddenTestCases, test.InputValidation, + test.OutputValidation); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + // Save test to Firestore + docRef, _, err := s.Client.Collection("tests").Add(ctx, map[string]interface{}{ + "questionDocRefId": test.QuestionDocRefId, + "questionTitle": test.QuestionTitle, + "visibleTestCases": test.VisibleTestCases, + "hiddenTestCases": test.HiddenTestCases, + "inputValidation": test.InputValidation, + "outputValidation": test.OutputValidation, + "createdAt": firestore.ServerTimestamp, + "updatedAt": firestore.ServerTimestamp, + }) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Get data + doc, err := docRef.Get(ctx) + if err != nil { + if err != iterator.Done { + http.Error(w, "Test not found", http.StatusInternalServerError) + return + } + http.Error(w, "Failed to get test", http.StatusInternalServerError) + return + } + + // Map data + if err := doc.DataTo(&test); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(test) +} + +// Manual test cases + +//curl -X POST http://localhost:8083/tests \ +//-H "Content-Type: application/json" \ +//-d '{ +//"questionDocRefId": "sampleDocRefId123", +//"questionTitle": "Sample Question Title", +//"visibleTestCases": "2\nhello\nolleh\nHannah\nhannaH", +//"hiddenTestCases": "2\nHannah\nhannaH\nabcdefg\ngfedcba" +//}' diff --git a/apps/execution-service/main.go b/apps/execution-service/main.go index e2da2948be..1173bfe2ff 100644 --- a/apps/execution-service/main.go +++ b/apps/execution-service/main.go @@ -83,7 +83,7 @@ func registerRoutes(r *chi.Mux, service *handlers.Service) { // Re: CreateTest // Current: Unused, since testcases are populated via script // Future extension: can be created by admin - //r.Post("/", service.CreateTest) + r.Post("/", service.CreateTest) r.Post("/populate", service.PopulateTests) r.Route("/{questionDocRefId}", func(r chi.Router) { diff --git a/apps/execution-service/utils/populate.go b/apps/execution-service/utils/populate.go index fc23098712..767b565af2 100644 --- a/apps/execution-service/utils/populate.go +++ b/apps/execution-service/utils/populate.go @@ -673,3 +673,9 @@ func validateInputOrOutput(inputOrOutput string) bool { } `, importCode.String(), functionBody) } + +func GetDefaultValidation() string { + return getPackagesAndFunction([]string{}, ` +return len(inputOrOutput) > 0 +`) +} From 60966abe1ff67733dd77e45fef4130677fb309a3 Mon Sep 17 00:00:00 2001 From: solomonng2001 Date: Tue, 12 Nov 2024 18:21:35 +0800 Subject: [PATCH 224/258] Update readme for create test --- apps/execution-service/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps/execution-service/README.md b/apps/execution-service/README.md index c53dc3ab9f..68d4031e37 100644 --- a/apps/execution-service/README.md +++ b/apps/execution-service/README.md @@ -106,6 +106,21 @@ The following json format will be returned: ] ``` +`POST /tests` + +To create a new test case, run the following command: + +```bash +curl -X POST http://localhost:8083/tests \ +-H "Content-Type: application/json" \ +-d '{ +"questionDocRefId": "sampleDocRefId123", +"questionTitle": "Sample Question Title", +"visibleTestCases": "2\nhello\nolleh\nHannah\nhannaH", +"hiddenTestCases": "2\nHannah\nhannaH\nabcdefg\ngfedcba" +}' +``` + `POST /tests/{questionDocRefId}/execute` To execute test cases via a question ID without custom test cases, run the following command, with custom code and language: From 5553b32c4b24e81ede9bdde37d9e36b4ce737d89 Mon Sep 17 00:00:00 2001 From: tituschewxj Date: Tue, 12 Nov 2024 19:04:16 +0800 Subject: [PATCH 225/258] docs: :memo: add images --- docs/architecture_diagram.png | Bin 0 -> 120229 bytes docs/browser_test.png | Bin 0 -> 64884 bytes docs/code_editor.png | Bin 0 -> 19746 bytes docs/collab_page_1.png | Bin 0 -> 444599 bytes docs/collab_page_2.png | Bin 0 -> 625611 bytes docs/collaboration_service.png | Bin 0 -> 146693 bytes ...mmunication_between_collab_and_matching.png | Bin 0 -> 107052 bytes docs/exeuction_process.png | Bin 0 -> 40205 bytes docs/frontend_matchmaking_architecture.png | Bin 0 -> 38358 bytes docs/grpc.png | Bin 0 -> 7778 bytes docs/home_page.png | Bin 0 -> 238636 bytes docs/indiv_question_page.png | Bin 0 -> 63042 bytes docs/jwt_verification.png | Bin 0 -> 14401 bytes docs/peerjs.png | Bin 0 -> 60177 bytes docs/question_page.png | Bin 0 -> 115184 bytes docs/question_service_testing.png | Bin 0 -> 135149 bytes docs/rabbit_mq_queue.png | Bin 0 -> 11645 bytes docs/redis_pubsub.png | Bin 0 -> 21938 bytes docs/submission_history_page.png | Bin 0 -> 117146 bytes docs/submission_process.png | Bin 0 -> 53474 bytes docs/unit_testing_workflow.png | Bin 0 -> 82658 bytes docs/userflow.png | Bin 0 -> 152645 bytes docs/websocket.png | Bin 0 -> 14893 bytes 23 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/architecture_diagram.png create mode 100644 docs/browser_test.png create mode 100644 docs/code_editor.png create mode 100644 docs/collab_page_1.png create mode 100644 docs/collab_page_2.png create mode 100644 docs/collaboration_service.png create mode 100644 docs/communication_between_collab_and_matching.png create mode 100644 docs/exeuction_process.png create mode 100644 docs/frontend_matchmaking_architecture.png create mode 100644 docs/grpc.png create mode 100644 docs/home_page.png create mode 100644 docs/indiv_question_page.png create mode 100644 docs/jwt_verification.png create mode 100644 docs/peerjs.png create mode 100644 docs/question_page.png create mode 100644 docs/question_service_testing.png create mode 100644 docs/rabbit_mq_queue.png create mode 100644 docs/redis_pubsub.png create mode 100644 docs/submission_history_page.png create mode 100644 docs/submission_process.png create mode 100644 docs/unit_testing_workflow.png create mode 100644 docs/userflow.png create mode 100644 docs/websocket.png diff --git a/docs/architecture_diagram.png b/docs/architecture_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..b6d18645d653de46a59dad552212cbdbde6550c0 GIT binary patch literal 120229 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
KfeNs)^7GA@BVN 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 W%TRy!$ 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 A`~Uy| literal 0 HcmV?d00001 diff --git a/docs/code_editor.png b/docs/code_editor.png new file mode 100644 index 0000000000000000000000000000000000000000..30a60ffaaf851d49143c01cde604fed6acfb5801 GIT binary patch literal 19746 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 literal 0 HcmV?d00001 diff --git a/docs/collab_page_1.png b/docs/collab_page_1.png new file mode 100644 index 0000000000000000000000000000000000000000..5e9cbd443d7d350bcf9b2f585c08fb5c78cdbe87 GIT binary patch literal 444599 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

r~_&ymH?IAUPT8F71(mtileB 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 z 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�+RfNOv>XtRj@ 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%0AwkcoQ&4!GWi(oGCJq* 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

@@ -144,7 +144,11 @@ const ProfilePage = (props: ProfilePageProps): JSX.Element => { - + Date: Tue, 12 Nov 2024 22:19:14 +0800 Subject: [PATCH 231/258] Add back localstorage clear method --- apps/frontend/src/components/Header/header.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/frontend/src/components/Header/header.tsx b/apps/frontend/src/components/Header/header.tsx index 387699f5db..ebb9f7c456 100644 --- a/apps/frontend/src/components/Header/header.tsx +++ b/apps/frontend/src/components/Header/header.tsx @@ -70,6 +70,7 @@ const Header = (props: HeaderProps): JSX.Element => { onClick: () => { // Clear away the previously stored jwt token in localstorage deleteToken(); + localStorage.clear(); // Redirect user to login page push("/login"); }, From 87d12999c1ea1b8ee488e63008e0af921af15f11 Mon Sep 17 00:00:00 2001 From: bensohh Date: Tue, 12 Nov 2024 22:20:25 +0800 Subject: [PATCH 232/258] Implement change code functionality for N4 frontend --- apps/frontend/package.json | 2 +- apps/frontend/pnpm-lock.yaml | 6 +- .../src/app/collaboration/[id]/page.tsx | 1 + .../CollaborativeEditor.tsx | 119 +++++++++--------- apps/frontend/src/utils/SelectOptions.ts | 16 +-- 5 files changed, 75 insertions(+), 69 deletions(-) diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 792fc18474..2f2c160b57 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -37,10 +37,10 @@ "yjs": "^13.6.20" }, "devDependencies": { - "@types/codemirror": "^5.60.15", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.0.1", + "@types/codemirror": "^5.60.15", "@types/jest": "^29.5.14", "@types/node": "^20", "@types/peerjs": "^1.1.0", diff --git a/apps/frontend/pnpm-lock.yaml b/apps/frontend/pnpm-lock.yaml index 413f0c29e3..5b174a23fd 100644 --- a/apps/frontend/pnpm-lock.yaml +++ b/apps/frontend/pnpm-lock.yaml @@ -4902,7 +4902,7 @@ snapshots: debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 8.0.0 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0))(eslint@8.0.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 @@ -4915,7 +4915,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0))(eslint@8.0.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0): dependencies: debug: 3.2.7 optionalDependencies: @@ -4937,7 +4937,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.0.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.30.0)(eslint@8.0.0))(eslint@8.0.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.8.0(eslint@8.0.0)(typescript@5.0.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.0.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 diff --git a/apps/frontend/src/app/collaboration/[id]/page.tsx b/apps/frontend/src/app/collaboration/[id]/page.tsx index 739eac08a6..5523316318 100644 --- a/apps/frontend/src/app/collaboration/[id]/page.tsx +++ b/apps/frontend/src/app/collaboration/[id]/page.tsx @@ -384,6 +384,7 @@ export default function CollaborationPage(props: CollaborationProps) { localStorage.removeItem("collabId"); localStorage.removeItem("questionDocRefId"); localStorage.removeItem("matchedTopics"); + localStorage.removeItem("editor-language"); // Remove editor language type when session closed }; return ( diff --git a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx index d32f67612d..fab13f68ac 100644 --- a/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx +++ b/apps/frontend/src/components/CollaborativeEditor/CollaborativeEditor.tsx @@ -77,6 +77,10 @@ interface Awareness { submitting: boolean; id: number; }; + editorState: { + language: string; + id: number; + }; } export const usercolors = [ @@ -101,8 +105,10 @@ const CollaborativeEditor = forwardRef( ) => { const editorRef = useRef(null); // const providerRef = useRef(null); - const [selectedLanguage, setSelectedLanguage] = useState("Python"); + const [selectedLanguage, setSelectedLanguage] = useState("python"); + const [mounted, setMounted] = useState(false); let sessionEndNotified = false; + let sessionEndTimeout: any; const languageConf = new Compartment(); @@ -113,57 +119,25 @@ const CollaborativeEditor = forwardRef( }); // Referenced: https://codemirror.net/examples/config/#dynamic-configuration - // const autoLanguage = EditorState.transactionExtender.of((tr) => { - // if (!tr.docChanged) return null; - - // const snippet = tr.newDoc.sliceString(0, 100); - - // // Handle code change - // props.onCodeChange(tr.newDoc.toString()); - - // // Test for various language - // const docIsPython = /^\s*(def|class)\s/.test(snippet); - // const docIsJava = /^\s*(class|public\s+static\s+void\s+main)\s/.test( - // snippet - // ); // Java has some problems - // const docIsCpp = /^\s*(#include|namespace|int\s+main)\s/.test(snippet); // Yet to test c++ - // const docIsGo = /^(package|import|func|type|var|const)\s/.test(snippet); - - // let newLanguage; - // let languageType; - // let languageLabel; - - // if (docIsPython) { - // newLanguage = python(); - // languageLabel = "Python"; - // languageType = pythonLanguage; - // } else if (docIsJava) { - // newLanguage = java(); - // languageLabel = "Java"; - // languageType = javaLanguage; - // } else if (docIsGo) { - // newLanguage = go(); - // languageLabel = "Go"; - // languageType = goLanguage; - // } else if (docIsCpp) { - // newLanguage = cpp(); - // languageLabel = "C++"; - // languageType = cppLanguage; - // } else { - // newLanguage = javascript(); // Default to JavaScript - // languageLabel = "JavaScript"; - // languageType = javascriptLanguage; - // } - - // const stateLanguage = tr.startState.facet(language); - // if (languageType == stateLanguage) return null; - - // setSelectedLanguage(languageLabel); - - // return { - // effects: languageConf.reconfigure(newLanguage), - // }; - // }); + const autoLanguage = EditorState.transactionExtender.of((tr) => { + if (!tr.docChanged) return null; + const editorLanguage = localStorage.getItem("editor-language") ?? ""; + let stateIsJs = tr.startState.facet(language) == javascriptLanguage; + let stateIsPython = tr.startState.facet(language) == pythonLanguage; + if ( + (stateIsJs && editorLanguage.toLowerCase() === "javascript") || + (stateIsPython && editorLanguage.toLowerCase() === "python") + ) + return null; + + return { + effects: languageConf.reconfigure( + editorLanguage.toLowerCase() === "javascript" + ? javascript() + : python() + ), + }; + }); const [messageApi, contextHolder] = message.useMessage(); @@ -199,6 +173,7 @@ const CollaborativeEditor = forwardRef( let latestSubmissionId: number = new Date(0).getTime(); let latestExecutingId: number = new Date(0).getTime(); let latestSubmittingId: number = new Date(0).getTime(); + let latestLanguageChangeId: number = new Date(0).getTime(); useImperativeHandle(ref, () => ({ endSession: () => { @@ -219,7 +194,20 @@ const CollaborativeEditor = forwardRef( }, })); - let sessionEndTimeout: any; + useEffect(() => { + localStorage.setItem("editor-language", selectedLanguage); + + if (props.providerRef.current && mounted) { + latestLanguageChangeId = Date.now(); + props.providerRef.current.awareness.setLocalStateField("editorState", { + language: selectedLanguage, + id: latestLanguageChangeId, + }); + success(`Changed Code Editor's language to ${selectedLanguage}`); + } else { + setMounted(true); + } + }, [selectedLanguage]); useEffect(() => { if (process.env.NEXT_PUBLIC_SIGNALLING_SERVICE_URL === undefined) { @@ -309,6 +297,21 @@ const CollaborativeEditor = forwardRef( .getStates() .get(clientID) as Awareness; + // New section to check for changes in language + if ( + state && + state.editorState && + state.editorState.id !== latestLanguageChangeId + ) { + latestSubmissionId = state.editorState.id; + setSelectedLanguage(state.editorState.language); + // if (props.user === state.user.name) { + // console.log("ownself update ownself"); + // } else { + // console.log("others update ownself"); + // } + } + if ( state && state.submissionResultsState && @@ -383,7 +386,7 @@ const CollaborativeEditor = forwardRef( basicSetup, languageConf.of(python()), // languageConf.of(javascript()), - // autoLanguage, + autoLanguage, yCollab(ytext, provider.awareness, { undoManager }), keymap.of([indentWithTab]), codeChangeListener, @@ -410,10 +413,12 @@ const CollaborativeEditor = forwardRef(
Select Language:
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

dd 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