diff --git a/components/feedback.tsx b/components/feedback.tsx index 92c4edf9..305db8f7 100644 --- a/components/feedback.tsx +++ b/components/feedback.tsx @@ -5,6 +5,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faThumbsUp, faThumbsDown } from "@fortawesome/free-solid-svg-icons"; import { faGithub } from "@fortawesome/free-brands-svg-icons"; import posthog from "posthog-js"; +import { consentedIdentify } from "@/lib/consent"; export function Feedback() { const [isVisible, setIsVisible] = useState(false); @@ -49,7 +50,7 @@ export function Feedback() { e.preventDefault(); if (formData.email) { - posthog.identify(formData.email); + consentedIdentify(posthog, formData.email); } posthog.capture("docs-feedback-detail", { diff --git a/components/scripts.tsx b/components/scripts.tsx index 62fea215..c103f8bb 100644 --- a/components/scripts.tsx +++ b/components/scripts.tsx @@ -1,11 +1,9 @@ "use client"; -import inEU from "@segment/in-eu"; import { usePathname, useSearchParams } from "next/navigation"; -import { Router } from "next/router"; import Script from "next/script"; -import posthog from "posthog-js"; import { Suspense, useEffect, useState } from "react"; +import { isEUVisitor, shouldOptOutCapturing } from "@/lib/consent"; const isProd = process.env.NEXT_PUBLIC_VERCEL_ENV === "production"; const baseDir = process.env.NEXT_PUBLIC_BASE_DIR || ""; @@ -18,10 +16,8 @@ function HubSpot() { const searchParams = useSearchParams(); useEffect(() => { - if (window) { - setLoadHs(!inEU()); - } - }, [loadHs]); + setLoadHs(!shouldOptOutCapturing(isEUVisitor())); + }, []); useEffect(() => { // @ts-ignore diff --git a/instrumentation-client.ts b/instrumentation-client.ts index 68ca0437..abe88746 100644 --- a/instrumentation-client.ts +++ b/instrumentation-client.ts @@ -1,18 +1,24 @@ import posthog from "posthog-js"; -import inEU from "@segment/in-eu"; +import { isEUVisitor, shouldOptOutCapturing } from "@/lib/consent"; const isProd = process.env.NEXT_PUBLIC_VERCEL_ENV === "production"; const initPostHog = () => { - if (inEU() || !process.env.NEXT_PUBLIC_POSTHOG_KEY) { + if (!process.env.NEXT_PUBLIC_POSTHOG_KEY || !isProd) { return; } - posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY ?? "", { - api_host: isProd ? "/i" : process.env.NEXT_PUBLIC_POSTHOG_HOST, // See Posthog rewrites in next config + const optOut = shouldOptOutCapturing(isEUVisitor()); + + posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY, { + api_host: "/i", ui_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, defaults: "2025-11-30", person_profiles: "always", + cross_subdomain_cookie: true, + opt_out_capturing_by_default: optOut, + opt_out_persistence_by_default: optOut, + cookieless_mode: "on_reject", loaded: (posthog) => { if (process.env.NODE_ENV === "development") posthog.debug(); }, diff --git a/lib/consent/debug.ts b/lib/consent/debug.ts new file mode 100644 index 00000000..d83ca02a --- /dev/null +++ b/lib/consent/debug.ts @@ -0,0 +1,19 @@ +/** Debug cookie names used by ConsentProvider to override detection. */ +export const DEBUG_EU_COOKIE = "__consent_debug_eu"; +export const DEBUG_GPC_COOKIE = "__consent_debug_gpc"; + +/** + * Read a debug override cookie by name. Returns null if not set or + * if running in production (Vercel production environment). + */ +export function getDebugCookie(name: string): string | null { + if (typeof document === "undefined") return null; + if (typeof process !== "undefined") { + const env = + (process.env as Record).VERCEL_ENV ?? + (process.env as Record).NEXT_PUBLIC_VERCEL_ENV; + if (env === "production") return null; + } + const match = document.cookie.split("; ").find((row) => row.startsWith(`${name}=`)); + return match ? match.split("=")[1] : null; +} diff --git a/lib/consent/eu-detection.ts b/lib/consent/eu-detection.ts new file mode 100644 index 00000000..fad4f88b --- /dev/null +++ b/lib/consent/eu-detection.ts @@ -0,0 +1,70 @@ +import { DEBUG_EU_COOKIE, getDebugCookie } from "./debug"; + +const EU_TIMEZONES = new Set([ + // EU member states + "Europe/Vienna", + "Europe/Brussels", + "Europe/Sofia", + "Europe/Zagreb", + "Asia/Famagusta", + "Asia/Nicosia", + "Europe/Prague", + "Europe/Copenhagen", + "Europe/Tallinn", + "Europe/Helsinki", + "Europe/Paris", + "Europe/Berlin", + "Europe/Busingen", + "Europe/Athens", + "Europe/Budapest", + "Europe/Dublin", + "Europe/Rome", + "Europe/Riga", + "Europe/Vilnius", + "Europe/Luxembourg", + "Europe/Malta", + "Europe/Amsterdam", + "Europe/Warsaw", + "Europe/Lisbon", + "Atlantic/Azores", + "Atlantic/Madeira", + "Europe/Bucharest", + "Europe/Bratislava", + "Europe/Ljubljana", + "Europe/Madrid", + "Africa/Ceuta", + "Atlantic/Canary", + "Europe/Stockholm", + // EEA (non-EU) + "Europe/Oslo", + "Arctic/Longyearbyen", + "Atlantic/Reykjavik", + "Europe/Vaduz", + // UK (still applies GDPR-equivalent) + "Europe/London", + "Europe/Belfast", + "Europe/Guernsey", + "Europe/Isle_of_Man", + "Europe/Jersey", +]); + +let cached: boolean | undefined; + +export function isEUVisitor(): boolean { + if (typeof window === "undefined") return true; + if (cached !== undefined) return cached; + + const debugOverride = getDebugCookie(DEBUG_EU_COOKIE); + if (debugOverride !== null) { + cached = debugOverride === "true"; + return cached; + } + + try { + const tz = Intl.DateTimeFormat().resolvedOptions().timeZone; + cached = EU_TIMEZONES.has(tz); + } catch { + cached = true; + } + return cached; +} diff --git a/lib/consent/index.ts b/lib/consent/index.ts new file mode 100644 index 00000000..44799a46 --- /dev/null +++ b/lib/consent/index.ts @@ -0,0 +1,19 @@ +/** + * @authzed/consent core (read-only consumer) + * + * Copied from authzed/web src/consent/core/. + * Portable consent utilities with zero external dependencies. + * + * This is a read-only consumer: it reads the `az-consent` cookie set by + * the marketing site (authzed.com) but does not write it or show a banner. + * Consent decisions are made on authzed.com and shared via the cookie. + */ +export { + readConsentCookie, + parseConsentCookie, + consentedIdentify, + shouldOptOutCapturing, + CONSENT_COOKIE_NAME, +} from "./storage"; +export { isEUVisitor } from "./eu-detection"; +export type { ConsentPreferences } from "./types"; diff --git a/lib/consent/storage.ts b/lib/consent/storage.ts new file mode 100644 index 00000000..b95a2230 --- /dev/null +++ b/lib/consent/storage.ts @@ -0,0 +1,55 @@ +import type { ConsentPreferences } from "./types"; + +const COOKIE_NAME = "az-consent"; +const COOKIE_VERSION = 1; + +export function readConsentCookie(): ConsentPreferences | null { + if (typeof document === "undefined") return null; + + const raw = getCookieValue(COOKIE_NAME); + if (!raw) return null; + + try { + const parsed = JSON.parse(raw); + if (parsed.version === COOKIE_VERSION) return parsed as ConsentPreferences; + } catch { + // invalid cookie + } + return null; +} + +export function parseConsentCookie(rawValue: string | undefined | null): ConsentPreferences | null { + if (!rawValue) return null; + try { + const parsed = JSON.parse(decodeURIComponent(rawValue)); + if (parsed.version === COOKIE_VERSION) return parsed as ConsentPreferences; + } catch { + // invalid cookie + } + return null; +} + +export const CONSENT_COOKIE_NAME = COOKIE_NAME; + +export function consentedIdentify( + ph: { identify: (id: string, props?: Record) => void }, + distinctId: string, + properties?: Record, +): void { + const consent = readConsentCookie(); + if (consent?.statistics) { + ph.identify(distinctId, properties); + } +} + +export function shouldOptOutCapturing(isEU: boolean): boolean { + const consent = readConsentCookie(); + if (consent !== null) return !consent.statistics; + return isEU; +} + +function getCookieValue(name: string): string | null { + if (typeof document === "undefined") return null; + const match = document.cookie.split("; ").find((row) => row.startsWith(`${name}=`)); + return match ? decodeURIComponent(match.split("=").slice(1).join("=")) : null; +} diff --git a/lib/consent/types.ts b/lib/consent/types.ts new file mode 100644 index 00000000..99f87179 --- /dev/null +++ b/lib/consent/types.ts @@ -0,0 +1,8 @@ +export interface ConsentPreferences { + version: 1; + necessary: true; + preferences: boolean; + statistics: boolean; + marketing: boolean; + updatedAt: string; // ISO-8601 +} diff --git a/package.json b/package.json index 47a806a3..b99d971d 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,6 @@ "@fortawesome/free-solid-svg-icons": "^6.5.2", "@fortawesome/react-fontawesome": "^0.2.2", "@radix-ui/react-slot": "^1.2.4", - "@segment/in-eu": "^0.4.0", "@svgr/webpack": "^8.1.0", "@vercel/speed-insights": "^1.0.12", "class-variance-authority": "^0.7.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 39af9d0a..bf1f04ee 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,9 +23,6 @@ importers: '@radix-ui/react-slot': specifier: ^1.2.4 version: 1.2.4(@types/react@19.1.6)(react@19.2.3) - '@segment/in-eu': - specifier: ^0.4.0 - version: 0.4.0 '@svgr/webpack': specifier: ^8.1.0 version: 8.1.0(typescript@5.9.3) @@ -920,160 +917,189 @@ packages: resolution: {integrity: sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm64@1.2.4': resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.1.0': resolution: {integrity: sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.4': resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.1.0': resolution: {integrity: sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.4': resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-riscv64@1.2.4': resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.1.0': resolution: {integrity: sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.4': resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.1.0': resolution: {integrity: sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.4': resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.1.0': resolution: {integrity: sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-arm64@1.2.4': resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.1.0': resolution: {integrity: sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.4': resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.34.1': resolution: {integrity: sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm64@0.34.5': resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.34.1': resolution: {integrity: sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.34.5': resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-ppc64@0.34.5': resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-linux-riscv64@0.34.5': resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.34.1': resolution: {integrity: sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.34.5': resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.34.1': resolution: {integrity: sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.34.5': resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.1': resolution: {integrity: sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-arm64@0.34.5': resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.34.1': resolution: {integrity: sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.34.5': resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.34.1': resolution: {integrity: sha512-YDybQnYrLQfEpzGOQe7OKcyLUCML4YOXl428gOOzBgN6Gw0rv8dpsJ7PqTHxBnXnwXr8S1mYFSLSa727tpz0xg==} @@ -1194,36 +1220,42 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@napi-rs/simple-git-linux-arm64-musl@0.1.22': resolution: {integrity: sha512-MOs7fPyJiU/wqOpKzAOmOpxJ/TZfP4JwmvPad/cXTOWYwwyppMlXFRms3i98EU3HOazI/wMU2Ksfda3+TBluWA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@napi-rs/simple-git-linux-ppc64-gnu@0.1.22': resolution: {integrity: sha512-L59dR30VBShRUIZ5/cQHU25upNgKS0AMQ7537J6LCIUEFwwXrKORZKJ8ceR+s3Sr/4jempWVvMdjEpFDE4HYww==} engines: {node: '>= 10'} cpu: [ppc64] os: [linux] + libc: [glibc] '@napi-rs/simple-git-linux-s390x-gnu@0.1.22': resolution: {integrity: sha512-4FHkPlCSIZUGC6HiADffbe6NVoTBMd65pIwcd40IDbtFKOgFMBA+pWRqKiQ21FERGH16Zed7XHJJoY3jpOqtmQ==} engines: {node: '>= 10'} cpu: [s390x] os: [linux] + libc: [glibc] '@napi-rs/simple-git-linux-x64-gnu@0.1.22': resolution: {integrity: sha512-Ei1tM5Ho/dwknF3pOzqkNW9Iv8oFzRxE8uOhrITcdlpxRxVrBVptUF6/0WPdvd7R9747D/q61QG/AVyWsWLFKw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@napi-rs/simple-git-linux-x64-musl@0.1.22': resolution: {integrity: sha512-zRYxg7it0p3rLyEJYoCoL2PQJNgArVLyNavHW03TFUAYkYi5bxQ/UFNVpgxMaXohr5yu7qCBqeo9j4DWeysalg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@napi-rs/simple-git-win32-arm64-msvc@0.1.22': resolution: {integrity: sha512-XGFR1fj+Y9cWACcovV2Ey/R2xQOZKs8t+7KHPerYdJ4PtjVzGznI4c2EBHXtdOIYvkw7tL5rZ7FN1HJKdD5Quw==} @@ -1270,24 +1302,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@next/swc-linux-arm64-musl@16.1.1': resolution: {integrity: sha512-MFHrgL4TXNQbBPzkKKur4Fb5ICEJa87HM7fczFs2+HWblM7mMLdco3dvyTI+QmLBU9xgns/EeeINSZD6Ar+oLg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@next/swc-linux-x64-gnu@16.1.1': resolution: {integrity: sha512-20bYDfgOQAPUkkKBnyP9PTuHiJGM7HzNBbuqmD0jiFVZ0aOldz+VnJhbxzjcSabYsnNjMPsE0cyzEudpYxsrUQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@next/swc-linux-x64-musl@16.1.1': resolution: {integrity: sha512-9pRbK3M4asAHQRkwaXwu601oPZHghuSC8IXNENgbBSyImHv/zY4K5udBusgdHkvJ/Tcr96jJwQYOll0qU8+fPA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@next/swc-win32-arm64-msvc@16.1.1': resolution: {integrity: sha512-bdfQkggaLgnmYrFkSQfsHfOhk/mCYmjnrbRCGgkMcoOBZ4n+TRRSLmT/CU5SATzlBJ9TpioUyBW/vWFXTqQRiA==} @@ -1327,21 +1363,25 @@ packages: resolution: {integrity: sha512-GubkQeQT5d3B/Jx/IiR7NMkSmXrCZcVI0BPh1i7mpFi8HgD1hQ/LbhiBKAMsMqs5bbugdQOgBEl8bOhe8JhW1g==} cpu: [arm64] os: [linux] + libc: [glibc] '@oxfmt/linux-arm64-musl@0.26.0': resolution: {integrity: sha512-OEypUwK69bFPj+aa3/LYCnlIUPgoOLu//WNcriwpnWNmt47808Ht7RJSg+MNK8a7pSZHpXJ5/E6CRK/OTwFdaQ==} cpu: [arm64] os: [linux] + libc: [musl] '@oxfmt/linux-x64-gnu@0.26.0': resolution: {integrity: sha512-xO6iEW2bC6ZHyOTPmPWrg/nM6xgzyRPaS84rATy6F8d79wz69LdRdJ3l/PXlkqhi7XoxhvX4ExysA0Nf10ZZEQ==} cpu: [x64] os: [linux] + libc: [glibc] '@oxfmt/linux-x64-musl@0.26.0': resolution: {integrity: sha512-Z3KuZFC+MIuAyFCXBHY71kCsdRq1ulbsbzTe71v+hrEv7zVBn6yzql+/AZcgfIaKzWO9OXNuz5WWLWDmVALwow==} cpu: [x64] os: [linux] + libc: [musl] '@oxfmt/win32-arm64@0.26.0': resolution: {integrity: sha512-3zRbqwVWK1mDhRhTknlQFpRFL9GhEB5GfU6U7wawnuEwpvi39q91kJ+SRJvJnhyPCARkjZBd1V8XnweN5IFd1g==} @@ -1444,9 +1484,6 @@ packages: '@scarf/scarf@1.4.0': resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==} - '@segment/in-eu@0.4.0': - resolution: {integrity: sha512-4JM6fMRMy1nZQk5x1nB1R4iIFOkcyCiUNOPQo161nUUsNE+U97l46v4xLIqQJAMjXjfxnULFFp+9uf6PYdnLtQ==} - '@shikijs/core@3.15.0': resolution: {integrity: sha512-8TOG6yG557q+fMsSVa8nkEDOZNTSxjbbR8l6lF2gyr6Np+jrPlslqDxQkN6rMXCECQ3isNPZAGszAfYoJOPGlg==} @@ -1697,24 +1734,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.1.17': resolution: {integrity: sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.1.17': resolution: {integrity: sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.1.17': resolution: {integrity: sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.1.17': resolution: {integrity: sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==} @@ -2941,10 +2982,6 @@ packages: jsonc-parser@3.2.1: resolution: {integrity: sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==} - jstz@2.1.1: - resolution: {integrity: sha512-8hfl5RD6P7rEeIbzStBz3h4f+BQHfq/ABtoU6gXKQv5OcZhnmrIpG7e1pYaZ8hS9e0mp+bxUj08fnDUbKctYyA==} - engines: {node: '>=0.10'} - katex@0.16.25: resolution: {integrity: sha512-woHRUZ/iF23GBP1dkDQMh1QBad9dmr8/PAwNA54VrSOVYgI12MAcE14TqnDdQOdzyEonGzMepYnqBMYdsoAr8Q==} hasBin: true @@ -3000,24 +3037,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.30.2: resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} @@ -5787,10 +5828,6 @@ snapshots: '@scarf/scarf@1.4.0': {} - '@segment/in-eu@0.4.0': - dependencies: - jstz: 2.1.1 - '@shikijs/core@3.15.0': dependencies: '@shikijs/types': 3.15.0 @@ -7638,8 +7675,6 @@ snapshots: jsonc-parser@3.2.1: {} - jstz@2.1.1: {} - katex@0.16.25: dependencies: commander: 8.3.0