diff --git a/.github/workflows/gcp-deploy-frontend.yaml b/.github/workflows/gcp-deploy-frontend.yaml index 616d1514db..9c874d74bf 100644 --- a/.github/workflows/gcp-deploy-frontend.yaml +++ b/.github/workflows/gcp-deploy-frontend.yaml @@ -143,8 +143,10 @@ jobs: USERBACK_TOKEN=${{secrets.USERBACK_TOKEN}} WEB3_STORAGE_TOKEN=${{secrets.WEB3_STORAGE_TOKEN}} OPENSEA_API_KEY=${{secrets.OPENSEA_API_KEY}} - GOOGLE_CAL_API_KEY=${{secrets.GOOGLE_CAL_API_KEY}} - GOOGLE_CAL_PRIVATE_KEY=${{secrets.GOOGLE_CAL_PRIVATE_KEY}} + GCAL_PRIVATE_KEY=${{secrets.GCAL_PRIVATE_KEY}} + GCAL_CLIENT_EMAIL=${{secrets.GCAL_CLIENT_EMAIL}} + GCAL_PROJECT_NUMBER=${{secrets.GCAL_PROJECT_NUMBER}} + GCAL_CALENDAR_ID=${{secrets.GCAL_CALENDAR_ID}} push: true deploy-frontend: diff --git a/.github/workflows/gcp-deploy-pr.yaml b/.github/workflows/gcp-deploy-pr.yaml index 1ee73f9a49..7a5c1c7394 100644 --- a/.github/workflows/gcp-deploy-pr.yaml +++ b/.github/workflows/gcp-deploy-pr.yaml @@ -32,9 +32,6 @@ env: HASURA_SECRET: metagame_secret GA4_ID: G-B1NKK3Q1BP APP_ENV: development - GOOGLE_CAL_PROJECT_NUMBER: 510169944888 - GOOGLE_CAL_CLIENT_EMAIL: metagamecalwebsite@metagamecal.iam.gserviceaccount.com - GOOGLE_CAL_CALENDAR_ID: nih59ktgafmm64ed4qk6ue8vv4 jobs: start-deployment: @@ -103,9 +100,6 @@ jobs: HASURA_TAG: ${{env.HASURA_TAG}} FRONTEND_TAG: ${{env.FRONTEND_TAG}} FRONTEND_TARGET: ${{env.FRONTEND_TARGET}} - GOOGLE_CAL_PROJECT_NUMBER: ${{env.GOOGLE_CAL_PROJECT_NUMBER}} - GOOGLE_CAL_CLIENT_EMAIL: ${{env.GOOGLE_CAL_CLIENT_EMAIL}} - GOOGLE_CAL_CALENDAR_ID: ${{env.GOOGLE_CAL_CALENDAR_ID}} steps: - name: First Intepolation of Variables @@ -255,23 +249,18 @@ jobs: needs: [env, delete-backend, undeploy-backend] steps: - - name: "Checkout: ${{github.event.pull_request.head.label}}" - uses: actions/checkout@v3 - with: - ref: ${{github.event.pull_request.head.sha}} - - name: Set Up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: "Login to Registry: ${{needs.env.outputs.DOCKER_REGISTRY}}" - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{needs.env.outputs.DOCKER_REGISTRY}} username: _json_key password: ${{secrets.GCP_SA_KEY}} - name: "Build & Push Container Image: ${{needs.env.outputs.BACKEND_TAG}}" - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: file: docker/backend/Dockerfile tags: ${{needs.env.outputs.BACKEND_TAG}} @@ -367,17 +356,17 @@ jobs: ref: ${{github.event.pull_request.head.sha}} - name: Set Up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: "Login to Registry: ${{needs.env.outputs.DOCKER_REGISTRY}}" - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{needs.env.outputs.DOCKER_REGISTRY}} username: _json_key password: ${{secrets.GCP_SA_KEY}} - name: "Build & Push Container Image: ${{needs.env.outputs.HASURA_TAG}}" - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: file: hasura/Dockerfile context: hasura @@ -465,23 +454,18 @@ jobs: needs: [env, delete-frontend, undeploy-frontend, deploy-hasura, seed-db] steps: - - name: "Checkout: ${{github.event.pull_request.head.label}}" - uses: actions/checkout@v3 - with: - ref: ${{github.event.pull_request.head.sha}} - - name: Set Up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: "Login to Registry: ${{needs.env.outputs.DOCKER_REGISTRY}}" - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{needs.env.outputs.DOCKER_REGISTRY}} username: _json_key password: ${{secrets.GCP_SA_KEY}} - name: "Build & Push Container Image: ${{needs.env.outputs.FRONTEND_TAG}}" - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: file: docker/frontend/Dockerfile tags: ${{needs.env.outputs.FRONTEND_TAG}} @@ -494,8 +478,10 @@ jobs: IMGIX_TOKEN=${{secrets.IMGIX_TOKEN}} WEB3_STORAGE_TOKEN=${{secrets.WEB3_STORAGE_TOKEN}} OPENSEA_API_KEY=${{secrets.OPENSEA_API_KEY}} - GOOGLE_CAL_API_KEY=${{secrets.GOOGLE_CAL_API_KEY}} - GOOGLE_CAL_PRIVATE_KEY=${{secrets.GOOGLE_CAL_PRIVATE_KEY}} + GCAL_PRIVATE_KEY=${{secrets.GCAL_PRIVATE_KEY}} + GCAL_PROJECT_NUMBER=${{secrets.GCAL_PROJECT_NUMBER}} + GCAL_CLIENT_EMAIL=${{secrets.GCAL_CLIENT_EMAIL}} + GCAL_CALENDAR_ID=${{secrets.GCAL_CALENDAR_ID}} push: true deploy-frontend: @@ -527,7 +513,12 @@ jobs: --memory ${{needs.env.outputs.FRONTEND_TARGET == 'development' && '5Gi' || '512Mi'}} \ --ingress all \ --max-instances 1 \ - --allow-unauthenticated + --allow-unauthenticated \ + --set-env-vars GCAL_PRIVATE_KEY="${{secrets.GCAL_PRIVATE_KEY}}" \ + --set-env-vars GCAL_PROJECT_NUMBER="${{secrets.GCAL_PROJECT_NUMBER}}" \ + --set-env-vars GCAL_CLIENT_EMAIL="${{secrets.GCAL_CLIENT_EMAIL}}" \ + --set-env-vars NEXT_PUBLIC_GCAL_CALENDAR_ID="${{secrets.GCAL_CALENDAR_ID}}" + seed-db: name: Seed Database diff --git a/.node-version b/.node-version index 47979412e9..209e3ef4b6 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -16.20.1 +20 diff --git a/docker/backend/Dockerfile b/docker/backend/Dockerfile index 55daf74f53..96d5a95ca2 100644 --- a/docker/backend/Dockerfile +++ b/docker/backend/Dockerfile @@ -1,9 +1,9 @@ -FROM node:16-slim as base +FROM node:20-slim as base WORKDIR /usr/src/app # Install dependencies not included in the slim image RUN apt-get update && \ - apt-get install -y --no-install-recommends g++ make python git openssl && \ + apt-get install -y --no-install-recommends g++ make python3 git openssl && \ apt-get install -y --no-install-recommends --reinstall ca-certificates # Install dependencies for dev and prod @@ -44,7 +44,7 @@ RUN yarn backend:build RUN yarn install --pure-lockfile --production --ignore-scripts --prefer-offline # Create completely new stage including only necessary files -FROM node:16-slim as app +FROM node:20-slim as app WORKDIR /app # Copy necessary files into the stage diff --git a/docker/discord-bot/Dockerfile b/docker/discord-bot/Dockerfile index 346f49f401..4844aec3b1 100644 --- a/docker/discord-bot/Dockerfile +++ b/docker/discord-bot/Dockerfile @@ -1,9 +1,9 @@ -FROM node:16-slim as base +FROM node:20-slim as base WORKDIR /usr/src/app # Install dependencies not included in the slim image RUN apt-get update && \ - apt-get install -y --no-install-recommends g++ make python git openssl && \ + apt-get install -y --no-install-recommends g++ make python3 git openssl && \ apt-get install -y --no-install-recommends --reinstall ca-certificates # Install dependencies for dev and prod @@ -38,7 +38,7 @@ RUN yarn discord-bot build RUN yarn install --pure-lockfile --production --ignore-scripts --prefer-offline # Create completely new stage including only necessary files -FROM node:16-slim as app +FROM node:20-slim as app WORKDIR /app # Needed at runtime diff --git a/docker/frontend/Dockerfile b/docker/frontend/Dockerfile index f17dd42955..17bb494c23 100644 --- a/docker/frontend/Dockerfile +++ b/docker/frontend/Dockerfile @@ -7,11 +7,11 @@ # site or dev environment respectively. ARG TARGET=production -FROM node:16-slim AS base +FROM node:20-slim AS base WORKDIR /usr/src/app # Install dependencies not included in the slim image -RUN apt-get update && apt-get install -y --no-install-recommends g++ make python git ca-certificates +RUN apt-get update && apt-get install -y --no-install-recommends g++ make python3 git ca-certificates # Install dependencies for dev and prod COPY package.json ./ @@ -51,6 +51,10 @@ ARG USERBACK_TOKEN ARG CERAMIC_URL https://ceramic.metagame.wtf ARG WEB3_STORAGE_TOKEN ARG OPENSEA_API_KEY +ARG GCAL_CALENDAR_ID +ARG GCAL_PRIVATE_KEY +ARG GCAL_CLIENT_EMAIL +ARG GCAL_PROJECT_NUMBER # ARGs are not available at runtime, so define ENV variables # These ENVs should match the --set-env-vars in `.github/workflows/gcp-deploy.yaml` @@ -63,9 +67,13 @@ ENV NEXT_PUBLIC_YOUTUBE_API_KEY $YOUTUBE_API_KEY ENV NEXT_PUBLIC_HONEYBADGER_API_KEY $HONEYBADGER_API_KEY ENV NEXT_PUBLIC_USERBACK_TOKEN $USERBACK_TOKEN ENV NEXT_PUBLIC_CERAMIC_URL $CERAMIC_URL +ENV NEXT_PUBLIC_GCAL_CALENDAR_ID $GCAL_CALENDAR_ID # These are not exposed to the browser ENV WEB3_STORAGE_TOKEN $WEB3_STORAGE_TOKEN ENV OPENSEA_API_KEY $OPENSEA_API_KEY +ENV GCAL_PRIVATE_KEY $GCAL_PRIVATE_KEY +ENV GCAL_CLIENT_EMAIL $GCAL_CLIENT_EMAIL +ENV GCAL_PROJECT_NUMBER $GCAL_PROJECT_NUMBER ONBUILD RUN yarn web:build # Delete devDependencies @@ -77,7 +85,7 @@ ONBUILD RUN yarn web:deps:build FROM "build-$TARGET" as built # New stage including only necessary files -FROM node:16-slim AS app +FROM node:20-slim AS app WORKDIR /app # Copy necessary files into the stage diff --git a/package.json b/package.json index cee5411904..e79d8081a3 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "docker:build": "docker-compose up --build -d", "docker:stop": "docker-compose down", "docker:clean": "docker-compose down -v", - "docker:dev": "COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose up --build", + "docker:dev": "DOCKER_BUILDKIT=1 docker compose up --build", "build": "lerna run --concurrency 1 --stream build", "web:dev": "lerna run dev --parallel --scope @metafam/web --include-dependencies", "web:build": "lerna run build --scope @metafam/web --include-dependencies --stream", @@ -102,7 +102,9 @@ "ethers": "5.7.0", "graphql": "16.8.0", "multihashes": "4.0.3", - "@urql/core": "3.2.2" + "@urql/core": "3.2.2", + "node-gyp": "10.0.1", + "better-sqlite3": "9.0.0" }, "browserslist": [ "defaults", diff --git a/packages/design-system/src/theme/colors.ts b/packages/design-system/src/theme/colors.ts index 52a56e4fbd..e0ca0a52ad 100644 --- a/packages/design-system/src/theme/colors.ts +++ b/packages/design-system/src/theme/colors.ts @@ -44,6 +44,7 @@ export type MetaColors = ChakraTheme['colors'] & { landing600: string; landing650: string; landingDarkGlass: string; + darkPurpleAlpha: ColorHues; midnightBlue: string; royalBlue: string; deepMagenta: string; @@ -184,4 +185,16 @@ export const colors: MetaColors = { landing600: '#DF9BFF', landing650: '#DFB9D7', landingDarkGlass: 'rgba(27, 13, 42, 0.9)', + darkPurpleAlpha: { + 50: 'rgba(27, 13, 42, 0.05)', + 100: 'rgba(27, 13, 42, 0.1)', + 200: 'rgba(27, 13, 42, 0.2)', + 300: 'rgba(27, 13, 42, 0.3)', + 400: 'rgba(27, 13, 42, 0.4)', + 500: 'rgba(27, 13, 42, 0.5)', + 600: 'rgba(27, 13, 42, 0.6)', + 700: 'rgba(27, 13, 42, 0.7)', + 800: 'rgba(27, 13, 42, 0.8)', + 900: 'rgba(27, 13, 42, 0.98)', + }, }; diff --git a/packages/web/assets/logo-small.png b/packages/web/assets/logo-small.png new file mode 100644 index 0000000000..2a6cb7dbfa Binary files /dev/null and b/packages/web/assets/logo-small.png differ diff --git a/packages/web/assets/logo-tiny.gif b/packages/web/assets/logo-tiny.gif new file mode 100644 index 0000000000..7588d26964 Binary files /dev/null and b/packages/web/assets/logo-tiny.gif differ diff --git a/packages/web/components/Dashboard/Calendar.tsx b/packages/web/components/Dashboard/Calendar.tsx index 4a1de0c320..bfe7f55141 100644 --- a/packages/web/components/Dashboard/Calendar.tsx +++ b/packages/web/components/Dashboard/Calendar.tsx @@ -8,8 +8,9 @@ import { ExternalLinkIcon, Flex, HStack, - IconButton, Image, + List, + ListItem, LoadingState, MetaButton, Popover, @@ -26,16 +27,11 @@ import { VStack, } from '@metafam/ds'; import { MetaLink } from 'components/Link'; -import { MarkdownViewer } from 'components/MarkdownViewer'; -import type { GoogleCalEventType } from 'lib/hooks/useCalendar'; +import type { GroupedEventsType } from 'lib/hooks/useCalendar'; import { useCalendar } from 'lib/hooks/useCalendar'; import { DateTime } from 'luxon'; import React, { useEffect, useRef, useState } from 'react'; - -type GroupedEventsType = { - date: string; - events: GoogleCalEventType[]; -}; +import { safelyParseContent } from 'utils/stringHelpers'; const loadMoreButtonStyles: ButtonProps = { display: 'flex', @@ -53,14 +49,13 @@ const loadMoreButtonStyles: ButtonProps = { export const Calendar: React.FC = () => { const [calendar, setCalendar] = useState([]); const [loadingMore, setLoadingMore] = useState(false); - const showHowMany = 3; + const showHowMany = 4; const { fetching, error, ics, eventsGroupedByDay, totalEvents, - cleanDescription, buildAddToCalendarLink, limit, setLimit, @@ -237,8 +232,8 @@ export const Calendar: React.FC = () => { }) .toUpperCase()} - { }} > {day && - day.events?.map((event) => ( - - - + day.events?.map((event) => { + const { cover, description } = event; - - - - - ))} - + > + + + + + + + + ); + })} + ); })} @@ -379,6 +345,7 @@ interface EventPopoverType { start: string; end: string; description: string; + cover?: string; htmlLink: string; location: string; addToCalUrl: string; @@ -389,13 +356,14 @@ const EventPopover = ({ start, end, description, + cover, htmlLink, location, addToCalUrl, }: EventPopoverType) => ( - - + - - - - {title} - - + + {title} + + + + Time + + {`${start} – ${end}`} + + {description && ( + + Description + + {safelyParseContent(description)} + + + )} + {location && ( + + Location + + {location} + + + )} + + + + + + + + - Date & Time - - {`${start} – ${end}`} - - {description && ( - - Description - - {description} - - - )} - {location && ( - - Location - - {location} - - + {cover && ( + {title} )} - - - - } - isExternal - /> - } - /> - - + ); diff --git a/packages/web/config.ts b/packages/web/config.ts index 23d12fbedc..2a938e2c4b 100644 --- a/packages/web/config.ts +++ b/packages/web/config.ts @@ -23,11 +23,21 @@ export const CONFIG = { 'https://ceramic-clay.3boxlabs.com', // testnet ceramicNetwork: process.env.NEXT_PUBLIC_CERAMIC_NETWORK || 'mainnet' || 'testnet-clay', - calendarId: process.env.NEXT_PUBLIC_GOOGLE_CAL_CALENDAR_ID, googleDataAPIKey: process.env.NEXT_PUBLIC_YOUTUBE_API_KEY, web3StorageToken: process.env.WEB3_STORAGE_TOKEN, openseaAPIKey: process.env.OPENSEA_API_KEY, alchemyAPIKey: process.env.NEXT_PUBLIC_ALCHEMY_API_KEY, mainnetRPC: process.env.NEXT_PUBLIC_MAINNET_RPC || 'https://eth.llamarpc.com', - metagameCalendarBackend: `${process.env.NEXT_PUBLIC_FRONTEND_URL}/api/events`, + calendarEndpoint: '/api/events', + gcal: { + calendarId: process.env.NEXT_PUBLIC_GCAL_CALENDAR_ID, + privateKey: process.env.GCAL_PRIVATE_KEY?.replace(/\\n/g, '\n'), + clientEmail: process.env.GCAL_CLIENT_EMAIL, + projectNumber: process.env.GCAL_PROJECT_NUMBER, + scopes: ['https://www.googleapis.com/auth/calendar'], + whitelist: [ + 'https://*.metagame.wtf', + 'https://frontend-pr-*-mjhnbmqqna-uk.a.run.app', + ], + }, }; diff --git a/packages/web/lib/hooks/useCalendar.ts b/packages/web/lib/hooks/useCalendar.ts index 2e7af59a29..8ec5e2a2df 100644 --- a/packages/web/lib/hooks/useCalendar.ts +++ b/packages/web/lib/hooks/useCalendar.ts @@ -3,26 +3,27 @@ import { CONFIG } from 'config'; import { DateTime } from 'luxon'; import { useCallback, useEffect, useState } from 'react'; -type GoogleCalEventDateTimeType = +export type GoogleCalEventDateTimeType = | { - dateTime: string; - timeZone: string; + date: string; } | { - date: string; + dateTime: string; + timeZone: string; }; export type GoogleCalEventType = { id: string; summary: string; description: string; + cover?: string; start: GoogleCalEventDateTimeType; end: GoogleCalEventDateTimeType; htmlLink: string; location: string; }; -type UseCalendarReturnTypes = { +export type UseCalendarReturnTypes = { events: Maybe; timeZone: TimeZonesType; fetching: boolean; @@ -32,7 +33,6 @@ type UseCalendarReturnTypes = { totalEvents: number; limit: number; setLimit: (limit: number) => void; - cleanDescription: (desc: string) => string; buildAddToCalendarLink: (event: GoogleCalEventType) => string; }; @@ -41,12 +41,12 @@ type TimeZonesType = { calendar: string; }; -type GroupedEventsType = { +export type GroupedEventsType = { date: string; events: GoogleCalEventType[]; }; -type CalendarDataType = { +export type CalendarDataType = { events: Maybe; days: GroupedEventsType[]; timeZone: TimeZonesType; @@ -59,7 +59,10 @@ type CalendarDataType = { * @returns calendar data (events, timezone, fetching, error, ics, eventsGroupedByDay, totalEvents, limit, setLimit) */ export const useCalendar = (clamp?: number): UseCalendarReturnTypes => { - const { metagameCalendarBackend, calendarId } = CONFIG; + const { + calendarEndpoint, + gcal: { calendarId }, + } = CONFIG; const [calendarData, setCalendarData] = useState({ events: null, days: [], @@ -71,32 +74,82 @@ export const useCalendar = (clamp?: number): UseCalendarReturnTypes => { }); const [limit, setLimit] = useState(clamp || 0); const [fetching, setFetching] = useState(false); - const [error, setError] = useState(undefined); + const [error, setError] = useState(); const calendarICS = `https://calendar.google.com/calendar/ical/${calendarId}%40group.calendar.google.com/public/basic.ics`; - // strip out the +++cover+++ from the description - const cleanDescription = (desc: string) => - desc ? desc.replace(/(\+\+\+).*(\+\+\+)/, '') : ''; + /** + * sanitize the description & get the cover image url if there is one and return the url & sanitized description + */ + const cleanDescription = ( + desc: string, + ): { cover?: string; description: string; originalDesc?: string } => { + if (!desc) { + return { + cover: undefined, + description: '', + originalDesc: desc, + }; + } + + function extractCoverUrl(input: string) { + const splitInput = input.split('+++
'); + const coverSection = splitInput.length > 1 ? splitInput[1] : null; + const urlRegex = /(https?:\/\/[^"\s<]+)/g; + + let coverUrl; + const modifiedInput = splitInput[0]; + + if (coverSection) { + const urls = coverSection.match(urlRegex); + if (urls && urls.length) { + coverUrl = urls.at(-1); + } + } + + return { + coverUrl, + modifiedInput, + }; + } + + const { coverUrl, modifiedInput } = extractCoverUrl(desc); + + const cleanRegex = + /(^(?:
)+|(?:
)+$|(?:
){2,})|(?:<\w+><\/\w+>\s*)+/g; + const cleanedDesc = modifiedInput.replace(cleanRegex, ''); + + return { + cover: coverUrl, + description: cleanedDesc, + originalDesc: desc, + }; + }; /** - * Builds a google calendar event url for adding to your calendar + * Builds a google calendar event url for adding to users calendar * */ const buildAddToCalendarLink = (event: GoogleCalEventType) => { - const start = - 'dateTime' in event.start - ? DateTime.fromISO(event.start.dateTime) - : DateTime.fromISO(event.start.date); - const end = - 'dateTime' in event.end - ? DateTime.fromISO(event.end.dateTime) - : DateTime.fromISO(event.end.date); + const start = DateTime.fromISO( + 'dateTime' in event.start ? event.start.dateTime : event.start.date, + ); + const end = DateTime.fromISO( + 'dateTime' in event.end ? event.end.dateTime : event.end.date, + ); const title = event.summary; const { location } = event; - const details = `${cleanDescription(event.description)}`; + + const details = `${ + cleanDescription(event.description).description + } \n\nMetaGame calendar event link`; const dates = `${start.toFormat('yyyyMMdd')}T${start.toFormat( 'HHmmss', )}/${end.toFormat('yyyyMMdd')}T${end.toFormat('HHmmss')}`; - const href = `https://www.google.com/calendar/render?action=TEMPLATE&text=${title}&dates=${dates}&details=${details}&location=${location}&sf=true&output=xml`; + const href = + 'https://www.google.com/calendar/render' + + `?action=TEMPLATE&text=${title}&dates=${dates}` + + `&details=${encodeURIComponent(details)}&location=${location}` + + '&sf=true&output=xml'; + return href; }; @@ -105,22 +158,60 @@ export const useCalendar = (clamp?: number): UseCalendarReturnTypes => { if (calendarData.days.length > 0) return; setFetching(true); - const res = await fetch(metagameCalendarBackend); + const res = await fetch(calendarEndpoint); const data = await res.json(); - const { days, events: fetchedEvents } = data; + const { days, events: fetchedEvents, error: errorMsg } = data; if (res.status !== 200 || !data) { - throw new Error('Error fetching data'); + throw new Error(errorMsg || 'Error fetching calendar data.'); } const usersTimeZone = DateTime.local().offsetNameShort || fetchedEvents.timeZone; + + // Sanitize the events descriptions & get the cover image url if there is one + const sanitizedEvents = fetchedEvents.items.map( + (event: GoogleCalEventType) => { + const { description } = event; + const { cover, description: cleanedDesc } = + cleanDescription(description); + return { + ...event, + description: cleanedDesc, + cover, + }; + }, + ); + + // Sanitize the grouped events descriptions & get the cover image url if there is one + const sanitizedDays = days.map((day: GroupedEventsType) => { + const { events } = day; + const cleanedEvents = events.map((event: GoogleCalEventType) => { + const { description } = event; + const { cover, description: cleanedDesc } = + cleanDescription(description); + return { + ...event, + description: cleanedDesc, + cover, + }; + }); + return { + ...day, + events: cleanedEvents, + }; + }); + const calValues: CalendarDataType = { events: fetchedEvents.items, - days, - timeZone: { users: usersTimeZone, calendar: fetchedEvents.timeZone }, - totalEvents: fetchedEvents.items.length, + days: sanitizedDays, + timeZone: { + users: usersTimeZone, + calendar: fetchedEvents.timeZone, + }, + totalEvents: sanitizedEvents.length, }; + setCalendarData(calValues); setError(undefined); @@ -130,7 +221,7 @@ export const useCalendar = (clamp?: number): UseCalendarReturnTypes => { } finally { setFetching(false); } - }, [metagameCalendarBackend, calendarData]); + }, [calendarData, calendarEndpoint]); useEffect(() => { if (calendarData.days.length > 0) { @@ -139,10 +230,10 @@ export const useCalendar = (clamp?: number): UseCalendarReturnTypes => { } fetchCalendarData(); - }, [metagameCalendarBackend, calendarData, fetchCalendarData]); + }, [calendarData, fetchCalendarData]); if (error) { - console.error('useCalendar error', error); + console.error({ 'useCalendar error': error }); } return { @@ -153,7 +244,6 @@ export const useCalendar = (clamp?: number): UseCalendarReturnTypes => { ics: calendarICS, eventsGroupedByDay: calendarData.days, totalEvents: calendarData.totalEvents, - cleanDescription, buildAddToCalendarLink, limit, setLimit, diff --git a/packages/web/package.json b/packages/web/package.json index b565945f3b..b254b96836 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -5,7 +5,7 @@ "type": "module", "scripts": { "dev": "concurrently \"next\" \"yarn generate --watch\"", - "build": "yarn generate:graphql && next build", + "build": "yarn generate:graphql && NODE_OPTIONS='--max-old-space-size=5120' next build", "start": "next start", "typecheck": "tsc --noEmit --pretty", "generate": "yarn generate:graphql", diff --git a/packages/web/pages/api/events.ts b/packages/web/pages/api/events.ts index 5ee26cad3f..f545896426 100644 --- a/packages/web/pages/api/events.ts +++ b/packages/web/pages/api/events.ts @@ -3,14 +3,6 @@ import { calendar_v3, google } from 'googleapis'; import { DateTime } from 'luxon'; import { NextApiRequest, NextApiResponse } from 'next'; -const options = { - PRIVATE_KEY: process.env.GOOGLE_CAL_PRIVATE_KEY, - CLIENT_EMAIL: process.env.NEXT_PUBLIC_GOOGLE_CAL_CLIENT_EMAIL, - PROJECT_NUMBER: process.env.NEXT_PUBLIC_GOOGLE_CAL_PROJECT_NUMBER, - CALENDAR_ID: process.env.NEXT_PUBLIC_GOOGLE_CAL_CALENDAR_ID, - SCOPES: ['https://www.googleapis.com/auth/calendar'], -}; - type GoogleCalEventDateTimeType = | { dateTime: string; @@ -31,92 +23,100 @@ export type GoogleCalEventType = { export const cleanDescription = (desc: string): string => desc ? desc.replace(/(\+\+\+).*(\+\+\+)/, '') : desc; +export const matchHostToPattern = (host: string, pattern: string): boolean => { + const regexPattern = pattern + .replace(/[.+?^${}()|[\]\\]/g, '\\$&') + .replace(/\*/g, '.*'); + + const regex = new RegExp(`^${regexPattern}$`); + + return regex.test(host); +}; + +export const isHostWhitelisted = (host: string, whitelist: string[]): boolean => + whitelist.some((pattern) => matchHostToPattern(host, pattern)); + export default async ( req: NextApiRequest, res: NextApiResponse, ): Promise => { - const { host } = req.headers; - const { publicURL } = CONFIG; - const publicHost = publicURL?.replace('https://', '').replace('http://', ''); - if (req.method === 'GET') { - const calId = options.CALENDAR_ID || ''; - const calendarId = `${calId}@group.calendar.google.com`; - - // strip out the +++cover+++ from the description - - const groupEventsByDay = (items: GoogleCalEventType[]) => { - const groupedEvents = items.reduce((acc, event) => { - // console.log('event', {acc, event}); - - const start = - 'dateTime' in event.start - ? DateTime.fromISO(event.start.dateTime, { - zone: event.start.timeZone, - }).toLocal() - : DateTime.fromISO(event.start.date).toLocal(); - - const dateKey = start.toFormat('yyyy-MM-dd'); - if (!acc[dateKey]) { - acc[dateKey] = []; - } - acc[dateKey].push(event); - return acc; - }, {} as Record); - - const days = Object.entries(groupedEvents).map(([date, calEvents]) => ({ - date, - events: calEvents as GoogleCalEventType[], - })); - - return days; + const { publicURL, gcal } = CONFIG; + const calendarId = `${gcal.calendarId}@group.calendar.google.com`; + + const canWhitelist = !!publicURL && gcal.whitelist.length > 0; + const isWhitelisted = canWhitelist + ? isHostWhitelisted(publicURL, gcal.whitelist) + : true; + + if (req.method !== 'GET') { + res.status(405).json({ error: 'Only GET requests allowed.' }); + return; + } + if (!isWhitelisted) { + res.status(403).json({ + error: `Traffic not allowed from ${publicURL}.`, + }); + return; + } + if (!gcal.privateKey || !gcal.clientEmail) { + res.status(500).json({ error: 'Missing Calendar Credentials' }); + return; + } + if (!gcal.calendarId) { + res.status(500).json({ error: 'Missing Calendar ID' }); + return; + } + + const groupEventsByDay = (items: GoogleCalEventType[]) => { + const groupedEvents = items.reduce((acc, event) => { + const start = + 'dateTime' in event.start + ? DateTime.fromISO(event.start.dateTime, { + zone: event.start.timeZone, + }).toLocal() + : DateTime.fromISO(event.start.date).toLocal(); + + const dateKey = start.toFormat('yyyy-MM-dd'); + acc[dateKey] ??= []; + + acc[dateKey].push(event); + return acc; + }, {} as Record); + + const days = Object.entries(groupedEvents).map(([date, calEvents]) => ({ + date, + events: calEvents as GoogleCalEventType[], + })); + + return days; + }; + + const auth = new google.auth.JWT( + gcal.clientEmail, + undefined, + gcal.privateKey, + ['https://www.googleapis.com/auth/calendar.readonly'], + ); + + const calendar = google.calendar({ version: 'v3', auth }); + + try { + const params: calendar_v3.Params$Resource$Events$List = { + calendarId, + timeMin: new Date().toISOString(), + timeMax: DateTime.now().plus({ days: 30 }).toISO() || '', + singleEvents: true, + orderBy: 'startTime', }; + const result = await calendar.events.list(params); + const events = result.data; + const days = groupEventsByDay(events.items as GoogleCalEventType[]); - if (req.method !== 'GET') { - res.status(405).end(); // Method Not Allowed - return; - } - if (host !== publicHost) { - res.status(403).end(); // Forbidden - return; - } - if (!options.PRIVATE_KEY || !options.CLIENT_EMAIL) { - res.status(500).json({ error: 'Missing Google Cal Credentials' }); - return; - } - if (!calendarId) { - res.status(500).json({ error: 'Missing Google Cal Calendar ID' }); - return; - } + const calData = { events, days }; - const auth = new google.auth.JWT( - options.CLIENT_EMAIL, - undefined, - options.PRIVATE_KEY, - ['https://www.googleapis.com/auth/calendar.readonly'], - ); - - const calendar = google.calendar({ version: 'v3', auth }); - - try { - const params: calendar_v3.Params$Resource$Events$List = { - calendarId, - timeMin: DateTime.now().toISO() || '', - timeMax: DateTime.now().plus({ days: 30 }).toISO() || '', - singleEvents: true, - orderBy: 'startTime', - }; - const result = await calendar.events.list(params); - const events = result.data; - const days = groupEventsByDay(events.items as GoogleCalEventType[]); - - const calData = { events, days }; - - res.status(200).json(calData); - } catch (err) { - console.error('err', err); - res.status(500).json({ error: `${err}` }); - } - } else { - res.status(405).end(); // Method Not Allowed + res.status(200).json(calData); + } catch (err) { + console.error({ err }); + res.status(500).json({ error: (err as Error).message }); } }; diff --git a/yarn.lock b/yarn.lock index 04788c91ef..d3ab6e205d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3622,6 +3622,18 @@ dependencies: multiformats "^9.5.4" +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -4755,6 +4767,17 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@npmcli/agent@^2.0.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@npmcli/agent/-/agent-2.2.0.tgz#e81f00fdb2a670750ff7731bbefb47ecbf0ccf44" + integrity sha512-2yThA1Es98orMkpSLVqlDZAMPK3jHJhifP2gnNUdk1754uZ8yI5c+ulCoVG+WlntQA6MzhrURMXjSd9Z7dJ2/Q== + dependencies: + agent-base "^7.1.0" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.1" + lru-cache "^10.0.1" + socks-proxy-agent "^8.0.1" + "@npmcli/ci-detect@^1.0.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@npmcli/ci-detect/-/ci-detect-1.4.0.tgz#18478bbaa900c37bfbd8a2006a6262c62e8b0fe1" @@ -4766,6 +4789,13 @@ "@gar/promisify" "^1.0.1" semver "^7.3.5" +"@npmcli/fs@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-3.1.0.tgz#233d43a25a91d68c3a863ba0da6a3f00924a173e" + integrity sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w== + dependencies: + semver "^7.3.5" + "@npmcli/git@^2.1.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-2.1.0.tgz#2fbd77e147530247d37f325930d457b3ebe894f6" @@ -5069,6 +5099,11 @@ version "1.0.1" resolved "https://registry.yarnpkg.com/@pedrouid/environment/-/environment-1.0.1.tgz#858f0f8a057340e0b250398b75ead77d6f4342ec" +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + "@popperjs/core@^2.9.3": version "2.11.8" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" @@ -6565,6 +6600,11 @@ abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" +abbrev@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" + integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== + abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" @@ -6742,9 +6782,10 @@ ansi-styles@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" -ansi-styles@^6.0.0: +ansi-styles@^6.0.0, ansi-styles@^6.1.0: version "6.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== ansicolors@~0.3.2: version "0.3.2" @@ -7301,12 +7342,13 @@ before-after-hook@^2.2.0: version "2.2.3" resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c" -better-sqlite3@^7.0.0: - version "7.6.2" - resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-7.6.2.tgz#47cd8cad5b9573cace535f950ac321166bc31384" +better-sqlite3@9.0.0, better-sqlite3@^7.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/better-sqlite3/-/better-sqlite3-9.0.0.tgz#bca6026fa1e9e5af62bfef448a7d8402d4549958" + integrity sha512-lDxQ9qg/XuUHZG6xzrQaMHkNWl37t35/LPB/VJGV8DdScSuGFNfFSqgscXEd8UIuyk/d9wU8iaMxQa4If5Wqog== dependencies: bindings "^1.5.0" - prebuild-install "^7.1.0" + prebuild-install "^7.1.1" big-integer@^1.6.48: version "1.6.51" @@ -7683,6 +7725,24 @@ cacache@^15.0.5, cacache@^15.2.0: tar "^6.0.2" unique-filename "^1.1.1" +cacache@^18.0.0: + version "18.0.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-18.0.0.tgz#17a9ecd6e1be2564ebe6cdca5f7cfed2bfeb6ddc" + integrity sha512-I7mVOPl3PUCeRub1U8YoGz2Lqv9WOBpobZ8RyWFXmReuILz+3OAyTa5oH3QPdtKZD7N0Yk00aLfzn0qvp8dZ1w== + dependencies: + "@npmcli/fs" "^3.1.0" + fs-minipass "^3.0.0" + glob "^10.2.2" + lru-cache "^10.0.1" + minipass "^7.0.3" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + p-map "^4.0.0" + ssri "^10.0.0" + tar "^6.1.11" + unique-filename "^3.0.0" + cacheable-lookup@^5.0.3: version "5.0.4" resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" @@ -10599,6 +10659,11 @@ expect@^29.0.0, expect@^29.6.3: jest-message-util "^29.6.3" jest-util "^29.6.3" +exponential-backoff@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6" + integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== + express-graphql@0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/express-graphql/-/express-graphql-0.12.0.tgz#58deabc309909ca2c9fe2f83f5fbe94429aa23df" @@ -11024,6 +11089,14 @@ for-each@^0.3.3: dependencies: is-callable "^1.1.3" +foreground-child@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" + integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -11141,6 +11214,13 @@ fs-minipass@^2.0.0, fs-minipass@^2.1.0: dependencies: minipass "^3.0.0" +fs-minipass@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-3.0.3.tgz#79a85981c4dc120065e96f62086bf6f9dc26cc54" + integrity sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw== + dependencies: + minipass "^7.0.3" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -11350,6 +11430,17 @@ glob@7.1.7: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^10.2.2, glob@^10.3.10: + version "10.3.10" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" + integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.3.5" + minimatch "^9.0.1" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry "^1.10.1" + glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -11477,9 +11568,10 @@ got@^11.8.5: p-cancelable "^2.0.0" responselike "^2.0.0" -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.3, graceful-fs@^4.2.4, graceful-fs@^4.2.9: +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== graphemer@^1.4.0: version "1.4.0" @@ -11839,9 +11931,10 @@ htmlparser2@^8.0: domutils "^3.0.1" entities "^4.4.0" -http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0: +http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== http-errors@1.8.0: version "1.8.0" @@ -11950,6 +12043,14 @@ https-proxy-agent@^7.0.0: agent-base "^7.0.2" debug "4" +https-proxy-agent@^7.0.1: + version "7.0.2" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b" + integrity sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA== + dependencies: + agent-base "^7.0.2" + debug "4" + human-signals@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" @@ -12733,6 +12834,11 @@ isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" +isexe@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-3.1.1.tgz#4a407e2bd78ddfb14bea0c27c6f7072dde775f0d" + integrity sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ== + iso-random-stream@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/iso-random-stream/-/iso-random-stream-2.0.2.tgz#a24f77c34cfdad9d398707d522a6a0cc640ff27d" @@ -12920,6 +13026,15 @@ iterator.prototype@^1.1.0: has-tostringtag "^1.0.0" reflect.getprototypeof "^1.0.3" +jackspeak@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" + integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + jake@^10.8.5: version "10.8.7" resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.7.tgz#63a32821177940c33f356e0ba44ff9d34e1c7d8f" @@ -14221,6 +14336,11 @@ lowercase-keys@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" +lru-cache@^10.0.1, "lru-cache@^9.1.1 || ^10.0.0": + version "10.0.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.1.tgz#0a3be479df549cca0e5d693ac402ff19537a6b7a" + integrity sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -14275,6 +14395,23 @@ make-error@1.x, make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" +make-fetch-happen@^13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz#705d6f6cbd7faecb8eac2432f551e49475bfedf0" + integrity sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A== + dependencies: + "@npmcli/agent" "^2.0.0" + cacache "^18.0.0" + http-cache-semantics "^4.1.1" + is-lambda "^1.0.1" + minipass "^7.0.2" + minipass-fetch "^3.0.0" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + negotiator "^0.6.3" + promise-retry "^2.0.1" + ssri "^10.0.0" + make-fetch-happen@^8.0.9: version "8.0.14" resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz#aaba73ae0ab5586ad8eaa68bd83332669393e222" @@ -14952,6 +15089,13 @@ minimatch@^5.0.1: dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.1: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + minimist-options@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -14980,6 +15124,17 @@ minipass-fetch@^1.3.0, minipass-fetch@^1.3.2: optionalDependencies: encoding "^0.1.12" +minipass-fetch@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-3.0.4.tgz#4d4d9b9f34053af6c6e597a64be8e66e42bf45b7" + integrity sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg== + dependencies: + minipass "^7.0.3" + minipass-sized "^1.0.3" + minizlib "^2.1.2" + optionalDependencies: + encoding "^0.1.13" + minipass-flush@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" @@ -15022,13 +15177,18 @@ minipass@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3: + version "7.0.4" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" + integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== + minizlib@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" dependencies: minipass "^2.9.0" -minizlib@^2.0.0, minizlib@^2.1.1: +minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" dependencies: @@ -15057,7 +15217,7 @@ mkdirp@*: version "3.0.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" -mkdirp@^0.5.1, mkdirp@^0.5.5: +mkdirp@^0.5.5: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" dependencies: @@ -15253,9 +15413,10 @@ near-api-js@^0.44.2: text-encoding-utf-8 "^1.0.2" tweetnacl "^1.0.1" -negotiator@0.6.3, negotiator@^0.6.2: +negotiator@0.6.3, negotiator@^0.6.2, negotiator@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== neo-async@^2.6.2: version "2.6.2" @@ -15390,36 +15551,21 @@ node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: version "4.6.0" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" -node-gyp@^5.0.2: - version "5.1.1" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-5.1.1.tgz#eb915f7b631c937d282e33aed44cb7a025f62a3e" - dependencies: - env-paths "^2.2.0" - glob "^7.1.4" - graceful-fs "^4.2.2" - mkdirp "^0.5.1" - nopt "^4.0.1" - npmlog "^4.1.2" - request "^2.88.0" - rimraf "^2.6.3" - semver "^5.7.1" - tar "^4.4.12" - which "^1.3.1" - -node-gyp@^7.1.0: - version "7.1.2" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae" +node-gyp@10.0.1, node-gyp@^5.0.2, node-gyp@^7.1.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-10.0.1.tgz#205514fc19e5830fa991e4a689f9e81af377a966" + integrity sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg== dependencies: env-paths "^2.2.0" - glob "^7.1.4" - graceful-fs "^4.2.3" - nopt "^5.0.0" - npmlog "^4.1.2" - request "^2.88.2" - rimraf "^3.0.2" - semver "^7.3.2" - tar "^6.0.2" - which "^2.0.2" + exponential-backoff "^3.1.1" + glob "^10.3.10" + graceful-fs "^4.2.6" + make-fetch-happen "^13.0.0" + nopt "^7.0.0" + proc-log "^3.0.0" + semver "^7.3.5" + tar "^6.1.2" + which "^4.0.0" node-html-parser@^5.2.0: version "5.4.2" @@ -15461,18 +15607,12 @@ nodemon@^2.0.20: touch "^3.1.0" undefsafe "^2.0.5" -nopt@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" - dependencies: - abbrev "1" - osenv "^0.1.4" - -nopt@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" +nopt@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.0.tgz#067378c68116f602f552876194fd11f1292503d7" + integrity sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA== dependencies: - abbrev "1" + abbrev "^2.0.0" nopt@~1.0.10: version "1.0.10" @@ -15834,21 +15974,10 @@ ora@^6.3.0: strip-ansi "^7.0.1" wcwidth "^1.0.1" -os-homedir@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - -os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: +os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" -osenv@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.0" - p-cancelable@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" @@ -16135,6 +16264,14 @@ path-root@^0.1.1: dependencies: path-root-regex "^0.1.0" +path-scurry@^1.10.1: + version "1.10.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" + integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== + dependencies: + lru-cache "^9.1.1 || ^10.0.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" @@ -16253,9 +16390,10 @@ preact@10.4.1: version "10.4.1" resolved "https://registry.yarnpkg.com/preact/-/preact-10.4.1.tgz#9b3ba020547673a231c6cf16f0fbaef0e8863431" -prebuild-install@^7.1.0: +prebuild-install@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.1.tgz#de97d5b34a70a0c81334fd24641f2a1702352e45" + integrity sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw== dependencies: detect-libc "^2.0.0" expand-template "^2.0.3" @@ -16290,6 +16428,11 @@ pretty-format@^29.0.0, pretty-format@^29.6.3: ansi-styles "^5.0.0" react-is "^18.0.0" +proc-log@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/proc-log/-/proc-log-3.0.0.tgz#fb05ef83ccd64fd7b20bbe9c8c1070fc08338dd8" + integrity sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A== + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -17292,7 +17435,7 @@ replace-ext@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" -request@^2.79.0, request@^2.85.0, request@^2.88.0, request@^2.88.2: +request@^2.79.0, request@^2.85.0: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" dependencies: @@ -17440,12 +17583,6 @@ rifm@^0.7.0: dependencies: "@babel/runtime" "^7.3.1" -rimraf@^2.6.3: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - dependencies: - glob "^7.1.3" - rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -17634,7 +17771,7 @@ semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" -semver@^7.1.1, semver@^7.1.3, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.5.3, semver@^7.5.4: +semver@^7.1.1, semver@^7.1.3, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.5.3, semver@^7.5.4: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" dependencies: @@ -17785,6 +17922,11 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + signedsource@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/signedsource/-/signedsource-1.0.0.tgz#1ddace4981798f93bd833973803d80d52e93ad6a" @@ -17881,9 +18023,19 @@ socks-proxy-agent@^6.0.0: debug "^4.3.3" socks "^2.6.2" -socks@^2.3.3, socks@^2.6.2: +socks-proxy-agent@^8.0.1: + version "8.0.2" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz#5acbd7be7baf18c46a3f293a840109a430a640ad" + integrity sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g== + dependencies: + agent-base "^7.0.2" + debug "^4.3.4" + socks "^2.7.1" + +socks@^2.3.3, socks@^2.6.2, socks@^2.7.1: version "2.7.1" resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55" + integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ== dependencies: ip "^2.0.0" smart-buffer "^4.2.0" @@ -18107,6 +18259,13 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" +ssri@^10.0.0: + version "10.0.5" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-10.0.5.tgz#e49efcd6e36385196cb515d3a2ad6c3f0265ef8c" + integrity sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A== + dependencies: + minipass "^7.0.3" + ssri@^8.0.0, ssri@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" @@ -18214,6 +18373,15 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -18222,14 +18390,6 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" @@ -18245,9 +18405,10 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^5.0.0: +string-width@^5.0.0, string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== dependencies: eastasianwidth "^0.2.0" emoji-regex "^9.2.2" @@ -18314,6 +18475,13 @@ stringify-package@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/stringify-package/-/stringify-package-1.0.1.tgz#e5aa3643e7f74d0f28628b72f3dad5cecfc3ba85" +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -18332,12 +18500,6 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -18538,7 +18700,7 @@ tar-stream@^2.1.4: inherits "^2.0.3" readable-stream "^3.1.1" -tar@^4.0.2, tar@^4.4.12: +tar@^4.0.2: version "4.4.19" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3" dependencies: @@ -18561,6 +18723,18 @@ tar@^6.0.2, tar@^6.1.0, tar@^6.1.11: mkdirp "^1.0.3" yallist "^4.0.0" +tar@^6.1.2: + version "6.2.0" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.0.tgz#b14ce49a79cb1cd23bc9b016302dea5474493f73" + integrity sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^5.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + temp-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" @@ -19126,12 +19300,26 @@ unique-filename@^1.1.1: dependencies: unique-slug "^2.0.0" +unique-filename@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-3.0.0.tgz#48ba7a5a16849f5080d26c760c86cf5cf05770ea" + integrity sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g== + dependencies: + unique-slug "^4.0.0" + unique-slug@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" dependencies: imurmurhash "^0.1.4" +unique-slug@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-4.0.0.tgz#6bae6bb16be91351badd24cdce741f892a6532e3" + integrity sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ== + dependencies: + imurmurhash "^0.1.4" + unist-util-generated@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-2.0.1.tgz#e37c50af35d3ed185ac6ceacb6ca0afb28a85cae" @@ -19997,6 +20185,13 @@ which@^2.0.1, which@^2.0.2: dependencies: isexe "^2.0.0" +which@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/which/-/which-4.0.0.tgz#cd60b5e74503a3fbcfbf6cd6b4138a8bae644c1a" + integrity sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg== + dependencies: + isexe "^3.1.1" + wide-align@^1.1.0: version "1.1.5" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" @@ -20021,6 +20216,15 @@ wordwrap@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-3.0.1.tgz#288a04d87eda5c286e060dfe8f135ce8d007f8ba" @@ -20044,13 +20248,14 @@ wrap-ansi@^6.0.1, wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" wrappy@1: version "1.0.2"