diff --git a/.env.example b/.env.example index 84bd766f6..6773227c8 100644 --- a/.env.example +++ b/.env.example @@ -11,3 +11,10 @@ MAPTILER_API_KEY=123 # SEO PREVENT_SEARCH_BOTS=false + +# CSP +# Set to "true" to emit Content-Security-Policy-Report-Only instead of the +# enforcing header. Useful when rolling out tighter CSP changes — violations +# are reported to the browser console but not blocked. Leave unset in normal +# operation. +CSP_REPORT_ONLY=false diff --git a/CHANGELOG.md b/CHANGELOG.md index 06b62e8b9..7a89cbf45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,9 @@ You can also check the - Incorporate the Swiss-Federal-CI library into this repository. - Fixes - Sanitize urls for links in tables + - Improve CSP header configuration - Maintenance + - Remove Google Analytics integration (it is no longer in use) - Set Maptiler API key from `MAPTILER_API_KEY` environment variable at runtime, to avoid having to rebuild the application when the key is rotated - Use AGENTS.md instead of CLAUDE.md and adjust context according to recent @@ -1438,7 +1440,6 @@ visualize.admin.ch are now noticeable faster. #### Performance - Improved performance of cube data fetching - - Added LRU cache to min max queries - Added query cache to bulk queries - Ordered filter so that non-discriminant filter are last diff --git a/app/domain/env.ts b/app/domain/env.ts index f204edbe6..414948e4f 100644 --- a/app/domain/env.ts +++ b/app/domain/env.ts @@ -42,9 +42,6 @@ export const SQL_ENDPOINT = export const GRAPHQL_ENDPOINT = clientEnv?.GRAPHQL_ENDPOINT ?? process.env.GRAPHQL_ENDPOINT ?? "/api/graphql"; -export const GA_TRACKING_ID = - clientEnv?.GA_TRACKING_ID ?? process.env.GA_TRACKING_ID; - export const ADFS_PROFILE_URL = clientEnv?.ADFS_PROFILE_URL ?? process.env.ADFS_PROFILE_URL; diff --git a/app/next.config.js b/app/next.config.js index 80c1a9904..27a8fe5c5 100644 --- a/app/next.config.js +++ b/app/next.config.js @@ -39,128 +39,176 @@ if (process.env.NEXT_PUBLIC_SENTRY_DSN) { console.log("Sentry DSN:", process.env.NEXT_PUBLIC_SENTRY_DSN); } -module.exports = withSentryConfig(withPreconstruct( - withBundleAnalyzer( - withMDX({ - output: "standalone", - i18n: { - locales, - defaultLocale, - }, - - experimental: { - instrumentationHook: true, - }, - - headers: async () => { - const headers = []; - - headers.push({ - source: "/:path*", - headers: [ - { - key: "X-Content-Type-Options", - value: "nosniff", - }, - ], - }); - - // See https://content-security-policy.com/ & https://developers.google.com/tag-platform/security/guides/csp - if (!(process.env.DISABLE_CSP && process.env.DISABLE_CSP === "true")) { - const sentryCSP = process.env.NEXT_PUBLIC_SENTRY_CSP ? ` ${process.env.NEXT_PUBLIC_SENTRY_CSP}` : ""; - headers[0].headers.push({ - key: "Content-Security-Policy", - value: [ - `default-src 'self' 'unsafe-inline'${process.env.NODE_ENV === "development" ? " 'unsafe-eval'" : "" - }${sentryCSP} https://vercel.live/ https://vercel.com https://*.googletagmanager.com`, - `script-src 'self' 'unsafe-inline'${process.env.NODE_ENV === "development" ? " 'unsafe-eval'" : "" - }${sentryCSP} https://vercel.live/ https://vercel.com https://*.googletagmanager.com https://api.mapbox.com https://api.maptiler.com`, - `style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net`, +module.exports = withSentryConfig( + withPreconstruct( + withBundleAnalyzer( + withMDX({ + output: "standalone", + i18n: { + locales, + defaultLocale, + }, + + experimental: { + instrumentationHook: true, + }, + + headers: async () => { + // See https://content-security-policy.com/ & https://developers.google.com/tag-platform/security/guides/csp + const isDev = process.env.NODE_ENV === "development"; + const isVercel = !!process.env.VERCEL; + const sentryCSP = process.env.NEXT_PUBLIC_SENTRY_CSP + ? ` ${process.env.NEXT_PUBLIC_SENTRY_CSP}` + : ""; + const unsafeEval = isDev ? " 'unsafe-eval'" : ""; + // Vercel Toolbar / Live Comments hosts — only needed on Vercel deployments + const vercelDefault = isVercel + ? " https://vercel.live/ https://vercel.com" + : ""; + const vercelScript = isVercel + ? " https://vercel.live/ https://vercel.com" + : ""; + const vercelScriptElem = isVercel + ? " https://vercel.live https://vercel.com https://*.vercel.app" + : ""; + const vercelWorker = isVercel ? " https://*.vercel.app" : ""; + + const buildCSP = (frameAncestors) => + [ + `default-src 'self' 'unsafe-inline'${unsafeEval}${sentryCSP}${vercelDefault}`, + `script-src 'self' 'unsafe-inline'${unsafeEval}${sentryCSP}${vercelScript} https://api.mapbox.com https://api.maptiler.com`, + `script-src-elem 'self' 'unsafe-inline' https://*.admin.ch https://visualize.admin.ch https://*.visualize.admin.ch${vercelScriptElem} https://api.mapbox.com`, + `style-src 'self' 'unsafe-inline' https://fonts.googleapis.com`, `font-src 'self'`, - `form-action 'self'`, + + // * to allow loading legend images from custom WMS / WMTS endpoints and data: to allow downloading images + `img-src 'self' * data: blob:`, // * to allow WMS / WMTS endpoints `connect-src 'self' *`, - // * to allow loading legend images from custom WMS / WMTS endpoints and data: to allow downloading images - `img-src 'self' * data: blob:`, - `script-src-elem 'self' 'unsafe-inline' https://*.admin.ch https://visualize.admin.ch https://*.visualize.admin.ch https://vercel.live https://vercel.com https://*.vercel.app https://*.google-analytics.com https://*.analytics.google.com https://*.googletagmanager.com https://api.mapbox.com https://cdn.jsdelivr.net`, - `worker-src 'self' blob: https://*.admin.ch https://*.vercel.app`, - ].join("; "), - }); - } + `worker-src 'self' blob: https://*.admin.ch${vercelWorker}`, + `form-action 'self'`, + `frame-ancestors ${frameAncestors}`, + `object-src 'none'`, + `base-uri 'self'`, + `upgrade-insecure-requests`, + ].join("; "); + + // When CSP_REPORT_ONLY=true, emit the report-only header so violations + // are surfaced to the browser console without being enforced. Useful + // for rolling out tighter policies. The header is otherwise always + // present — there is intentionally no kill-switch to fully disable CSP. + const reportOnly = + process.env.CSP_REPORT_ONLY && + process.env.CSP_REPORT_ONLY === "true"; + const cspKey = reportOnly + ? "Content-Security-Policy-Report-Only" + : "Content-Security-Policy"; + + const baseHeaders = [ + { key: "X-Content-Type-Options", value: "nosniff" }, + ]; + if (process.env.PREVENT_SEARCH_BOTS === "true") { + baseHeaders.push({ + key: "X-Robots-Tag", + value: "noindex, nofollow", + }); + } - if (process.env.PREVENT_SEARCH_BOTS === "true") { - headers[0].headers.push({ - key: "X-Robots-Tag", - value: "noindex, nofollow", + const headers = []; + + // Catch-all — block iframing to prevent clickjacking on the editor / browser / login UI. + // Must come first: when multiple Next.js header rules match the same path, + // later rules override earlier ones for the same header key. + headers.push({ + source: "/:path*", + headers: [ + ...baseHeaders, + { key: cspKey, value: buildCSP("'self'") }, + ], }); - } - - return headers; - }, - - pageExtensions: ["js", "ts", "tsx", "mdx"], - - eslint: { - // Warning: Dangerously allow production builds to successfully complete even if - // your project has ESLint errors. - ignoreDuringBuilds: true, - }, - - webpack (config, { dev }) { - config.module.rules.push({ - test: /\.(graphql|gql)$/, - exclude: /node_modules/, - loader: "graphql-tag/loader", - }); - - /* Enable source maps in production */ - if (!dev) { - config.devtool = "source-map"; - - for (const plugin of config.plugins) { - if (plugin.constructor.name === "UglifyJsPlugin") { - plugin.options.sourceMap = true; - break; - } + + // Routes that are intended to be embedded in third-party iframes. + // These override the catch-all CSP to allow `frame-ancestors *`. + // `/api/embed-aem-ext/*` serves the AEM external-embed HTML wrapper, + // which partner sites may iframe directly. + const embeddableSources = [ + "/embed/:path*", + "/preview", + "/api/embed-aem-ext/:path*", + ]; + for (const source of embeddableSources) { + headers.push({ + source, + headers: [...baseHeaders, { key: cspKey, value: buildCSP("*") }], + }); } - if (config.optimization && config.optimization.minimizer) { - for (const plugin of config.optimization.minimizer) { - if (plugin.constructor.name === "TerserPlugin") { + return headers; + }, + + pageExtensions: ["js", "ts", "tsx", "mdx"], + + eslint: { + // Warning: Dangerously allow production builds to successfully complete even if + // your project has ESLint errors. + ignoreDuringBuilds: true, + }, + + webpack(config, { dev }) { + config.module.rules.push({ + test: /\.(graphql|gql)$/, + exclude: /node_modules/, + loader: "graphql-tag/loader", + }); + + /* Enable source maps in production */ + if (!dev) { + config.devtool = "source-map"; + + for (const plugin of config.plugins) { + if (plugin.constructor.name === "UglifyJsPlugin") { plugin.options.sourceMap = true; break; } } + + if (config.optimization && config.optimization.minimizer) { + for (const plugin of config.optimization.minimizer) { + if (plugin.constructor.name === "TerserPlugin") { + plugin.options.sourceMap = true; + break; + } + } + } } - } - - config.resolve.extensions.push(dev ? ".dev.ts" : ".prod.ts"); - config.resolve.alias = { - ...config.resolve.alias, - "mapbox-gl": "maplibre-gl", - }; - // For some reason these need to be ignored for serverless target - config.plugins.push( - new IgnorePlugin({ resourceRegExp: /^(pg-native|vue)$/ }) - ); - - return config; - }, - - async redirects () { - return [ - { - source: "/storybook", - destination: "/storybook/index.html", - permanent: true, - }, - ]; - }, - }) - ), - { silent: true }, - { hideSourcemaps: true } -)); + config.resolve.extensions.push(dev ? ".dev.ts" : ".prod.ts"); + config.resolve.alias = { + ...config.resolve.alias, + "mapbox-gl": "maplibre-gl", + }; + // For some reason these need to be ignored for serverless target + config.plugins.push( + new IgnorePlugin({ resourceRegExp: /^(pg-native|vue)$/ }) + ); + + return config; + }, + + async redirects() { + return [ + { + source: "/storybook", + destination: "/storybook/index.html", + permanent: true, + }, + ]; + }, + }) + ), + { silent: true }, + { hideSourcemaps: true } + ) +); diff --git a/app/pages/_app.tsx b/app/pages/_app.tsx index 29b6e6dc8..1adacf70b 100644 --- a/app/pages/_app.tsx +++ b/app/pages/_app.tsx @@ -20,10 +20,9 @@ import * as federalTheme from "@/themes/theme"; import { AsyncLocalizationProvider } from "@/utils/async-localization-provider"; import { EventEmitterProvider } from "@/utils/event-emitter"; import { Flashes } from "@/utils/flashes"; -import { analyticsPageView } from "@/utils/google-analytics"; -import "@/utils/nprogress.css"; import { useNProgress } from "@/utils/use-nprogress"; +import "@/utils/nprogress.css"; import "@/configurator/components/color-picker.css"; const GQLDebugPanel = dynamic( @@ -45,12 +44,8 @@ export default function App({ i18n.activate(locale); } - // Initialize analytics + // Activate the right locale on route change useEffect(() => { - const handleRouteChange = (url: string) => { - analyticsPageView(url); - }; - const handleRouteStart = (url: string) => { const locale = parseLocaleString(url.slice(1)); if (i18n.locale !== locale) { @@ -59,10 +54,8 @@ export default function App({ }; routerEvents.on("routeChangeStart", handleRouteStart); - routerEvents.on("routeChangeComplete", handleRouteChange); return () => { routerEvents.off("routeChangeStart", handleRouteStart); - routerEvents.off("routeChangeComplete", handleRouteChange); }; }, [routerEvents]); diff --git a/app/pages/_document.tsx b/app/pages/_document.tsx index 770cf42c1..15a298102 100644 --- a/app/pages/_document.tsx +++ b/app/pages/_document.tsx @@ -1,7 +1,5 @@ import Document, { Head, Html, Main, NextScript } from "next/document"; -import { GA_TRACKING_ID } from "@/domain/env"; - class MyDocument extends Document { render() { return ( @@ -9,19 +7,6 @@ class MyDocument extends Document { {/* eslint-disable-next-line @next/next/no-sync-scripts */} - {GA_TRACKING_ID && ( - <> - - - )}
diff --git a/app/pages/api/client-env.ts b/app/pages/api/client-env.ts index c5c177a23..1bc463af9 100644 --- a/app/pages/api/client-env.ts +++ b/app/pages/api/client-env.ts @@ -13,7 +13,6 @@ export default async function clientEnvApi( case "GET": try { const result = `window.__clientEnv__=${JSON.stringify({ - GA_TRACKING_ID: process.env.GA_TRACKING_ID, ENDPOINT: process.env.ENDPOINT, WHITELISTED_DATA_SOURCES: process.env.WHITELISTED_DATA_SOURCES !== undefined diff --git a/app/pages/embed/[chartId].tsx b/app/pages/embed/[chartId].tsx index 3deefefa7..0f2554353 100644 --- a/app/pages/embed/[chartId].tsx +++ b/app/pages/embed/[chartId].tsx @@ -2,7 +2,6 @@ import { Config as PrismaConfig } from "@prisma/client"; import "iframe-resizer/js/iframeResizer.contentWindow.js"; import { GetServerSideProps } from "next"; import ErrorPage from "next/error"; -import Head from "next/head"; import "@open-iframe-resizer/core"; import { ChartPublished } from "@/components/chart-published"; @@ -62,30 +61,12 @@ const EmbedPage = (props: PageProps) => { } = props; return ( - <> - - - - - - - + + + ); }; diff --git a/app/utils/google-analytics.ts b/app/utils/google-analytics.ts deleted file mode 100644 index 11df25da3..000000000 --- a/app/utils/google-analytics.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { GA_TRACKING_ID } from "../domain/env"; - -declare global { - interface Window { - gtag?: (...args: $IntentionalAny) => void; - } -} - -// https://developers.google.com/analytics/devguides/collection/gtagjs/ip-anonymization - -// https://developers.google.com/analytics/devguides/collection/gtagjs/pages -export const analyticsPageView = (path: string) => { - window.gtag?.("config", GA_TRACKING_ID, { - page_path: path, - anonymize_ip: true, - }); -}; - -// https://developers.google.com/analytics/devguides/collection/gtagjs/events -/** @internal */ -export const analyticsEvent = ({ - action, - category, - label, - value, -}: { - action: string; - category: string; - label: string; - value?: number; -}) => { - window.gtag?.("event", action, { - event_category: category, - event_label: label, - value: value, - anonymize_ip: true, - }); -}; diff --git a/yarn.lock b/yarn.lock index a17219b32..d825895d1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -277,29 +277,7 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.6.tgz#103f466803fa0f059e82ccac271475470570d74c" integrity sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg== -"@babel/core@7.12.9": - version "7.12.9" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.9.tgz#fd450c4ec10cdbb980e2928b7aa7a28484593fc8" - integrity sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.12.5" - "@babel/helper-module-transforms" "^7.12.1" - "@babel/helpers" "^7.12.5" - "@babel/parser" "^7.12.7" - "@babel/template" "^7.12.7" - "@babel/traverse" "^7.12.9" - "@babel/types" "^7.12.7" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.19" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/core@^7.0.0", "@babel/core@^7.10.5", "@babel/core@^7.12.3", "@babel/core@^7.12.9", "@babel/core@^7.18.9", "@babel/core@^7.21.0", "@babel/core@^7.23.0", "@babel/core@^7.24.4", "@babel/core@^7.26.10", "@babel/core@^7.7.7": +"@babel/core@7.12.9", "@babel/core@^7.0.0", "@babel/core@^7.10.5", "@babel/core@^7.12.3", "@babel/core@^7.12.9", "@babel/core@^7.14.6", "@babel/core@^7.18.9", "@babel/core@^7.21.0", "@babel/core@^7.23.0", "@babel/core@^7.24.4", "@babel/core@^7.26.10", "@babel/core@^7.7.7": version "7.29.0" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.29.0.tgz#5286ad785df7f79d656e88ce86e650d16ca5f322" integrity sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA== @@ -329,17 +307,6 @@ jsesc "^2.5.1" source-map "^0.5.0" -"@babel/generator@^7.12.5", "@babel/generator@^7.29.0": - version "7.29.1" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.1.tgz#d09876290111abbb00ef962a7b83a5307fba0d50" - integrity sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw== - dependencies: - "@babel/parser" "^7.29.0" - "@babel/types" "^7.29.0" - "@jridgewell/gen-mapping" "^0.3.12" - "@jridgewell/trace-mapping" "^0.3.28" - jsesc "^3.0.2" - "@babel/generator@^7.21.1": version "7.28.3" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.3.tgz#9626c1741c650cbac39121694a0f2d7451b8ef3e" @@ -404,6 +371,17 @@ "@jridgewell/trace-mapping" "^0.3.28" jsesc "^3.0.2" +"@babel/generator@^7.29.0": + version "7.29.1" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.1.tgz#d09876290111abbb00ef962a7b83a5307fba0d50" + integrity sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw== + dependencies: + "@babel/parser" "^7.29.0" + "@babel/types" "^7.29.0" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + "@babel/helper-annotate-as-pure@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz" @@ -682,15 +660,6 @@ "@babel/traverse" "^7.28.6" "@babel/types" "^7.28.6" -"@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.28.6": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz#9312d9d9e56edc35aeb6e95c25d4106b50b9eb1e" - integrity sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA== - dependencies: - "@babel/helper-module-imports" "^7.28.6" - "@babel/helper-validator-identifier" "^7.28.5" - "@babel/traverse" "^7.28.6" - "@babel/helper-module-transforms@^7.14.5": version "7.15.8" resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.8.tgz" @@ -725,6 +694,15 @@ "@babel/helper-validator-identifier" "^7.25.9" "@babel/traverse" "^7.25.9" +"@babel/helper-module-transforms@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz#9312d9d9e56edc35aeb6e95c25d4106b50b9eb1e" + integrity sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA== + dependencies: + "@babel/helper-module-imports" "^7.28.6" + "@babel/helper-validator-identifier" "^7.28.5" + "@babel/traverse" "^7.28.6" + "@babel/helper-optimise-call-expression@^7.14.5", "@babel/helper-optimise-call-expression@^7.15.4": version "7.15.4" resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz" @@ -988,14 +966,6 @@ "@babel/template" "^7.22.15" "@babel/types" "^7.22.19" -"@babel/helpers@^7.12.5": - version "7.29.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.29.2.tgz#9cfbccb02b8e229892c0b07038052cc1a8709c49" - integrity sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw== - dependencies: - "@babel/template" "^7.28.6" - "@babel/types" "^7.29.0" - "@babel/helpers@^7.28.6": version "7.28.6" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.6.tgz#fca903a313ae675617936e8998b814c415cbf5d7" @@ -1041,15 +1011,10 @@ js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@7.12.16": - version "7.12.16" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.16.tgz#cc31257419d2c3189d394081635703f549fc1ed4" - integrity sha512-c/+u9cqV6F0+4Hpq01jnJO+GLp2DdT63ppz9Xa+6cHaajM9VFzK/iDXiKK65YtpeVwu+ctfS6iqlMqRgQRzeCw== - -"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.12.13", "@babel/parser@^7.12.7", "@babel/parser@^7.15.4", "@babel/parser@^7.20.7", "@babel/parser@^7.21.4", "@babel/parser@^7.22.0", "@babel/parser@^7.22.15", "@babel/parser@^7.23.0", "@babel/parser@^7.24.0", "@babel/parser@^7.24.4", "@babel/parser@^7.24.5", "@babel/parser@^7.25.4", "@babel/parser@^7.25.9", "@babel/parser@^7.26.2", "@babel/parser@^7.27.0", "@babel/parser@^7.28.3", "@babel/parser@^7.28.6", "@babel/parser@^7.29.0": - version "7.29.2" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.2.tgz#58bd50b9a7951d134988a1ae177a35ef9a703ba1" - integrity sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA== +"@babel/parser@7.12.16", "@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.12.13", "@babel/parser@^7.14.6", "@babel/parser@^7.15.4", "@babel/parser@^7.20.7", "@babel/parser@^7.21.4", "@babel/parser@^7.22.0", "@babel/parser@^7.22.15", "@babel/parser@^7.23.0", "@babel/parser@^7.24.0", "@babel/parser@^7.24.4", "@babel/parser@^7.24.5", "@babel/parser@^7.25.4", "@babel/parser@^7.25.9", "@babel/parser@^7.26.2", "@babel/parser@^7.27.0", "@babel/parser@^7.28.3", "@babel/parser@^7.28.6", "@babel/parser@^7.29.0": + version "7.29.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.3.tgz#116f70a77958307fceac27747573032f8a62f88e" + integrity sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA== dependencies: "@babel/types" "^7.29.0" @@ -2242,15 +2207,6 @@ resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.26.10.tgz#1fce13e5a331a9dafff192b5db41350d72d44bed" integrity sha512-AYXK0hLWfEaK9WAePJqs30qro09a8w7X3YZzjukqtLXreE7xBZYdi5EMrP87T4UrVqmQ9tIX6L6SeTu5LDh3zw== -"@babel/template@^7.12.7", "@babel/template@^7.28.6": - version "7.28.6" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.28.6.tgz#0e7e56ecedb78aeef66ce7972b082fce76a23e57" - integrity sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ== - dependencies: - "@babel/code-frame" "^7.28.6" - "@babel/parser" "^7.28.6" - "@babel/types" "^7.28.6" - "@babel/template@^7.15.4": version "7.15.4" resolved "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz" @@ -2296,6 +2252,15 @@ "@babel/parser" "^7.27.0" "@babel/types" "^7.27.0" +"@babel/template@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.28.6.tgz#0e7e56ecedb78aeef66ce7972b082fce76a23e57" + integrity sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ== + dependencies: + "@babel/code-frame" "^7.28.6" + "@babel/parser" "^7.28.6" + "@babel/types" "^7.28.6" + "@babel/traverse@7.12.13": version "7.12.13" resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.13.tgz" @@ -2326,19 +2291,6 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/traverse@^7.12.9", "@babel/traverse@^7.29.0": - version "7.29.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.0.tgz#f323d05001440253eead3c9c858adbe00b90310a" - integrity sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA== - dependencies: - "@babel/code-frame" "^7.29.0" - "@babel/generator" "^7.29.0" - "@babel/helper-globals" "^7.28.0" - "@babel/parser" "^7.29.0" - "@babel/template" "^7.28.6" - "@babel/types" "^7.29.0" - debug "^4.3.1" - "@babel/traverse@^7.18.9": version "7.24.0" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.0.tgz#4a408fbf364ff73135c714a2ab46a5eab2831b1e" @@ -2410,6 +2362,19 @@ "@babel/types" "^7.28.6" debug "^4.3.1" +"@babel/traverse@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.0.tgz#f323d05001440253eead3c9c858adbe00b90310a" + integrity sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA== + dependencies: + "@babel/code-frame" "^7.29.0" + "@babel/generator" "^7.29.0" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.29.0" + "@babel/template" "^7.28.6" + "@babel/types" "^7.29.0" + debug "^4.3.1" + "@babel/types@7.12.13": version "7.12.13" resolved "https://registry.npmjs.org/@babel/types/-/types-7.12.13.tgz" @@ -2427,14 +2392,6 @@ "@babel/helper-validator-identifier" "^7.14.9" to-fast-properties "^2.0.0" -"@babel/types@^7.12.7", "@babel/types@^7.25.4", "@babel/types@^7.29.0": - version "7.29.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.0.tgz#9f5b1e838c446e72cf3cd4b918152b8c605e37c7" - integrity sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A== - dependencies: - "@babel/helper-string-parser" "^7.27.1" - "@babel/helper-validator-identifier" "^7.28.5" - "@babel/types@^7.16.7": version "7.17.0" resolved "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz" @@ -2505,6 +2462,14 @@ "@babel/helper-validator-identifier" "^7.24.5" to-fast-properties "^2.0.0" +"@babel/types@^7.25.4", "@babel/types@^7.29.0": + version "7.29.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.0.tgz#9f5b1e838c446e72cf3cd4b918152b8c605e37c7" + integrity sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.28.5" + "@babel/types@^7.25.9", "@babel/types@^7.26.0": version "7.26.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.0.tgz#deabd08d6b753bc8e0f198f8709fb575e31774ff" @@ -15980,7 +15945,7 @@ fwd-stream@^1.0.4: dependencies: readable-stream "~1.0.26-4" -gensync@^1.0.0-beta.1, gensync@^1.0.0-beta.2: +gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== @@ -17489,7 +17454,7 @@ is-core-module@^2.13.0: dependencies: hasown "^2.0.0" -is-core-module@^2.15.1, is-core-module@^2.16.0, is-core-module@^2.16.1: +is-core-module@^2.15.1, is-core-module@^2.16.0: version "2.16.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== @@ -23222,16 +23187,6 @@ resolve@^1.21.0, resolve@^1.22.1: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^1.3.2: - version "1.22.12" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.12.tgz#f5b2a680897c69c238a13cd16b15671f8b73549f" - integrity sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA== - dependencies: - es-errors "^1.3.0" - is-core-module "^2.16.1" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - resolve@^2.0.0-next.5: version "2.0.0-next.5" resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" @@ -23585,11 +23540,6 @@ semver-compare@^1.0.0: resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^5.4.1: - version "5.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz"