diff --git a/.github/workflows/admin.checks.yml b/.github/workflows/admin.checks.yml index 92192e41..4ef7d993 100644 --- a/.github/workflows/admin.checks.yml +++ b/.github/workflows/admin.checks.yml @@ -50,6 +50,8 @@ jobs: context: . file: ./apps/admin/Dockerfile tags: registry.fly.io/${{ steps.app_name.outputs.value }}:${{ github.head_ref }}-${{ github.sha }} + secrets: "SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}" + build-args: APPLICATION_VERSION=${{ github.sha }} cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,mode=max,dest=/tmp/.buildx-cache-new diff --git a/.github/workflows/admin.deploy.yml b/.github/workflows/admin.deploy.yml index 60a0f09f..94fdcb42 100644 --- a/.github/workflows/admin.deploy.yml +++ b/.github/workflows/admin.deploy.yml @@ -80,6 +80,8 @@ jobs: file: ./apps/admin/Dockerfile push: true tags: registry.fly.io/${{ steps.app_name.outputs.value }}:${{ github.ref_name }}-${{ github.sha }} + secrets: "SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}" + build-args: APPLICATION_VERSION=${{ github.sha }} cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,mode=max,dest=/tmp/.buildx-cache-new diff --git a/apps/admin/.env b/apps/admin/.env index 05a304af..f61f51cf 100644 --- a/apps/admin/.env +++ b/apps/admin/.env @@ -1,6 +1,7 @@ ALGOLIA_ADMIN_KEY="mock-key" ALGOLIA_ID="mock-id" APPLICATION_TOKEN="admin-token" +APPLICATION_VERSION="local-version" CLOUDINARY_API_KEY="mock-api-key" CLOUDINARY_API_SECRET="mock-api-secret" CLOUDINARY_CLOUD_NAME="mock-cloud-name" diff --git a/apps/admin/Dockerfile b/apps/admin/Dockerfile index a5090228..7e5df1d0 100644 --- a/apps/admin/Dockerfile +++ b/apps/admin/Dockerfile @@ -1,3 +1,5 @@ +ARG APPLICATION_VERSION + # base node image FROM node:22.11-bullseye-slim as base @@ -60,7 +62,8 @@ ADD ./libs/search-params-io ./libs/search-params-io ADD ./libs/tailwind-animation ./libs/tailwind-animation ADD ./libs/zod-utils ./libs/zod-utils ADD ./apps/admin ./apps/admin -RUN yarn --cwd ./apps/admin build +RUN --mount=type=secret,id=SENTRY_AUTH_TOKEN,env=SENTRY_AUTH_TOKEN \ + yarn --cwd ./apps/admin build # Finally, build the production image with minimal footprint FROM base @@ -68,6 +71,7 @@ COPY --from=production-deps /workspace/node_modules ./node_modules COPY --from=production-deps /workspace/apps/admin/node_modules ./apps/admin/node_modules COPY --from=build /workspace/node_modules/.prisma ./node_modules/.prisma COPY --from=build /workspace/apps/admin/build ./apps/admin/build +COPY --from=build /workspace/apps/admin/server.js ./apps/admin/ ADD ./prisma ./prisma ADD ./apps/admin ./apps/admin diff --git a/apps/admin/package.json b/apps/admin/package.json index 0f06bc94..62c47c72 100644 --- a/apps/admin/package.json +++ b/apps/admin/package.json @@ -19,11 +19,12 @@ "dev:icons": "yarn generate:icons --watch", "dev:remix": "node -r dotenv-flow/config ./node_modules/.bin/remix vite:dev --host", "dev:theme": "tsx watch --clear-screen=false ./scripts/generate-theme.ts", - "build": "run-s build:icons build:theme build:remix", + "build": "run-s build:icons build:theme build:server build:remix", "build:icons": "yarn generate:icons --minify", "build:remix": "remix vite:build", + "build:server": "tsc -p ./tsconfig.server.json", "build:theme": "yarn generate:theme", - "start": "remix-serve ./build/server/index.js" + "start": "node server.js ./build/server/index.js" }, "dependencies": { "@algolia/client-search": "^4.22.1", @@ -44,18 +45,23 @@ "@radix-ui/react-popover": "^1.0.6", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-visually-hidden": "^1.0.3", + "@remix-run/express": "~2.9.2", "@remix-run/node": "~2.9.2", "@remix-run/react": "~2.9.2", - "@remix-run/serve": "~2.9.2", "@sentry/remix": "^8.37.1", + "@sentry/vite-plugin": "^3.1.1", "@tailwindcss/container-queries": "^0.1.1", "algoliasearch": "^4.19.1", "autosize": "^6.0.1", "bowser": "^2.11.0", + "chokidar": "^3.5.3", "cloudinary": "^2.2.0", + "compression": "^1.7.4", "cookie-signature": "^1.2.1", "croner": "^8.0.0", "downshift": "^9.0.6", + "express": "^4.17.1", + "get-port": "^5.1.1", "googleapis": "^144.0.0", "history": "^5.3.0", "isbot": "^5.1.8", @@ -72,6 +78,7 @@ "metascraper-image": "^5.36.0", "metascraper-publisher": "^5.36.0", "metascraper-title": "^5.36.0", + "morgan": "^1.10.0", "react": "^18.2.0", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", @@ -81,6 +88,7 @@ "remark-breaks": "^4.0.0", "remark-gfm": "^4.0.0", "remix-utils": "^7.5.0", + "source-map-support": "^0.5.21", "tiny-invariant": "^1.3.1", "uuid": "^9.0.0", "zod": "^3.22.2", @@ -92,7 +100,9 @@ "@remix-run/dev": "~2.9.2", "@total-typescript/ts-reset": "^0.5.1", "@types/autosize": "^4.0.1", + "@types/compression": "^1.7.0", "@types/cookie-signature": "^1.1.0", + "@types/express": "^4.17.9", "@types/lodash.chunk": "^4.2.7", "@types/lodash.difference": "^4.5.7", "@types/lodash.intersection": "^4.4.7", @@ -100,9 +110,11 @@ "@types/lodash.orderby": "^4.6.7", "@types/lodash.zip": "^4.2.7", "@types/luxon": "^3.3.1", + "@types/morgan": "^1.9.2", "@types/node": "^22.8.7", "@types/react": "^18.2.21", "@types/react-dom": "^18.2.7", + "@types/source-map-support": "^0.5.6", "@types/uuid": "^9.0.2", "autoprefixer": "^10.4.15", "chokidar": "^3.5.3", diff --git a/apps/admin/server.ts b/apps/admin/server.ts new file mode 100644 index 00000000..f4b70d9d --- /dev/null +++ b/apps/admin/server.ts @@ -0,0 +1,115 @@ +/** + * Copied from @remix-run/server. + * + * We can't use `installGlobals()` with @mjackson/form-data-parser which is + * automatically called by `@remix-run/server`. + * + * This is version is the same as we used, with only the following changes: + * - Calls to `installGlobals()` have be removed. + * - Code for `NODE_ENV="development"` have been removed. We use + * `remix vite:dev` in dev. + * + * @see https://github.com/mjackson/remix-the-web/issues/26 + * @see https://github.com/remix-run/remix/blob/%40remix-run/serve%402.9.2/packages/remix-serve/cli.ts + */ + +import { createRequestHandler } from "@remix-run/express"; +import type { ServerBuild } from "@remix-run/node"; +import compression from "compression"; +import express from "express"; +import getPort from "get-port"; +import morgan from "morgan"; +import { existsSync, readFileSync } from "node:fs"; +import { networkInterfaces } from "node:os"; +import { fileURLToPath } from "node:url"; +import { install as installSourceMapSupport } from "source-map-support"; + +if (process.env.NODE_ENV !== "production") { + throw new Error("server.ts should only be run in NODE_ENV=production."); +} + +installSourceMapSupport({ + retrieveSourceMap: function (source) { + let match = source.startsWith("file://"); + if (match) { + let filePath = fileURLToPath(source); + let sourceMapPath = `${filePath}.map`; + if (existsSync(sourceMapPath)) { + return { + url: source, + map: readFileSync(sourceMapPath, "utf8"), + }; + } + } + return null; + }, +}); + +run(); + +function parseNumber(raw?: string) { + if (raw === undefined) return undefined; + let maybe = Number(raw); + if (Number.isNaN(maybe)) return undefined; + return maybe; +} + +async function run() { + let port = parseNumber(process.env.PORT) ?? (await getPort({ port: 3000 })); + + let buildPathArg = process.argv[2]; + + if (!buildPathArg) { + console.error(` + Usage: remix-serve - e.g. remix-serve build/index.js`); + process.exit(1); + } + + let build = (await import(buildPathArg)) as ServerBuild; + + let onListen = () => { + let address = + process.env.HOST || + Object.values(networkInterfaces()) + .flat() + .find((ip) => String(ip?.family).includes("4") && !ip?.internal) + ?.address; + + if (!address) { + console.log(`[remix-serve] http://localhost:${port}`); + } else { + console.log( + `[remix-serve] http://localhost:${port} (http://${address}:${port})`, + ); + } + }; + + let app = express(); + app.disable("x-powered-by"); + app.use(compression()); + app.use( + build.publicPath, + express.static(build.assetsBuildDirectory, { + immutable: true, + maxAge: "1y", + }), + ); + app.use(express.static("public", { maxAge: "1h" })); + app.use(morgan("tiny")); + + app.all( + "*", + createRequestHandler({ + build, + mode: process.env.NODE_ENV, + }), + ); + + let server = process.env.HOST + ? app.listen(port, process.env.HOST, onListen) + : app.listen(port, onListen); + + ["SIGTERM", "SIGINT"].forEach((signal) => { + process.once(signal, () => server?.close(console.error)); + }); +} diff --git a/apps/admin/src/core/data-display/error-page.tsx b/apps/admin/src/core/data-display/error-page.tsx index 754d51f5..30ac053c 100644 --- a/apps/admin/src/core/data-display/error-page.tsx +++ b/apps/admin/src/core/data-display/error-page.tsx @@ -7,11 +7,17 @@ import { useLocation, useRouteError, } from "@remix-run/react"; +import { captureRemixErrorBoundaryError } from "@sentry/remix"; +import { useEffect } from "react"; export function ErrorPage() { const error = useRouteError(); console.error("ErrorBoundary error", error); + useEffect(() => { + captureRemixErrorBoundaryError(error); + }, [error]); + const status = isRouteErrorResponse(error) ? asStatusCode(error.status) : DEFAULT_STATUS_CODE; diff --git a/apps/admin/src/core/env.server.ts b/apps/admin/src/core/env.server.ts index e380fd0e..9041d1f3 100644 --- a/apps/admin/src/core/env.server.ts +++ b/apps/admin/src/core/env.server.ts @@ -25,6 +25,11 @@ export function checkEnv() { */ export function getClientEnv() { return { + APPLICATION_VERSION: process.env.APPLICATION_VERSION, + RUNTIME_ENV: process.env.RUNTIME_ENV, + SENTRY_DSN: process.env.SENTRY_DSN, + SENTRY_ENABLE_LOCAL: process.env.SENTRY_ENABLE_LOCAL, + SENTRY_TRACES_SAMPLE_RATE: process.env.SENTRY_TRACES_SAMPLE_RATE, SHOW_URL: process.env.SHOW_URL, }; } @@ -44,8 +49,20 @@ declare global { } const processEnvSchema = zu.object({ + APPLICATION_VERSION: zu.string(), GOOGLE_API_CLIENT_EMAIL: zu.string().optional(), GOOGLE_API_PRIVATE_KEY: zu.string().optional(), GOOGLE_DRIVE_ROOT_FOLDER_ID: zu.string(), + RUNTIME_ENV: zu.enum(["local", "production", "staging"]), + SENTRY_DSN: zu.string().optional(), + SENTRY_ENABLE_LOCAL: zu.enum(["false", "true"]).optional(), + SENTRY_TRACES_SAMPLE_RATE: zu.coerce + .number() + .min(0) + .max(1) + // Because we access the raw value and not the parsed one, we need to be + // sure the type remains string and not number. + .transform((value) => String(value)) + .optional(), SHOW_URL: zu.string(), }); diff --git a/apps/admin/src/core/monitoring.client.ts b/apps/admin/src/core/monitoring.client.ts new file mode 100644 index 00000000..11e60905 --- /dev/null +++ b/apps/admin/src/core/monitoring.client.ts @@ -0,0 +1,28 @@ +import { useLocation, useMatches } from "@remix-run/react"; +import { + browserTracingIntegration, + httpClientIntegration, + init, +} from "@sentry/remix"; +import { useEffect } from "react"; + +export function initMonitoring() { + if ( + CLIENT_ENV.SENTRY_DSN != null && + (CLIENT_ENV.RUNTIME_ENV !== "local" || + CLIENT_ENV.SENTRY_ENABLE_LOCAL === "true") + ) { + init({ + dsn: CLIENT_ENV.SENTRY_DSN, + environment: CLIENT_ENV.RUNTIME_ENV, + tracesSampleRate: Number(CLIENT_ENV.SENTRY_TRACES_SAMPLE_RATE ?? 0), + integrations: [ + // https://docs.sentry.io/platforms/javascript/guides/remix/configuration/integrations/browsertracing + browserTracingIntegration({ useEffect, useLocation, useMatches }), + + // https://docs.sentry.io/platforms/javascript/guides/remix/configuration/integrations/httpclient + httpClientIntegration(), + ], + }); + } +} diff --git a/apps/admin/src/core/monitoring.server.ts b/apps/admin/src/core/monitoring.server.ts new file mode 100644 index 00000000..ccdaf20e --- /dev/null +++ b/apps/admin/src/core/monitoring.server.ts @@ -0,0 +1,32 @@ +import type { User } from "@prisma/client"; +import { init, setUser } from "@sentry/remix"; + +export function initMonitoring() { + if ( + process.env.SENTRY_DSN != null && + (process.env.RUNTIME_ENV !== "local" || + process.env.SENTRY_ENABLE_LOCAL === "true") + ) { + init({ + dsn: process.env.SENTRY_DSN, + environment: process.env.RUNTIME_ENV, + tracesSampleRate: Number(process.env.SENTRY_TRACES_SAMPLE_RATE ?? 0), + }); + } +} + +export function setCurrentUserForMonitoring( + currentUser: null | Pick, +) { + if (currentUser == null) { + setUser(null); + return; + } + + setUser({ + id: currentUser.id, + username: currentUser.displayName, + email: currentUser.email, + groups: currentUser.groups, + }); +} diff --git a/apps/admin/src/core/monitoring.ts b/apps/admin/src/core/monitoring.ts new file mode 100644 index 00000000..7cc8e45a --- /dev/null +++ b/apps/admin/src/core/monitoring.ts @@ -0,0 +1,19 @@ +import type { User } from "@prisma/client"; +import { setUser } from "@sentry/remix"; + +export function useCurrentUserForMonitoring( + currentUser: null | Pick, +) { + // Do this as early as possible for possible errors during rendering. + if (currentUser == null) { + setUser(null); + return; + } + + setUser({ + id: currentUser.id, + username: currentUser.displayName, + email: currentUser.email, + groups: currentUser.groups, + }); +} diff --git a/apps/admin/src/current-user/db.server.ts b/apps/admin/src/current-user/db.server.ts index 86f7fa89..f1110054 100644 --- a/apps/admin/src/current-user/db.server.ts +++ b/apps/admin/src/current-user/db.server.ts @@ -1,5 +1,6 @@ import { algolia } from "#core/algolia/algolia.server"; import { EmailAlreadyUsedError, PrismaErrorCodes } from "#core/errors.server"; +import { setCurrentUserForMonitoring } from "#core/monitoring.server"; import { Routes } from "#core/navigation"; import { prisma } from "#core/prisma.server"; import { NextSearchParams } from "#core/search-params"; @@ -34,8 +35,11 @@ export class CurrentUserDbDelegate { // - Cast the object to the internal properties for internal usages. // - Cast the object to the given properties for the return value. const internalSelect = { - shouldChangePassword: true, + displayName: true, + email: true, groups: true, + id: true, + shouldChangePassword: true, } satisfies Prisma.UserSelect; const user = (await prisma.user.findFirst({ @@ -66,6 +70,8 @@ export class CurrentUserDbDelegate { throw await this.redirectToLogin(request); } + setCurrentUserForMonitoring(user); + if (!skipPasswordChangeCheck && user.shouldChangePassword) { throw await this.redirectToDefinePassword(request); } @@ -150,6 +156,8 @@ export class CurrentUserDbDelegate { } private async redirectToLogin(request: Request) { + setCurrentUserForMonitoring(null); + const path = this.getCurrentRoutePath(request); return redirect( diff --git a/apps/admin/src/entry.client.tsx b/apps/admin/src/entry.client.tsx index 1ac74a6c..79257a4f 100644 --- a/apps/admin/src/entry.client.tsx +++ b/apps/admin/src/entry.client.tsx @@ -1,7 +1,10 @@ +import { initMonitoring } from "#core/monitoring.client"; import { RemixBrowser } from "@remix-run/react"; import { StrictMode, startTransition } from "react"; import { hydrateRoot } from "react-dom/client"; +initMonitoring(); + if (process.env.NODE_ENV === "development") { import("#mocks/mocks.client").then((module) => module.startWorker()); } diff --git a/apps/admin/src/entry.server.tsx b/apps/admin/src/entry.server.tsx index f35d08fb..6ec531f0 100644 --- a/apps/admin/src/entry.server.tsx +++ b/apps/admin/src/entry.server.tsx @@ -1,9 +1,11 @@ import { checkEnv, getClientEnv } from "#core/env.server"; +import { initMonitoring } from "#core/monitoring.server"; import { extendCurrentUserPreferences } from "#current-user/preferences.server"; import { extendCurrentUserSession } from "#current-user/session.server"; import type { EntryContext, HandleDataRequestFunction } from "@remix-run/node"; import { createReadableStreamFromReadable } from "@remix-run/node"; import { RemixServer } from "@remix-run/react"; +import { sentryHandleError } from "@sentry/remix"; import { isbot } from "isbot"; import { PassThrough } from "node:stream"; import type { RenderToPipeableStreamOptions } from "react-dom/server"; @@ -11,6 +13,7 @@ import { renderToPipeableStream } from "react-dom/server"; checkEnv(); global.CLIENT_ENV = getClientEnv(); +initMonitoring(); const ABORT_DELAY_MS = 5000; @@ -79,6 +82,8 @@ export default async function handleRequest( }); } +export const handleError = sentryHandleError; + export const handleDataRequest: HandleDataRequestFunction = async ( response, { request }, diff --git a/apps/admin/src/root.tsx b/apps/admin/src/root.tsx index ba2dc87e..3748f274 100644 --- a/apps/admin/src/root.tsx +++ b/apps/admin/src/root.tsx @@ -17,6 +17,7 @@ import { ScrollRestoration, useLoaderData, } from "@remix-run/react"; +import { withSentry } from "@sentry/remix"; import { Settings } from "luxon"; import "#tailwind.css"; @@ -72,7 +73,9 @@ export const meta: MetaFunction = () => { return [{ title: getPageTitle() }]; }; -export default function App() { +export default withSentry(App); + +function App() { const { CLIENT_ENV } = useLoaderData(); return ( diff --git a/apps/admin/src/routes/_layout.tsx b/apps/admin/src/routes/_layout.tsx index e3a1c9ae..c06a05fd 100644 --- a/apps/admin/src/routes/_layout.tsx +++ b/apps/admin/src/routes/_layout.tsx @@ -3,6 +3,7 @@ import { BaseLink } from "#core/base-link"; import { db } from "#core/db.server"; import { SideBar } from "#core/layout/side-bar"; import { TabBar } from "#core/layout/tab-bar"; +import { useCurrentUserForMonitoring } from "#core/monitoring"; import { Routes } from "#core/navigation"; import { getPageTitle } from "#core/page-title"; import { DropdownSheet } from "#core/popovers/dropdown-sheet"; @@ -50,6 +51,8 @@ export async function loader({ request }: LoaderFunctionArgs) { export default function Route() { const { currentUser } = useLoaderData(); + useCurrentUserForMonitoring(currentUser); + return (
diff --git a/apps/admin/src/routes/animals.$id.pictures.$pictureId.tsx b/apps/admin/src/routes/animals.$id.pictures.$pictureId.tsx index e02f3c18..b46d9cfa 100644 --- a/apps/admin/src/routes/animals.$id.pictures.$pictureId.tsx +++ b/apps/admin/src/routes/animals.$id.pictures.$pictureId.tsx @@ -7,6 +7,7 @@ import { DynamicImage } from "#core/data-display/image"; import { db } from "#core/db.server"; import type { RouteHandle } from "#core/handles"; import { assertIsDefined } from "#core/is-defined.server"; +import { useCurrentUserForMonitoring } from "#core/monitoring"; import { Routes } from "#core/navigation"; import { getPageTitle } from "#core/page-title"; import { prisma } from "#core/prisma.server"; @@ -32,7 +33,7 @@ const ParamsSchema = zu.object({ export async function loader({ request, params }: LoaderFunctionArgs) { const currentUser = await db.currentUser.get(request, { - select: { groups: true }, + select: { displayName: true, email: true, groups: true, id: true }, }); assertCurrentUserHasGroups(currentUser, [ @@ -65,7 +66,11 @@ export async function loader({ request, params }: LoaderFunctionArgs) { throw notFound(); } - return json({ animal, visiblePictureId: paramsResult.data.pictureId }); + return json({ + currentUser, + animal, + visiblePictureId: paramsResult.data.pictureId, + }); } export const meta: MetaFunction = ({ data }) => { @@ -78,7 +83,11 @@ export const meta: MetaFunction = ({ data }) => { }; export default function Route() { - const { animal, visiblePictureId } = useLoaderData(); + const { currentUser, animal, visiblePictureId } = + useLoaderData(); + + useCurrentUserForMonitoring(currentUser); + const allPictures = getAllAnimalPictures(animal); const visiblePictureIndex = allPictures.indexOf(visiblePictureId); diff --git a/apps/admin/src/routes/define-password.tsx b/apps/admin/src/routes/define-password.tsx index bbedbf61..f8fc1051 100644 --- a/apps/admin/src/routes/define-password.tsx +++ b/apps/admin/src/routes/define-password.tsx @@ -5,6 +5,7 @@ import { Form } from "#core/form-elements/form"; import { PasswordInput } from "#core/form-elements/password-input"; import type { RouteHandle } from "#core/handles"; import { AuthPage } from "#core/layout/auth-page"; +import { useCurrentUserForMonitoring } from "#core/monitoring"; import { Routes } from "#core/navigation"; import { getPageTitle } from "#core/page-title"; import { NextSearchParams } from "#core/search-params"; @@ -18,7 +19,7 @@ import type { MetaFunction, } from "@remix-run/node"; import { json, redirect } from "@remix-run/node"; -import { useFetcher } from "@remix-run/react"; +import { useFetcher, useLoaderData } from "@remix-run/react"; import { useEffect, useRef } from "react"; export const handle: RouteHandle = { @@ -28,7 +29,15 @@ export const handle: RouteHandle = { export async function loader({ request }: LoaderFunctionArgs) { const currentUser = await db.currentUser.get( request, - { select: { shouldChangePassword: true } }, + { + select: { + displayName: true, + email: true, + groups: true, + id: true, + shouldChangePassword: true, + }, + }, { skipPasswordChangeCheck: true }, ); @@ -40,7 +49,7 @@ export async function loader({ request }: LoaderFunctionArgs) { throw redirect(next); } - return null; + return json({ currentUser }); } export const meta: MetaFunction = () => { @@ -75,6 +84,10 @@ export async function action({ request }: ActionFunctionArgs) { } export default function Route() { + const { currentUser } = useLoaderData(); + + useCurrentUserForMonitoring(currentUser); + const fetcher = useFetcher(); const passwordRef = useRef(null); diff --git a/apps/admin/src/routes/downloads.animals.tsx b/apps/admin/src/routes/downloads.animals.tsx index 3cb3d6ec..2bd1c9fb 100644 --- a/apps/admin/src/routes/downloads.animals.tsx +++ b/apps/admin/src/routes/downloads.animals.tsx @@ -11,6 +11,7 @@ import { BaseImage, createCloudinaryUrl } from "#core/data-display/image"; import { db } from "#core/db.server"; import type { RouteHandle } from "#core/handles"; import { Spinner } from "#core/loaders/spinner"; +import { useCurrentUserForMonitoring } from "#core/monitoring"; import { getPageTitle } from "#core/page-title"; import { prisma } from "#core/prisma.server"; import { assertCurrentUserHasGroups } from "#current-user/groups.server"; @@ -37,7 +38,7 @@ const MAX_ANIMAL_COUNT = MAX_ITEM_PER_PAGES * MAX_PAGES; export async function loader({ request }: LoaderFunctionArgs) { const currentUser = await db.currentUser.get(request, { - select: { id: true, groups: true }, + select: { displayName: true, email: true, groups: true, id: true }, }); assertCurrentUserHasGroups(currentUser, [UserGroup.ADMIN]); @@ -65,6 +66,7 @@ export async function loader({ request }: LoaderFunctionArgs) { }); return defer({ + currentUser, totalCount: await totalCount, animals: fromPrismaPromise(animals), }); @@ -75,7 +77,9 @@ export const meta: MetaFunction = () => { }; export default function Route() { - const { animals, totalCount } = useLoaderData(); + const { currentUser, animals, totalCount } = useLoaderData(); + + useCurrentUserForMonitoring(currentUser); return (
diff --git a/apps/admin/src/routes/login.tsx b/apps/admin/src/routes/login.tsx index 388f8203..55591f50 100644 --- a/apps/admin/src/routes/login.tsx +++ b/apps/admin/src/routes/login.tsx @@ -5,6 +5,7 @@ import { Input } from "#core/form-elements/input"; import { PasswordInput } from "#core/form-elements/password-input"; import type { RouteHandle } from "#core/handles"; import { AuthPage } from "#core/layout/auth-page"; +import { useCurrentUserForMonitoring } from "#core/monitoring"; import { Routes } from "#core/navigation"; import { getPageTitle } from "#core/page-title"; import { NextSearchParams } from "#core/search-params"; @@ -97,6 +98,8 @@ export async function action({ request }: ActionFunctionArgs) { } export default function Route() { + useCurrentUserForMonitoring(null); + const fetcher = useFetcher(); const emailRef = useRef(null); const passwordRef = useRef(null); diff --git a/apps/admin/src/types.d.ts b/apps/admin/src/types.d.ts index 91907063..e0ca3410 100644 --- a/apps/admin/src/types.d.ts +++ b/apps/admin/src/types.d.ts @@ -14,7 +14,6 @@ declare global { DATABASE_URL?: string; ENABLE_CRONS?: "true" | "false"; PUBLIC_HOST?: string; - RUNTIME_ENV?: "local" | "staging" | "production"; SESSION_SECRET?: string; SHOW_NOTIFICATION_ENDPOINT?: string; } diff --git a/apps/admin/tsconfig.server.json b/apps/admin/tsconfig.server.json new file mode 100644 index 00000000..cb5461c3 --- /dev/null +++ b/apps/admin/tsconfig.server.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.base.json", + "files": ["./server.ts"], + "exclude": ["./node_modules"], + + "compilerOptions": { + // Transpiling with TypeScript. + "module": "ESNext", + "moduleResolution": "node", + "noEmit": false + } +} diff --git a/apps/admin/vite.config.ts b/apps/admin/vite.config.ts index e984e220..c30fa499 100644 --- a/apps/admin/vite.config.ts +++ b/apps/admin/vite.config.ts @@ -1,12 +1,23 @@ import { vitePlugin as remix } from "@remix-run/dev"; -import { installGlobals } from "@remix-run/node"; +import { sentryVitePlugin } from "@sentry/vite-plugin"; import { createRequire } from "node:module"; import type { Plugin } from "vite"; import { defineConfig } from "vite"; import tsconfigPaths from "vite-tsconfig-paths"; -// Install the web fetch globals for Node. -installGlobals(); +const shouldCreateSentryRelease = process.env.SENTRY_AUTH_TOKEN != null; + +if (shouldCreateSentryRelease) { + console.log( + "A new Sentry release we be created:", + `admin-${process.env.APPLICATION_VERSION}`, + ); +} else { + console.log( + "Not creating a new Sentry release for:", + `admin-${process.env.APPLICATION_VERSION}`, + ); +} export default defineConfig({ cacheDir: "./node_modules/.cache/vite", @@ -27,7 +38,28 @@ export default defineConfig({ tsconfigPaths(), prismaClient(), + + shouldCreateSentryRelease + ? sentryVitePlugin({ + org: "animeaux", + project: "admin", + authToken: process.env.SENTRY_AUTH_TOKEN, + release: { + // Prefix release as they're global per organization. + // https://docs.sentry.io/platforms/javascript/guides/remix/configuration/releases/#bind-the-version + name: `admin-${process.env.APPLICATION_VERSION}`, + inject: true, + }, + sourcemaps: { + filesToDeleteAfterUpload: ["./build/**/*.map"], + }, + }) + : null, ], + + build: { + sourcemap: shouldCreateSentryRelease, + }, }); /** diff --git a/apps/show/src/core/monitoring.client.ts b/apps/show/src/core/monitoring.client.ts index b4d69611..11e60905 100644 --- a/apps/show/src/core/monitoring.client.ts +++ b/apps/show/src/core/monitoring.client.ts @@ -1,5 +1,9 @@ import { useLocation, useMatches } from "@remix-run/react"; -import { browserTracingIntegration, init } from "@sentry/remix"; +import { + browserTracingIntegration, + httpClientIntegration, + init, +} from "@sentry/remix"; import { useEffect } from "react"; export function initMonitoring() { @@ -13,7 +17,11 @@ export function initMonitoring() { environment: CLIENT_ENV.RUNTIME_ENV, tracesSampleRate: Number(CLIENT_ENV.SENTRY_TRACES_SAMPLE_RATE ?? 0), integrations: [ + // https://docs.sentry.io/platforms/javascript/guides/remix/configuration/integrations/browsertracing browserTracingIntegration({ useEffect, useLocation, useMatches }), + + // https://docs.sentry.io/platforms/javascript/guides/remix/configuration/integrations/httpclient + httpClientIntegration(), ], }); } diff --git a/yarn.lock b/yarn.lock index ca734c72..22320abf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -158,6 +158,15 @@ dependencies: "@babel/highlight" "^7.22.5" +"@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.2": + version "7.26.2" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" + integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== + dependencies: + "@babel/helper-validator-identifier" "^7.25.9" + js-tokens "^4.0.0" + picocolors "^1.0.0" + "@babel/compat-data@^7.20.5": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.21.0.tgz#c241dc454e5b5917e40d37e525e2f4530c399298" @@ -168,6 +177,32 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.6.tgz#15606a20341de59ba02cd2fcc5086fcbe73bf544" integrity sha512-29tfsWTq2Ftu7MXmimyC0C5FDZv5DYxOZkh3XD3+QW4V/BYuv/LyEsjj3c0hqedEaDt6DBfDvexMKU8YevdqFg== +"@babel/compat-data@^7.26.5": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.5.tgz#df93ac37f4417854130e21d72c66ff3d4b897fc7" + integrity sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg== + +"@babel/core@^7.18.5": + version "7.26.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.7.tgz#0439347a183b97534d52811144d763a17f9d2b24" + integrity sha512-SRijHmF0PSPgLIBYlWnG0hyeJLwXE2CgpsXaMOrtt2yp9/86ALw6oUlj9KYuZ0JN07T4eBMVIW4li/9S1j2BGA== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.26.2" + "@babel/generator" "^7.26.5" + "@babel/helper-compilation-targets" "^7.26.5" + "@babel/helper-module-transforms" "^7.26.0" + "@babel/helpers" "^7.26.7" + "@babel/parser" "^7.26.7" + "@babel/template" "^7.25.9" + "@babel/traverse" "^7.26.7" + "@babel/types" "^7.26.7" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + "@babel/core@^7.20.7": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.0.tgz#1341aefdcc14ccc7553fcc688dd8986a2daffc13" @@ -249,6 +284,17 @@ "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" +"@babel/generator@^7.26.5": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.5.tgz#e44d4ab3176bbcaf78a5725da5f1dc28802a9458" + integrity sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw== + dependencies: + "@babel/parser" "^7.26.5" + "@babel/types" "^7.26.5" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^3.0.2" + "@babel/helper-annotate-as-pure@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb" @@ -285,6 +331,17 @@ browserslist "^4.21.9" lru-cache "^5.1.1" +"@babel/helper-compilation-targets@^7.26.5": + version "7.26.5" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz#75d92bb8d8d51301c0d49e52a65c9a7fe94514d8" + integrity sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA== + dependencies: + "@babel/compat-data" "^7.26.5" + "@babel/helper-validator-option" "^7.25.9" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + "@babel/helper-create-class-features-plugin@^7.22.5": version "7.22.6" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.6.tgz#58564873c889a6fea05a538e23f9f6d201f10950" @@ -374,6 +431,14 @@ dependencies: "@babel/types" "^7.22.5" +"@babel/helper-module-imports@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz#e7f8d20602ebdbf9ebbea0a0751fb0f2a4141715" + integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw== + dependencies: + "@babel/traverse" "^7.25.9" + "@babel/types" "^7.25.9" + "@babel/helper-module-transforms@^7.21.0": version "7.21.2" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz#160caafa4978ac8c00ac66636cb0fa37b024e2d2" @@ -402,6 +467,15 @@ "@babel/traverse" "^7.22.5" "@babel/types" "^7.22.5" +"@babel/helper-module-transforms@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz#8ce54ec9d592695e58d84cd884b7b5c6a2fdeeae" + integrity sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw== + dependencies: + "@babel/helper-module-imports" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@babel/traverse" "^7.25.9" + "@babel/helper-optimise-call-expression@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz#f21531a9ccbff644fdd156b4077c16ff0c3f609e" @@ -481,6 +555,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== +"@babel/helper-string-parser@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" + integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== + "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": version "7.19.1" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" @@ -496,6 +575,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== +"@babel/helper-validator-identifier@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== + "@babel/helper-validator-option@^7.18.6": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz#8224c7e13ace4bafdc4004da2cf064ef42673180" @@ -506,6 +590,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac" integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw== +"@babel/helper-validator-option@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72" + integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw== + "@babel/helpers@^7.21.0": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.21.0.tgz#9dd184fb5599862037917cdc9eecb84577dc4e7e" @@ -524,6 +613,14 @@ "@babel/traverse" "^7.22.6" "@babel/types" "^7.22.5" +"@babel/helpers@^7.26.7": + version "7.26.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.7.tgz#fd1d2a7c431b6e39290277aacfd8367857c576a4" + integrity sha512-8NHiL98vsi0mbPQmYAGWwfcFaOy4j2HY49fXJCfuDcdE7fMIsH9a7GdaeXpIBsbT7307WU8KCMp5pUVDNL4f9A== + dependencies: + "@babel/template" "^7.25.9" + "@babel/types" "^7.26.7" + "@babel/highlight@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" @@ -566,6 +663,13 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b" integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ== +"@babel/parser@^7.25.9", "@babel/parser@^7.26.5", "@babel/parser@^7.26.7": + version "7.26.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.7.tgz#e114cd099e5f7d17b05368678da0fb9f69b3385c" + integrity sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w== + dependencies: + "@babel/types" "^7.26.7" + "@babel/plugin-syntax-decorators@^7.22.10": version "7.23.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.23.3.tgz#a1d351d6c25bfdcf2e16f99b039101bc0ffcb0ca" @@ -717,6 +821,15 @@ "@babel/parser" "^7.22.5" "@babel/types" "^7.22.5" +"@babel/template@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.9.tgz#ecb62d81a8a6f5dc5fe8abfc3901fc52ddf15016" + integrity sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg== + dependencies: + "@babel/code-frame" "^7.25.9" + "@babel/parser" "^7.25.9" + "@babel/types" "^7.25.9" + "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2": version "7.21.2" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.2.tgz#ac7e1f27658750892e815e60ae90f382a46d8e75" @@ -765,6 +878,19 @@ debug "^4.3.1" globals "^11.1.0" +"@babel/traverse@^7.25.9", "@babel/traverse@^7.26.7": + version "7.26.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.7.tgz#99a0a136f6a75e7fb8b0a1ace421e0b25994b8bb" + integrity sha512-1x1sgeyRLC3r5fQOM0/xtQKsYjyxmFjaOrLJNtZ81inNjyJHGIolTULPiSc/2qe1/qfpFLisLQYFnnZl7QoedA== + dependencies: + "@babel/code-frame" "^7.26.2" + "@babel/generator" "^7.26.5" + "@babel/parser" "^7.26.7" + "@babel/template" "^7.25.9" + "@babel/types" "^7.26.7" + debug "^4.3.1" + globals "^11.1.0" + "@babel/types@^7.18.6", "@babel/types@^7.20.2", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2": version "7.21.2" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.2.tgz#92246f6e00f91755893c2876ad653db70c8310d1" @@ -792,6 +918,14 @@ "@babel/helper-validator-identifier" "^7.22.5" to-fast-properties "^2.0.0" +"@babel/types@^7.25.9", "@babel/types@^7.26.5", "@babel/types@^7.26.7": + version "7.26.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.7.tgz#5e2b89c0768e874d4d061961f3a5a153d71dc17a" + integrity sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg== + dependencies: + "@babel/helper-string-parser" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@bundled-es-modules/cookie@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@bundled-es-modules/cookie/-/cookie-2.0.0.tgz#c3b82703969a61cf6a46e959a012b2c257f6b164" @@ -1324,6 +1458,15 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.24" +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.8" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" + integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + "@jridgewell/resolve-uri@3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" @@ -1354,6 +1497,11 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== +"@jridgewell/sourcemap-codec@^1.4.15": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + "@jridgewell/trace-mapping@^0.3.17": version "0.3.17" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" @@ -1362,7 +1510,7 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" -"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.9": +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25", "@jridgewell/trace-mapping@^0.3.9": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== @@ -2828,6 +2976,11 @@ "@sentry/types" "8.37.1" "@sentry/utils" "8.37.1" +"@sentry/babel-plugin-component-annotate@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-3.1.1.tgz#a10f63d642095ffabb42dd30898e3303e2c8c762" + integrity sha512-gp6lFDhrpuVQSQ+N7zKCMJOyYkYoUs4AQlNQctZMRCpp6URGy+eGj5YDPdMNCFylVs8M6t1C6gbBqzrd5sz9Pg== + "@sentry/browser@8.37.1": version "8.37.1" resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-8.37.1.tgz#2e6e4accc395ad9e6313e07b09415370c71e5874" @@ -2841,41 +2994,109 @@ "@sentry/types" "8.37.1" "@sentry/utils" "8.37.1" +"@sentry/bundler-plugin-core@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@sentry/bundler-plugin-core/-/bundler-plugin-core-3.1.1.tgz#330be53ac6e64b93b0d2e8f301612fc0cecb5b30" + integrity sha512-FlYucOSGyujmhA5e1eDhwk+OmuM2RO9yljoBMjEFxtX6gIRioolmPvVa+8FowBMEd594KHPt9MyjOuAwsVIXwg== + dependencies: + "@babel/core" "^7.18.5" + "@sentry/babel-plugin-component-annotate" "3.1.1" + "@sentry/cli" "2.39.1" + dotenv "^16.3.1" + find-up "^5.0.0" + glob "^9.3.2" + magic-string "0.30.8" + unplugin "1.0.1" + "@sentry/cli-darwin@2.38.2": version "2.38.2" resolved "https://registry.yarnpkg.com/@sentry/cli-darwin/-/cli-darwin-2.38.2.tgz#2a53028e143d0cfed607588b87e04906ef5317e7" integrity sha512-21ywIcJCCFrCTyiF1o1PaT7rbelFC2fWmayKYgFElnQ55IzNYkcn8BYhbh/QknE0l1NBRaeWMXwTTdeoqETCCg== +"@sentry/cli-darwin@2.39.1": + version "2.39.1" + resolved "https://registry.yarnpkg.com/@sentry/cli-darwin/-/cli-darwin-2.39.1.tgz#75c338a53834b4cf72f57599f4c72ffb36cf0781" + integrity sha512-kiNGNSAkg46LNGatfNH5tfsmI/kCAaPA62KQuFZloZiemTNzhy9/6NJP8HZ/GxGs8GDMxic6wNrV9CkVEgFLJQ== + "@sentry/cli-linux-arm64@2.38.2": version "2.38.2" resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.38.2.tgz#1b45de7e4f5e1a953b88b0b811d789de1fc708aa" integrity sha512-4Fp/jjQpNZj4Th+ZckMQvldAuuP0ZcyJ9tJCP1CCOn5poIKPYtY6zcbTP036R7Te14PS4ALOcDNX3VNKfpsifA== +"@sentry/cli-linux-arm64@2.39.1": + version "2.39.1" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.39.1.tgz#27db44700c33fcb1e8966257020b43f8494373e6" + integrity sha512-5VbVJDatolDrWOgaffsEM7znjs0cR8bHt9Bq0mStM3tBolgAeSDHE89NgHggfZR+DJ2VWOy4vgCwkObrUD6NQw== + "@sentry/cli-linux-arm@2.38.2": version "2.38.2" resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm/-/cli-linux-arm-2.38.2.tgz#91f73c251f1d4b591fa98af10ee3889c9b93d208" integrity sha512-+AiKDBQKIdQe4NhBiHSHGl0KR+b//HHTrnfK1SaTrOm9HtM4ELXAkjkRF3bmbpSzSQCS5WzcbIxxCJOeaUaO0A== +"@sentry/cli-linux-arm@2.39.1": + version "2.39.1" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm/-/cli-linux-arm-2.39.1.tgz#451683fa9a5a60b1359d104ec71334ed16f4b63c" + integrity sha512-DkENbxyRxUrfLnJLXTA4s5UL/GoctU5Cm4ER1eB7XN7p9WsamFJd/yf2KpltkjEyiTuplv0yAbdjl1KX3vKmEQ== + "@sentry/cli-linux-i686@2.38.2": version "2.38.2" resolved "https://registry.yarnpkg.com/@sentry/cli-linux-i686/-/cli-linux-i686-2.38.2.tgz#26e30a9bc358f910e21d812359294dd4c6103fda" integrity sha512-6zVJN10dHIn4R1v+fxuzlblzVBhIVwsaN/S7aBED6Vn1HhAyAcNG2tIzeCLGeDfieYjXlE2sCI82sZkQBCbAGw== +"@sentry/cli-linux-i686@2.39.1": + version "2.39.1" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-i686/-/cli-linux-i686-2.39.1.tgz#9965a81f97a94e8b6d1d15589e43fee158e35201" + integrity sha512-pXWVoKXCRrY7N8vc9H7mETiV9ZCz+zSnX65JQCzZxgYrayQPJTc+NPRnZTdYdk5RlAupXaFicBI2GwOCRqVRkg== + "@sentry/cli-linux-x64@2.38.2": version "2.38.2" resolved "https://registry.yarnpkg.com/@sentry/cli-linux-x64/-/cli-linux-x64-2.38.2.tgz#18728bbb20e28315c4368baded677786f2dba70a" integrity sha512-4UiLu9zdVtqPeltELR5MDGKcuqAdQY9xz3emISuA6bm+MXGbt2W1WgX+XY3GElwjZbmH8qpyLUEd34sw6sdcbQ== +"@sentry/cli-linux-x64@2.39.1": + version "2.39.1" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-x64/-/cli-linux-x64-2.39.1.tgz#31fe008b02f92769543dc9919e2a5cbc4cda7889" + integrity sha512-IwayNZy+it7FWG4M9LayyUmG1a/8kT9+/IEm67sT5+7dkMIMcpmHDqL8rWcPojOXuTKaOBBjkVdNMBTXy0mXlA== + "@sentry/cli-win32-i686@2.38.2": version "2.38.2" resolved "https://registry.yarnpkg.com/@sentry/cli-win32-i686/-/cli-win32-i686-2.38.2.tgz#dfe268b041c3e3db556290dba745455d0b2c0d72" integrity sha512-DYfSvd5qLPerLpIxj3Xu2rRe3CIlpGOOfGSNI6xvJ5D8j6hqbOHlCzvfC4oBWYVYGtxnwQLMeDGJ7o7RMYulig== +"@sentry/cli-win32-i686@2.39.1": + version "2.39.1" + resolved "https://registry.yarnpkg.com/@sentry/cli-win32-i686/-/cli-win32-i686-2.39.1.tgz#609e8790c49414011445e397130560c777850b35" + integrity sha512-NglnNoqHSmE+Dz/wHeIVRnV2bLMx7tIn3IQ8vXGO5HWA2f8zYJGktbkLq1Lg23PaQmeZLPGlja3gBQfZYSG10Q== + "@sentry/cli-win32-x64@2.38.2": version "2.38.2" resolved "https://registry.yarnpkg.com/@sentry/cli-win32-x64/-/cli-win32-x64-2.38.2.tgz#e7b5744026ff5f7e84971512bee228620ba5857d" integrity sha512-W5UX58PKY1hNUHo9YJxWNhGvgvv2uOYHI27KchRiUvFYBIqlUUcIdPZDfyzetDfd8qBCxlAsFnkL2VJSNdpA9A== +"@sentry/cli-win32-x64@2.39.1": + version "2.39.1" + resolved "https://registry.yarnpkg.com/@sentry/cli-win32-x64/-/cli-win32-x64-2.39.1.tgz#1a874a5570c6d162b35d9d001c96e5389d07d2cb" + integrity sha512-xv0R2CMf/X1Fte3cMWie1NXuHmUyQPDBfCyIt6k6RPFPxAYUgcqgMPznYwVMwWEA1W43PaOkSn3d8ZylsDaETw== + +"@sentry/cli@2.39.1": + version "2.39.1" + resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.39.1.tgz#916bb5b7567ccf7fdf94ef6cf8a2b9ab78370d29" + integrity sha512-JIb3e9vh0+OmQ0KxmexMXg9oZsR/G7HMwxt5BUIKAXZ9m17Xll4ETXTRnRUBT3sf7EpNGAmlQk1xEmVN9pYZYQ== + dependencies: + https-proxy-agent "^5.0.0" + node-fetch "^2.6.7" + progress "^2.0.3" + proxy-from-env "^1.1.0" + which "^2.0.2" + optionalDependencies: + "@sentry/cli-darwin" "2.39.1" + "@sentry/cli-linux-arm" "2.39.1" + "@sentry/cli-linux-arm64" "2.39.1" + "@sentry/cli-linux-i686" "2.39.1" + "@sentry/cli-linux-x64" "2.39.1" + "@sentry/cli-win32-i686" "2.39.1" + "@sentry/cli-win32-x64" "2.39.1" + "@sentry/cli@^2.37.0": version "2.38.2" resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.38.2.tgz#e9a7a9bbeaaade4557de91704d50d131760345d3" @@ -2993,6 +3214,14 @@ dependencies: "@sentry/types" "8.37.1" +"@sentry/vite-plugin@^3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@sentry/vite-plugin/-/vite-plugin-3.1.1.tgz#e66f5f9f1a6df2209f0afc4584b890b289ce2e6b" + integrity sha512-Vdh9twaTT1KTzG92YzGtsLpjydAmU3PSgH/4FEJrwAfT+Tr31qo3eHeagw27jrJduzM8SK1t/t6A/DH3FrtC5g== + dependencies: + "@sentry/bundler-plugin-core" "3.1.1" + unplugin "1.0.1" + "@tailwindcss/container-queries@^0.1.1": version "0.1.1" resolved "https://registry.yarnpkg.com/@tailwindcss/container-queries/-/container-queries-0.1.1.tgz#9a759ce2cb8736a4c6a0cb93aeb740573a731974" @@ -3673,6 +3902,11 @@ acorn@^8.0.0, acorn@^8.8.2: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== +acorn@^8.8.1: + version "8.14.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" + integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== + acorn@^8.9.0: version "8.11.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" @@ -4111,6 +4345,16 @@ browserslist@^4.23.0: node-releases "^2.0.14" update-browserslist-db "^1.0.13" +browserslist@^4.24.0: + version "4.24.4" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.4.tgz#c6b2865a3f08bcb860a0e827389003b9fe686e4b" + integrity sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A== + dependencies: + caniuse-lite "^1.0.30001688" + electron-to-chromium "^1.5.73" + node-releases "^2.0.19" + update-browserslist-db "^1.1.1" + buffer-equal-constant-time@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" @@ -4237,6 +4481,11 @@ caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001503, caniuse-lite@^1.0.300015 resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz" integrity sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA== +caniuse-lite@^1.0.30001688: + version "1.0.30001696" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001696.tgz#00c30a2fc11e3c98c25e5125418752af3ae2f49f" + integrity sha512-pDCPkvzfa39ehJtJ+OwGT/2yvT2SbjfHhiIW2LWOAcMQ7BzwxT/XuyUp4OTOd0XFWA6BKw0JalnBHgSi5DGJBQ== + ccount@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5" @@ -4543,6 +4792,11 @@ convert-source-map@^1.7.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" @@ -4970,6 +5224,11 @@ dotenv@^16.0.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07" integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ== +dotenv@^16.3.1: + version "16.4.7" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.7.tgz#0e20c5b82950140aa99be360a8a5f52335f53c26" + integrity sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ== + downshift@^9.0.6: version "9.0.6" resolved "https://registry.yarnpkg.com/downshift/-/downshift-9.0.6.tgz#a842e59741ac5e789e80be852609a2738b85e85f" @@ -5042,6 +5301,11 @@ electron-to-chromium@^1.4.668: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.788.tgz#a3545959d5cfa0a266d3e551386c040be34e7e06" integrity sha512-ubp5+Ev/VV8KuRoWnfP2QF2Bg+O2ZFdb49DiiNbz2VmgkIqrnyYaqIOqj8A6K/3p1xV0QcU5hBQ1+BmB6ot1OA== +electron-to-chromium@^1.5.73: + version "1.5.90" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.90.tgz#4717e5a5413f95bbb12d0af14c35057e9c65e0b6" + integrity sha512-C3PN4aydfW91Natdyd449Kw+BzhLmof6tzy5W1pFC5SpQxVXT+oyiyOG9AgYYSN9OdA/ik3YkCrpwqI8ug5Tug== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -5315,6 +5579,11 @@ escalade@^3.1.1, escalade@^3.1.2: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -6214,6 +6483,16 @@ glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^9.3.2: + version "9.3.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-9.3.5.tgz#ca2ed8ca452781a3009685607fdf025a899dfe21" + integrity sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q== + dependencies: + fs.realpath "^1.0.0" + minimatch "^8.0.2" + minipass "^4.2.4" + path-scurry "^1.6.1" + globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" @@ -7174,6 +7453,11 @@ jsesc@^2.5.1: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + json-bigint@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-1.0.0.tgz#ae547823ac0cad8398667f8cd9ef4730f5b01ff1" @@ -7218,7 +7502,7 @@ json5@^1.0.2: dependencies: minimist "^1.2.0" -json5@^2.2.2: +json5@^2.2.2, json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== @@ -7465,6 +7749,13 @@ lz-string@^1.4.4: resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" integrity sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ== +magic-string@0.30.8: + version "0.30.8" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.8.tgz#14e8624246d2bedba70d5462aa99ac9681844613" + integrity sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.15" + make-fetch-happen@^13.0.0: version "13.0.1" resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz#273ba2f78f45e1f3a6dca91cede87d9fa4821e36" @@ -8561,6 +8852,13 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^8.0.2: + version "8.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-8.0.4.tgz#847c1b25c014d4e9a7f68aaf63dedd668a626229" + integrity sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA== + dependencies: + brace-expansion "^2.0.1" + minimatch@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.0.tgz#bfc8e88a1c40ffd40c172ddac3decb8451503b56" @@ -8633,6 +8931,11 @@ minipass@^3.0.0: dependencies: yallist "^4.0.0" +minipass@^4.2.4: + version "4.2.8" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a" + integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ== + minipass@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" @@ -8859,6 +9162,11 @@ node-releases@^2.0.14: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +node-releases@^2.0.19: + version "2.0.19" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" + integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== + node-releases@^2.0.8: version "2.0.10" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f" @@ -9304,7 +9612,7 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.11.1: +path-scurry@^1.11.1, path-scurry@^1.6.1: version "1.11.1" resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== @@ -9448,6 +9756,11 @@ picocolors@^1.0.0, picocolors@^1.0.1: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -10573,6 +10886,11 @@ semver@^6.1.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + semver@^7.0.0, semver@^7.1.1, semver@^7.5.3, semver@~7.5.0, semver@~7.5.4: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" @@ -11582,6 +11900,16 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== +unplugin@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.0.1.tgz#83b528b981cdcea1cad422a12cd02e695195ef3f" + integrity sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA== + dependencies: + acorn "^8.8.1" + chokidar "^3.5.3" + webpack-sources "^3.2.3" + webpack-virtual-modules "^0.5.0" + update-browserslist-db@^1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" @@ -11598,6 +11926,14 @@ update-browserslist-db@^1.0.11, update-browserslist-db@^1.0.13: escalade "^3.1.2" picocolors "^1.0.1" +update-browserslist-db@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz#97e9c96ab0ae7bcac08e9ae5151d26e6bc6b5580" + integrity sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -11838,6 +12174,16 @@ webidl-conversions@^7.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack-virtual-modules@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.5.0.tgz#362f14738a56dae107937ab98ea7062e8bdd3b6c" + integrity sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw== + whatwg-encoding@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz#d0f4ef769905d426e1688f3e34381a99b60b76e5"