From 2e66ad33cafb4ecd1af5a50acf9a0fb7f26b3609 Mon Sep 17 00:00:00 2001 From: Jung Sun A Date: Thu, 2 Jul 2026 09:01:23 +0900 Subject: [PATCH 01/12] =?UTF-8?q?feat:=20web=20Sentry=20=EC=97=90=EB=9F=AC?= =?UTF-8?q?=20=EB=AA=A8=EB=8B=88=ED=84=B0=EB=A7=81=20=EB=8F=84=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/.gitignore | 1 + apps/web/instrumentation-client.ts | 27 + apps/web/instrumentation.ts | 8 + apps/web/next.config.mjs | 17 +- apps/web/package.json | 1 + apps/web/sentry.edge.config.ts | 14 + apps/web/sentry.server.config.ts | 14 + apps/web/src/app/global-error.tsx | 6 + pnpm-lock.yaml | 1200 +++++++++++++++++++++++++++- turbo.json | 7 +- 10 files changed, 1288 insertions(+), 7 deletions(-) create mode 100644 apps/web/instrumentation-client.ts create mode 100644 apps/web/instrumentation.ts create mode 100644 apps/web/sentry.edge.config.ts create mode 100644 apps/web/sentry.server.config.ts diff --git a/apps/web/.gitignore b/apps/web/.gitignore index f886745c..4f328319 100644 --- a/apps/web/.gitignore +++ b/apps/web/.gitignore @@ -27,6 +27,7 @@ yarn-error.log* # env files (can opt-in for commiting if needed) .env* +!.env.example # vercel .vercel diff --git a/apps/web/instrumentation-client.ts b/apps/web/instrumentation-client.ts new file mode 100644 index 00000000..f02ffed7 --- /dev/null +++ b/apps/web/instrumentation-client.ts @@ -0,0 +1,27 @@ +import * as Sentry from '@sentry/nextjs'; + +/** production/staging 에서만 수집 (dev/local 비활성) */ +const stage = process.env.NEXT_PUBLIC_STAGE; +const enabled = stage === 'production' || stage === 'staging'; + +Sentry.init({ + dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, + environment: stage, + enabled, + ...(process.env.NEXT_PUBLIC_WEB_VERSION ? { release: process.env.NEXT_PUBLIC_WEB_VERSION } : {}), + /** Performance(Tracing)는 초기엔 off */ + tracesSampleRate: 0, + /** Session Replay — 에러 발생 세션만 녹화 */ + replaysSessionSampleRate: 0, + replaysOnErrorSampleRate: 1.0, + integrations: [ + Sentry.replayIntegration({ + maskAllText: true, + blockAllMedia: true, + }), + ], + /** PII 기본 마스킹 */ + sendDefaultPii: false, +}); + +export const onRouterTransitionStart = Sentry.captureRouterTransitionStart; diff --git a/apps/web/instrumentation.ts b/apps/web/instrumentation.ts new file mode 100644 index 00000000..21051d4a --- /dev/null +++ b/apps/web/instrumentation.ts @@ -0,0 +1,8 @@ +import * as Sentry from '@sentry/nextjs'; + +export async function register() { + if (process.env.NEXT_RUNTIME === 'nodejs') await import('./sentry.server.config'); + if (process.env.NEXT_RUNTIME === 'edge') await import('./sentry.edge.config'); +} + +export const onRequestError = Sentry.captureRequestError; diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs index 08c0ef7d..d7b9e062 100644 --- a/apps/web/next.config.mjs +++ b/apps/web/next.config.mjs @@ -1,3 +1,5 @@ +import { withSentryConfig } from '@sentry/nextjs'; + import { getWebVersion } from './config/getWebVersion.mjs'; /** @type {import('next').NextConfig} */ @@ -45,4 +47,17 @@ const nextConfig = async () => { }; }; -export default nextConfig; +export default withSentryConfig(nextConfig, { + org: 'piki-92', + project: 'piki-web', + /** SENTRY_AUTH_TOKEN 이 있을 때만 소스맵 업로드 (CI/Vercel env 주입) */ + silent: !process.env.CI, + /** 소스맵 업로드 후 클라이언트 번들에서 제거 (원본 코드 노출 방지) */ + sourcemaps: { + deleteSourcemapsAfterUpload: true, + }, + /** Sentry SDK 디버그 로그 제거로 번들 크기 절감 */ + bundleSizeOptimizations: { + excludeDebugStatements: true, + }, +}); diff --git a/apps/web/package.json b/apps/web/package.json index 5b34f6b6..12707aa6 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -13,6 +13,7 @@ "@microsoft/fetch-event-source": "^2.0.1", "@next/third-parties": "^16.2.9", "@piki/core": "workspace:*", + "@sentry/nextjs": "^10.63.0", "@tanstack/react-query": "^5.96.2", "@tanstack/react-query-devtools": "^5.96.2", "axios": "^1.15.2", diff --git a/apps/web/sentry.edge.config.ts b/apps/web/sentry.edge.config.ts new file mode 100644 index 00000000..989b97c8 --- /dev/null +++ b/apps/web/sentry.edge.config.ts @@ -0,0 +1,14 @@ +import * as Sentry from '@sentry/nextjs'; + +/** 배포 환경(production/staging/dev). Sentry 는 production/staging 에서만 수집 (dev·로컬 비활성) */ +const stage = process.env.NEXT_PUBLIC_STAGE; +const enabled = stage === 'production' || stage === 'staging'; + +Sentry.init({ + dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, + environment: stage, + enabled, + ...(process.env.NEXT_PUBLIC_WEB_VERSION ? { release: process.env.NEXT_PUBLIC_WEB_VERSION } : {}), + tracesSampleRate: 0, + sendDefaultPii: false, +}); diff --git a/apps/web/sentry.server.config.ts b/apps/web/sentry.server.config.ts new file mode 100644 index 00000000..989b97c8 --- /dev/null +++ b/apps/web/sentry.server.config.ts @@ -0,0 +1,14 @@ +import * as Sentry from '@sentry/nextjs'; + +/** 배포 환경(production/staging/dev). Sentry 는 production/staging 에서만 수집 (dev·로컬 비활성) */ +const stage = process.env.NEXT_PUBLIC_STAGE; +const enabled = stage === 'production' || stage === 'staging'; + +Sentry.init({ + dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, + environment: stage, + enabled, + ...(process.env.NEXT_PUBLIC_WEB_VERSION ? { release: process.env.NEXT_PUBLIC_WEB_VERSION } : {}), + tracesSampleRate: 0, + sendDefaultPii: false, +}); diff --git a/apps/web/src/app/global-error.tsx b/apps/web/src/app/global-error.tsx index cc53826f..c95a6178 100644 --- a/apps/web/src/app/global-error.tsx +++ b/apps/web/src/app/global-error.tsx @@ -1,6 +1,8 @@ 'use client'; +import * as Sentry from '@sentry/nextjs'; import Link from 'next/link'; +import { useEffect } from 'react'; import { ROUTES } from '@/consts/route'; import '@/styles/globals.css'; @@ -12,6 +14,10 @@ type Props = { // TODO: 임시 글로벌 에러 페이지 - 디자인 변경 필요 export default function GlobalError({ error, reset }: Props) { + useEffect(() => { + Sentry.captureException(error); + }, [error]); + return ( diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dcd49b22..970b267b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -214,10 +214,13 @@ importers: version: 2.0.1 '@next/third-parties': specifier: ^16.2.9 - version: 16.2.9(next@16.2.0(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0) + version: 16.2.9(next@16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0) '@piki/core': specifier: workspace:* version: link:../../packages/core + '@sentry/nextjs': + specifier: ^10.63.0 + version: 10.63.0(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))(next@16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(webpack@5.108.3(postcss@8.5.8)) '@tanstack/react-query': specifier: ^5.96.2 version: 5.96.2(react@19.1.0) @@ -247,7 +250,7 @@ importers: version: 0.20.0 next: specifier: 16.2.0 - version: 16.2.0(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) radix-ui: specifier: ^1.4.3 version: 1.4.3(@types/react-dom@19.1.11(@types/react@19.1.17))(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -348,6 +351,17 @@ packages: resolution: {integrity: sha512-FSEVWXvwroExDXUu8qV6Wqp2X3D1nJ0Li4LFymCyvCVrm7I3lNfG0zZWSWvGU1RE7891eTnFTyh31L3igOwNKQ==} hasBin: true + '@apm-js-collab/code-transformer-bundler-plugins@0.5.0': + resolution: {integrity: sha512-YxLBY5nGlurL7QeJLq6e5g0ouBpAp0pwgyA/5rHXEXwhiPLn9ZHbT+Y2LlP90GT872cSocfjWRYu/fnpuBudNQ==} + engines: {node: '>=18.0.0'} + + '@apm-js-collab/code-transformer@0.15.0': + resolution: {integrity: sha512-XmXYVs8CzJ1Aj79noVbn2weUO/XWtRyURpGqx7aU7DOXlUQhR0WKOQNF0okh7PCeY37vxf7kU3v57OAkEPm3ww==} + hasBin: true + + '@apm-js-collab/tracing-hooks@0.10.1': + resolution: {integrity: sha512-w2OWXR7FWrKqSziuE9+QclaZrStxO/8+OwbXM635s/zs0Eez1Qo3ivSPdB2WsaPY/iznKTytONPx/PitD7IXcA==} + '@babel/code-frame@7.10.4': resolution: {integrity: sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==} @@ -1873,6 +1887,42 @@ packages: '@open-draft/until@2.1.0': resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + '@opentelemetry/api-logs@0.214.0': + resolution: {integrity: sha512-40lSJeqYO8Uz2Yj7u94/SJWE/wONa7rmMKjI1ZcIjgf3MHNHv1OZUCrCETGuaRF62d5pQD1wKIW+L4lmSMTzZA==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/api@1.9.1': + resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/core@2.8.0': + resolution: {integrity: sha512-hd1Lfh8p545nNz+jq1Ejfz+Mn1hyLuxYn1YzTfFNrxr8urEWMNQLPf1Th8kjOH+HxwawCrtgBp8JpBUR4ZSgww==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/instrumentation@0.214.0': + resolution: {integrity: sha512-MHqEX5Dk59cqVah5LiARMACku7jXSVk9iVDWOea4x3cr7VfdByeDCURK6o1lntT1JS/Tsovw01UJrBhN3/uC5w==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/resources@2.8.0': + resolution: {integrity: sha512-qmXQ27ilDbUK/vGMqwL8D4/rhn76C+sherM4wTbjlfknR8Nvfc/hCxjRJPhkzZzUsPiNg16SA31NxMabwttRjg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-trace-base@2.8.0': + resolution: {integrity: sha512-mhU4jp+vW0mGbFRd+GeXHvmfA4aDqWjBjLC3pE5XMpLs0IE2ryYb019Ts2AQrOq67gaTF25D91+fgvEHDZEnuQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/semantic-conventions@1.41.1': + resolution: {integrity: sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==} + engines: {node: '>=14'} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -2780,12 +2830,302 @@ packages: '@react-navigation/routers@7.5.3': resolution: {integrity: sha512-1tJHg4KKRJuQ1/EvJxatrMef3NZXEPzwUIUZ3n1yJ2t7Q97siwRtbynRpQG9/69ebbtiZ8W3ScOZF/OmhvM4Rg==} + '@rollup/plugin-commonjs@28.0.1': + resolution: {integrity: sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA==} + engines: {node: '>=16.0.0 || 14 >= 14.17'} + peerDependencies: + rollup: ^2.68.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/pluginutils@5.4.0': + resolution: {integrity: sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.62.2': + resolution: {integrity: sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.62.2': + resolution: {integrity: sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.62.2': + resolution: {integrity: sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.62.2': + resolution: {integrity: sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.62.2': + resolution: {integrity: sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.62.2': + resolution: {integrity: sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.62.2': + resolution: {integrity: sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.62.2': + resolution: {integrity: sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.62.2': + resolution: {integrity: sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.62.2': + resolution: {integrity: sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.62.2': + resolution: {integrity: sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.62.2': + resolution: {integrity: sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.62.2': + resolution: {integrity: sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-musl@4.62.2': + resolution: {integrity: sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.62.2': + resolution: {integrity: sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.62.2': + resolution: {integrity: sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.62.2': + resolution: {integrity: sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.62.2': + resolution: {integrity: sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.62.2': + resolution: {integrity: sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openbsd-x64@4.62.2': + resolution: {integrity: sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.62.2': + resolution: {integrity: sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.62.2': + resolution: {integrity: sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.62.2': + resolution: {integrity: sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.62.2': + resolution: {integrity: sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.62.2': + resolution: {integrity: sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==} + cpu: [x64] + os: [win32] + '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + '@sentry/babel-plugin-component-annotate@5.3.0': + resolution: {integrity: sha512-p4q8gn8wcFqZGP/s2MnJCAAd8fTikaU6A0mM97RDHQgStcrYiaS0Sc5zUNfb1V+UOLPuvdEdL6MwyxfzjYJQTA==} + engines: {node: '>= 18'} + + '@sentry/browser-utils@10.63.0': + resolution: {integrity: sha512-DhUGNN+CH8fzAs6qAsueKPU70qShyTX3NxLhIP+l5DbGXDSXpYXBT6s8ubZus0/LhxpLvI0iSyNIDvZRD/gZaA==} + engines: {node: '>=18'} + + '@sentry/browser@10.63.0': + resolution: {integrity: sha512-0mi56YOkwgyjdLOcN5cB1//EcYzEOt3NZ2GLygE92B3zAAwVM1WgbmibZCXToKFClH7z1uH3VWVfBffmkwIMYw==} + engines: {node: '>=18'} + + '@sentry/bundler-plugin-core@5.3.0': + resolution: {integrity: sha512-L5T60sWdAI3qWwdg3Ptwek/0TY59PERrxyqp4XMUkroayQvGd9r5dIW9Q1kSeXX9iJ442nXbFZKAOyCKV4Z13Q==} + engines: {node: '>= 18'} + + '@sentry/cli-darwin@2.58.6': + resolution: {integrity: sha512-udAVvcyfNa0R+95GvPz/+43/N3TC0TYKdkQ7D7jhPSzbcMc7l2fxRNN5yB3UpCA5fWFnW4toeaqwDBhb/Wh3LA==} + engines: {node: '>=10'} + os: [darwin] + + '@sentry/cli-linux-arm64@2.58.6': + resolution: {integrity: sha512-q8mEcNNmeXMy5i+jWT30TVpH7LcP4HD21CD5XRSPAd/a912HF6EpK0ybf/1USO14WOhoXbAGi9txwaWabSe33g==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux, freebsd, android] + + '@sentry/cli-linux-arm@2.58.6': + resolution: {integrity: sha512-pD0LAt5PcUzAinBwvDqc66x9+2CabHEv486yP0gRjWO7SakbaxmfVq/EXd8VLq/Tzi39LAu422UYK1lpW3MILw==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux, freebsd, android] + + '@sentry/cli-linux-i686@2.58.6': + resolution: {integrity: sha512-q8vNJi1eOV/4vxAFWBsEwLHoSYapaZHIf4j76KJGJXFKTkEbsjCOOsKbwUIBTQQhRgV4DFWh3ryfsPS/que4Kg==} + engines: {node: '>=10'} + cpu: [x86, ia32] + os: [linux, freebsd, android] + + '@sentry/cli-linux-x64@2.58.6': + resolution: {integrity: sha512-DZu956Mhi3ZRjTBe1WdbGV46ldVbA8d2rgp/fh51GsI25zjBHah4wZnPTSzpc+YqxU6pJpg579B/r3jrIK530Q==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux, freebsd, android] + + '@sentry/cli-win32-arm64@2.58.6': + resolution: {integrity: sha512-nj0Ff/kmAB73EPDhR8B4O9r+NUHK5GkPCkGWC+kXVemqAJWL5jcJ5KdxG0l/S0z6RoEoltID8/43/B+TaMlT7A==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@sentry/cli-win32-i686@2.58.6': + resolution: {integrity: sha512-WNZiDzPbgsEMQWq4avsQ391v/xWKJDIWWWo9GYl+N/w5qcYKkoDW7wQG7T9FasI6ENn68phChTOAPXXxbfAdOg==} + engines: {node: '>=10'} + cpu: [x86, ia32] + os: [win32] + + '@sentry/cli-win32-x64@2.58.6': + resolution: {integrity: sha512-R35WJ17oF4D2eqI1DR2sQQqr0fjRTt5xoP16WrTu91XM2lndRMFsnjh+/GttbxapLCBNlrjzia99MJ0PZHZpgA==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@sentry/cli@2.58.6': + resolution: {integrity: sha512-baBcNPLLfUi9WuL+Tpri9BFaAdvugZIKelC5X0tt0Zdy+K0K+PCVSrnNmwMWU/HyaF/SEv6b6UHnXIdqanBlcg==} + engines: {node: '>= 10'} + hasBin: true + + '@sentry/conventions@0.12.0': + resolution: {integrity: sha512-z1JQrl/1SLY+8wpzvork6vl+fpsg/oCCxM7HWWhUnI/R+OGNyoIzieQuggX3uUMY7NBtp8UWCQx6FeFazzOF9g==} + engines: {node: '>=14'} + + '@sentry/core@10.63.0': + resolution: {integrity: sha512-OtUbsrnbEHffOF2S2+M5zXa3HIM0U2b4CDVLKMY1dgS0J3ivRF8XvkjvyIcEG/y8JXnwXbnprLyjhG+AqMdUZQ==} + engines: {node: '>=18'} + + '@sentry/feedback@10.63.0': + resolution: {integrity: sha512-If/+72xFg9ylz4twUo3U9gUpZ+Ys+T/3Y09WH7r2gGhWEOF9bp+ta94+Pg7Lb0M2nVD7waz4OxIvB49GEvtLDA==} + engines: {node: '>=18'} + + '@sentry/nextjs@10.63.0': + resolution: {integrity: sha512-SN3tBm+wpDmr4GONaxuIRjQglAiPBKF7JEsQlli1HNfar1JG+fRsxWy0/aKcn9Kp/XX1kOpFgW9tcfuE4UKm7Q==} + engines: {node: '>=18'} + peerDependencies: + next: ^13.2.0 || ^14.0 || ^15.0.0-rc.0 || ^16.0.0-0 + + '@sentry/node-core@10.63.0': + resolution: {integrity: sha512-TaNtkGDRNxH3SjOea2PDtaebkNjMbAH8ZFsEcwlqmadpS7nqSR7z6slZy/iu7y1nLiUdbmcM5JmXwxksy52WRQ==} + engines: {node: '>=18'} + peerDependencies: + '@opentelemetry/api': ^1.9.0 + '@opentelemetry/core': ^1.30.1 || ^2.1.0 + '@opentelemetry/exporter-trace-otlp-http': '>=0.57.0 <1' + '@opentelemetry/instrumentation': '>=0.57.1 <1' + '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@opentelemetry/core': + optional: true + '@opentelemetry/exporter-trace-otlp-http': + optional: true + '@opentelemetry/instrumentation': + optional: true + '@opentelemetry/sdk-trace-base': + optional: true + + '@sentry/node@10.63.0': + resolution: {integrity: sha512-E+JfDTdUDGQPRsAfCTR2YgmQgxYdoxk4ks6niHN+ByW8alEZL+nXlcN9vI57qj1LsS4v2jjfLxJf1/cMMt84YA==} + engines: {node: '>=18'} + + '@sentry/opentelemetry@10.63.0': + resolution: {integrity: sha512-8yqi8+Ej/anmMn82blXA0BNMeAMs4av6nx0DzhxDrFya28ZaYOn19PChd3erMidfU0HnLLFNqWiFlYxBKq+/KA==} + engines: {node: '>=18'} + peerDependencies: + '@opentelemetry/api': ^1.9.0 + '@opentelemetry/core': ^1.30.1 || ^2.1.0 + '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 + + '@sentry/react@10.63.0': + resolution: {integrity: sha512-+/Y0dd4EMqyqYBJ1D3bAYYuG+ccIx5+IFcbTZ9p+XWnW6nNIVjy5zttVftYo6xOmtTQbzRuPT/vO4dqDHKKmfw==} + engines: {node: '>=18'} + peerDependencies: + react: 19.1.0 + + '@sentry/replay-canvas@10.63.0': + resolution: {integrity: sha512-1Dg6yo+KDNZcE9M6V2EP4DGgTDJMcUgg5ui69w/E96ZZPWErS/bibK2bGj20H3qwpJXlnEwXB5YAJ2fZ620T1A==} + engines: {node: '>=18'} + + '@sentry/replay@10.63.0': + resolution: {integrity: sha512-u4fDaLbd4QmJbU0qGzV5g2B2hjw5utdeZzpTrmq565AS5o6mfaZdCz30zF9R2Unkn0g9SJr90piTN2RMwvDrkw==} + engines: {node: '>=18'} + + '@sentry/server-utils@10.63.0': + resolution: {integrity: sha512-7NN//DG9Yak8t2+6WiEcNmN269iHRVdtZtZIwucEd0OXyZ3FEBBDaBF+bT9V6H/kPtUvVMkHQ72Bn2Xs5JYGxg==} + engines: {node: '>=18'} + + '@sentry/vercel-edge@10.63.0': + resolution: {integrity: sha512-6vay7/Skgjt1SiDchobaN7mOeSDRwhQUikVvuT7Q/0nX5Xg5TRlSMbqwcllqKxwDXdJiW3MVdqqLixY1c8WjJA==} + engines: {node: '>=18'} + + '@sentry/webpack-plugin@5.3.0': + resolution: {integrity: sha512-i3OQUrS0FZlXLgq57RIKDp+vHHzuvYKPCKewAPXULWKMsBXFGhP6veGRQ+6To/pmZkkXjEX5ofVNDy9C3jEPKQ==} + engines: {node: '>= 18'} + peerDependencies: + webpack: '>=5.0.0' + '@sinclair/typebox@0.27.10': resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==} @@ -3055,6 +3395,9 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + '@types/graceful-fs@4.1.9': resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} @@ -3274,11 +3617,62 @@ packages: peerDependencies: '@urql/core': ^5.0.0 + '@webassemblyjs/ast@1.14.1': + resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} + + '@webassemblyjs/floating-point-hex-parser@1.13.2': + resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} + + '@webassemblyjs/helper-api-error@1.13.2': + resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} + + '@webassemblyjs/helper-buffer@1.14.1': + resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} + + '@webassemblyjs/helper-numbers@1.13.2': + resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': + resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} + + '@webassemblyjs/helper-wasm-section@1.14.1': + resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} + + '@webassemblyjs/ieee754@1.13.2': + resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} + + '@webassemblyjs/leb128@1.13.2': + resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} + + '@webassemblyjs/utf8@1.13.2': + resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} + + '@webassemblyjs/wasm-edit@1.14.1': + resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} + + '@webassemblyjs/wasm-gen@1.14.1': + resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} + + '@webassemblyjs/wasm-opt@1.14.1': + resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} + + '@webassemblyjs/wasm-parser@1.14.1': + resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} + + '@webassemblyjs/wast-printer@1.14.1': + resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + '@xmldom/xmldom@0.8.12': resolution: {integrity: sha512-9k/gHF6n/pAi/9tqr3m3aqkuiNosYTurLLUtc7xQ9sxB/wm7WPygCv8GYa6mS0fLJEHhqMC1ATYhz++U/lRHqg==} engines: {node: '>=10.0.0'} deprecated: this version has critical issues, please update to the latest version + '@xtuc/ieee754@1.2.0': + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + + '@xtuc/long@4.2.2': + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -3291,6 +3685,17 @@ packages: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} + acorn-import-attributes@1.9.5: + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} + peerDependencies: + acorn: ^8 + + acorn-import-phases@1.0.4: + resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} + engines: {node: '>=10.13.0'} + peerDependencies: + acorn: ^8.14.0 + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -3301,10 +3706,27 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + acorn@8.17.0: + resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} + engines: {node: '>=0.4.0'} + hasBin: true + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} + ajv-formats@2.1.1: + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + ajv-formats@3.0.1: resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} peerDependencies: @@ -3313,6 +3735,11 @@ packages: ajv: optional: true + ajv-keywords@5.1.0: + resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} + peerDependencies: + ajv: ^8.8.2 + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -3423,6 +3850,10 @@ packages: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} + astring@1.9.0: + resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} + hasBin: true + async-function@1.0.0: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} @@ -3658,6 +4089,10 @@ packages: engines: {node: '>=12.13.0'} hasBin: true + chrome-trace-event@1.0.4: + resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} + engines: {node: '>=6.0'} + chromium-edge-launcher@0.2.0: resolution: {integrity: sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg==} @@ -3668,6 +4103,9 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} + cjs-module-lexer@2.2.0: + resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} + class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} @@ -3752,6 +4190,9 @@ packages: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} engines: {node: '>= 10'} + commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + compressible@2.0.18: resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} engines: {node: '>= 0.6'} @@ -4070,6 +4511,10 @@ packages: resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} engines: {node: '>=10.13.0'} + enhanced-resolve@5.24.1: + resolution: {integrity: sha512-7DdUaTjmNwMcH2gLr1qycesKII3BK4RLy/mdAb7x10Lq7bR4aNKHt1BR1ZALSv0rPM/hF5wYF0PhGop/rJm8vw==} + engines: {node: '>=10.13.0'} + entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -4104,6 +4549,9 @@ packages: resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} engines: {node: '>= 0.4'} + es-module-lexer@2.2.0: + resolution: {integrity: sha512-3lGxdTXCLfe1MYfTz1y2ksAAUM4NAOP6rPEjxGJVKO7TZ5+tvHCaQWGpC4Y3IXvW3ece0Cz1cIP4FWBxOnGCTQ==} + es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} @@ -4251,6 +4699,10 @@ packages: '@typescript-eslint/eslint-plugin': optional: true + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + eslint-scope@8.4.0: resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4286,14 +4738,25 @@ packages: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -4306,6 +4769,10 @@ packages: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + eventsource-parser@3.0.8: resolution: {integrity: sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ==} engines: {node: '>=18.0.0'} @@ -4931,6 +5398,10 @@ packages: http-parser-js@0.5.10: resolution: {integrity: sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==} + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + https-proxy-agent@7.0.6: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} @@ -4973,6 +5444,10 @@ packages: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} + import-in-the-middle@3.2.0: + resolution: {integrity: sha512-vR2B6HKIhaBjcZr2bLpFiJ1VbzOlRQ7aby4/gw5WPIzToLjqpfWw3VJ4sk1uDchoOODEirvO2jyrSPtUSL5CrQ==} + engines: {node: '>=18'} + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -5127,6 +5602,9 @@ packages: is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-reference@1.2.1: + resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} + is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} @@ -5251,6 +5729,10 @@ packages: resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-worker@27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} + jest-worker@29.7.0: resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -5427,6 +5909,10 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + loader-runner@4.3.2: + resolution: {integrity: sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==} + engines: {node: '>=6.11.5'} + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -5521,6 +6007,10 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + meriyah@6.1.4: + resolution: {integrity: sha512-Sz8FzjzI0kN13GK/6MVEsVzMZEPvOhnmmI1lU5+/1cGOiK3QUahntrNNtdVeihrO7t9JpoH75iMNXg6R6uWflQ==} + engines: {node: '>=18.0.0'} + metro-babel-transformer@0.83.3: resolution: {integrity: sha512-1vxlvj2yY24ES1O5RsSIvg4a4WeL7PFXgKOHvXTXiW0deLvQr28ExXj6LjwCCDZ4YZLhq6HddLpZnX4dEdSq5g==} engines: {node: '>=20.19.4'} @@ -5688,6 +6178,49 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minimizer-webpack-plugin@5.6.1: + resolution: {integrity: sha512-DoeAZz8Q1C1znwsUzej1fdoi4jCf7/+Em27ouLqfK/+3m8G+D7yDhUwrc3CNhjSzGUN1kn7Iv4sWmjflQHenpw==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@minify-html/node': '*' + '@swc/core': '*' + '@swc/css': '*' + '@swc/html': '*' + clean-css: '*' + cssnano: '*' + csso: '*' + esbuild: '*' + html-minifier-terser: '*' + lightningcss: '*' + postcss: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@minify-html/node': + optional: true + '@swc/core': + optional: true + '@swc/css': + optional: true + '@swc/html': + optional: true + clean-css: + optional: true + cssnano: + optional: true + csso: + optional: true + esbuild: + optional: true + html-minifier-terser: + optional: true + lightningcss: + optional: true + postcss: + optional: true + uglify-js: + optional: true + minipass@7.1.3: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} @@ -5701,6 +6234,9 @@ packages: engines: {node: '>=10'} hasBin: true + module-details-from-path@1.0.4: + resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} + ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -5749,6 +6285,9 @@ packages: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + nested-error-stacks@2.0.1: resolution: {integrity: sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==} @@ -6192,6 +6731,9 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + proxy-from-env@2.1.0: resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} engines: {node: '>=10'} @@ -6422,6 +6964,10 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + require-in-the-middle@8.0.1: + resolution: {integrity: sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==} + engines: {node: '>=9.3.0 || >=8.10.0 <9.0.0'} + requireg@0.2.2: resolution: {integrity: sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg==} engines: {node: '>= 4.0.0'} @@ -6484,6 +7030,11 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + rollup@4.62.2: + resolution: {integrity: sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + router@2.2.0: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} @@ -6520,6 +7071,13 @@ packages: scheduler@0.26.0: resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + schema-utils@4.3.3: + resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} + engines: {node: '>= 10.13.0'} + + semifies@1.0.0: + resolution: {integrity: sha512-xXR3KGeoxTNWPD4aBvL5NUpMTT7WMANr3EWnaS190QVkY52lqqcVRD7Q05UVbBhiWDGWMlJEUam9m7uFFGVScw==} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -6884,6 +7442,10 @@ packages: resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} engines: {node: '>=6'} + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + tar@7.5.13: resolution: {integrity: sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==} engines: {node: '>=18'} @@ -7165,6 +7727,10 @@ packages: warn-once@0.1.1: resolution: {integrity: sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==} + watchpack@2.5.2: + resolution: {integrity: sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg==} + engines: {node: '>=10.13.0'} + wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} @@ -7182,6 +7748,20 @@ packages: resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==} engines: {node: '>=8'} + webpack-sources@3.5.0: + resolution: {integrity: sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==} + engines: {node: '>=10.13.0'} + + webpack@5.108.3: + resolution: {integrity: sha512-hOpaCHmQVVY66IVTjofnH14IgSdmod2aquSGHGuYig/OIdWge01Hk2Wt988DZcwXumFUT4+FvJY5N+ikl8o/ww==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + websocket-driver@0.7.5: resolution: {integrity: sha512-ZL2+3c7kMBdIRCMz6l8jQMHyGVxj+UL+xVk74Ombiciboca8rHa15L86B19E5oh1pL9Ii/uj54gtsIrZGMo6zA==} engines: {node: '>=0.8.0'} @@ -7384,6 +7964,30 @@ snapshots: '@antfu/ni@0.23.2': {} + '@apm-js-collab/code-transformer-bundler-plugins@0.5.0': + dependencies: + '@apm-js-collab/code-transformer': 0.15.0 + es-module-lexer: 2.2.0 + magic-string: 0.30.21 + module-details-from-path: 1.0.4 + + '@apm-js-collab/code-transformer@0.15.0': + dependencies: + '@types/estree': 1.0.8 + astring: 1.9.0 + esquery: 1.7.0 + meriyah: 6.1.4 + semifies: 1.0.0 + source-map: 0.6.1 + + '@apm-js-collab/tracing-hooks@0.10.1': + dependencies: + '@apm-js-collab/code-transformer': 0.15.0 + debug: 4.4.3 + module-details-from-path: 1.0.4 + transitivePeerDependencies: + - supports-color + '@babel/code-frame@7.10.4': dependencies: '@babel/highlight': 7.25.9 @@ -9365,9 +9969,9 @@ snapshots: '@next/swc-win32-x64-msvc@16.2.0': optional: true - '@next/third-parties@16.2.9(next@16.2.0(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)': + '@next/third-parties@16.2.9(next@16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)': dependencies: - next: 16.2.0(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + next: 16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react: 19.1.0 third-party-capital: 1.0.20 @@ -9404,6 +10008,41 @@ snapshots: '@open-draft/until@2.1.0': {} + '@opentelemetry/api-logs@0.214.0': + dependencies: + '@opentelemetry/api': 1.9.1 + + '@opentelemetry/api@1.9.1': {} + + '@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/semantic-conventions': 1.41.1 + + '@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.214.0 + import-in-the-middle: 3.2.0 + require-in-the-middle: 8.0.1 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/resources@2.8.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + + '@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.8.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + + '@opentelemetry/semantic-conventions@1.41.1': {} + '@pkgjs/parseargs@0.11.0': optional: true @@ -10430,10 +11069,286 @@ snapshots: dependencies: nanoid: 3.3.11 + '@rollup/plugin-commonjs@28.0.1(rollup@4.62.2)': + dependencies: + '@rollup/pluginutils': 5.4.0(rollup@4.62.2) + commondir: 1.0.1 + estree-walker: 2.0.2 + fdir: 6.5.0(picomatch@4.0.4) + is-reference: 1.2.1 + magic-string: 0.30.21 + picomatch: 4.0.4 + optionalDependencies: + rollup: 4.62.2 + + '@rollup/pluginutils@5.4.0(rollup@4.62.2)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.4 + optionalDependencies: + rollup: 4.62.2 + + '@rollup/rollup-android-arm-eabi@4.62.2': + optional: true + + '@rollup/rollup-android-arm64@4.62.2': + optional: true + + '@rollup/rollup-darwin-arm64@4.62.2': + optional: true + + '@rollup/rollup-darwin-x64@4.62.2': + optional: true + + '@rollup/rollup-freebsd-arm64@4.62.2': + optional: true + + '@rollup/rollup-freebsd-x64@4.62.2': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.62.2': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.62.2': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.62.2': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.62.2': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.62.2': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.62.2': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.62.2': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.62.2': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.62.2': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.62.2': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.62.2': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.62.2': + optional: true + + '@rollup/rollup-linux-x64-musl@4.62.2': + optional: true + + '@rollup/rollup-openbsd-x64@4.62.2': + optional: true + + '@rollup/rollup-openharmony-arm64@4.62.2': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.62.2': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.62.2': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.62.2': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.62.2': + optional: true + '@rtsao/scc@1.1.0': {} '@sec-ant/readable-stream@0.4.1': {} + '@sentry/babel-plugin-component-annotate@5.3.0': {} + + '@sentry/browser-utils@10.63.0': + dependencies: + '@sentry/core': 10.63.0 + + '@sentry/browser@10.63.0': + dependencies: + '@sentry/browser-utils': 10.63.0 + '@sentry/core': 10.63.0 + '@sentry/feedback': 10.63.0 + '@sentry/replay': 10.63.0 + '@sentry/replay-canvas': 10.63.0 + + '@sentry/bundler-plugin-core@5.3.0': + dependencies: + '@babel/core': 7.29.0 + '@sentry/babel-plugin-component-annotate': 5.3.0 + '@sentry/cli': 2.58.6 + dotenv: 16.4.7 + find-up: 5.0.0 + glob: 13.0.6 + magic-string: 0.30.21 + transitivePeerDependencies: + - encoding + - supports-color + + '@sentry/cli-darwin@2.58.6': + optional: true + + '@sentry/cli-linux-arm64@2.58.6': + optional: true + + '@sentry/cli-linux-arm@2.58.6': + optional: true + + '@sentry/cli-linux-i686@2.58.6': + optional: true + + '@sentry/cli-linux-x64@2.58.6': + optional: true + + '@sentry/cli-win32-arm64@2.58.6': + optional: true + + '@sentry/cli-win32-i686@2.58.6': + optional: true + + '@sentry/cli-win32-x64@2.58.6': + optional: true + + '@sentry/cli@2.58.6': + dependencies: + https-proxy-agent: 5.0.1 + node-fetch: 2.7.0 + progress: 2.0.3 + proxy-from-env: 1.1.0 + which: 2.0.2 + optionalDependencies: + '@sentry/cli-darwin': 2.58.6 + '@sentry/cli-linux-arm': 2.58.6 + '@sentry/cli-linux-arm64': 2.58.6 + '@sentry/cli-linux-i686': 2.58.6 + '@sentry/cli-linux-x64': 2.58.6 + '@sentry/cli-win32-arm64': 2.58.6 + '@sentry/cli-win32-i686': 2.58.6 + '@sentry/cli-win32-x64': 2.58.6 + transitivePeerDependencies: + - encoding + - supports-color + + '@sentry/conventions@0.12.0': {} + + '@sentry/core@10.63.0': {} + + '@sentry/feedback@10.63.0': + dependencies: + '@sentry/core': 10.63.0 + + '@sentry/nextjs@10.63.0(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))(next@16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(webpack@5.108.3(postcss@8.5.8))': + dependencies: + '@opentelemetry/api': 1.9.1 + '@rollup/plugin-commonjs': 28.0.1(rollup@4.62.2) + '@sentry/browser-utils': 10.63.0 + '@sentry/bundler-plugin-core': 5.3.0 + '@sentry/conventions': 0.12.0 + '@sentry/core': 10.63.0 + '@sentry/node': 10.63.0(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1)) + '@sentry/opentelemetry': 10.63.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1)) + '@sentry/react': 10.63.0(react@19.1.0) + '@sentry/vercel-edge': 10.63.0 + '@sentry/webpack-plugin': 5.3.0(webpack@5.108.3(postcss@8.5.8)) + next: 16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + rollup: 4.62.2 + stacktrace-parser: 0.1.11 + transitivePeerDependencies: + - '@opentelemetry/core' + - '@opentelemetry/exporter-trace-otlp-http' + - '@opentelemetry/sdk-trace-base' + - encoding + - react + - supports-color + - webpack + + '@sentry/node-core@10.63.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))': + dependencies: + '@sentry/conventions': 0.12.0 + '@sentry/core': 10.63.0 + '@sentry/opentelemetry': 10.63.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1)) + import-in-the-middle: 3.2.0 + optionalDependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.8.0(@opentelemetry/api@1.9.1) + + '@sentry/node@10.63.0(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.8.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + '@sentry/conventions': 0.12.0 + '@sentry/core': 10.63.0 + '@sentry/node-core': 10.63.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1)) + '@sentry/opentelemetry': 10.63.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1)) + '@sentry/server-utils': 10.63.0 + import-in-the-middle: 3.2.0 + transitivePeerDependencies: + - '@opentelemetry/core' + - '@opentelemetry/exporter-trace-otlp-http' + - supports-color + + '@sentry/opentelemetry@10.63.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.8.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.8.0(@opentelemetry/api@1.9.1) + '@sentry/conventions': 0.12.0 + '@sentry/core': 10.63.0 + + '@sentry/react@10.63.0(react@19.1.0)': + dependencies: + '@sentry/browser': 10.63.0 + '@sentry/core': 10.63.0 + react: 19.1.0 + + '@sentry/replay-canvas@10.63.0': + dependencies: + '@sentry/core': 10.63.0 + '@sentry/replay': 10.63.0 + + '@sentry/replay@10.63.0': + dependencies: + '@sentry/browser-utils': 10.63.0 + '@sentry/core': 10.63.0 + + '@sentry/server-utils@10.63.0': + dependencies: + '@apm-js-collab/code-transformer': 0.15.0 + '@apm-js-collab/code-transformer-bundler-plugins': 0.5.0 + '@apm-js-collab/tracing-hooks': 0.10.1 + '@sentry/conventions': 0.12.0 + '@sentry/core': 10.63.0 + magic-string: 0.30.21 + transitivePeerDependencies: + - supports-color + + '@sentry/vercel-edge@10.63.0': + dependencies: + '@opentelemetry/api': 1.9.1 + '@sentry/core': 10.63.0 + + '@sentry/webpack-plugin@5.3.0(webpack@5.108.3(postcss@8.5.8))': + dependencies: + '@sentry/bundler-plugin-core': 5.3.0 + webpack: 5.108.3(postcss@8.5.8) + transitivePeerDependencies: + - encoding + - supports-color + '@sinclair/typebox@0.27.10': {} '@sindresorhus/merge-streams@4.0.0': {} @@ -10693,6 +11608,8 @@ snapshots: '@types/estree@1.0.8': {} + '@types/estree@1.0.9': {} + '@types/graceful-fs@4.1.9': dependencies: '@types/node': 22.15.3 @@ -10907,8 +11824,88 @@ snapshots: '@urql/core': 5.2.0(graphql@16.14.0) wonka: 6.3.6 + '@webassemblyjs/ast@1.14.1': + dependencies: + '@webassemblyjs/helper-numbers': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + + '@webassemblyjs/floating-point-hex-parser@1.13.2': {} + + '@webassemblyjs/helper-api-error@1.13.2': {} + + '@webassemblyjs/helper-buffer@1.14.1': {} + + '@webassemblyjs/helper-numbers@1.13.2': + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.13.2 + '@webassemblyjs/helper-api-error': 1.13.2 + '@xtuc/long': 4.2.2 + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} + + '@webassemblyjs/helper-wasm-section@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/wasm-gen': 1.14.1 + + '@webassemblyjs/ieee754@1.13.2': + dependencies: + '@xtuc/ieee754': 1.2.0 + + '@webassemblyjs/leb128@1.13.2': + dependencies: + '@xtuc/long': 4.2.2 + + '@webassemblyjs/utf8@1.13.2': {} + + '@webassemblyjs/wasm-edit@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/helper-wasm-section': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-opt': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wast-printer': 1.14.1 + + '@webassemblyjs/wasm-gen@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wasm-opt@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + + '@webassemblyjs/wasm-parser@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-api-error': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wast-printer@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@xtuc/long': 4.2.2 + '@xmldom/xmldom@0.8.12': {} + '@xtuc/ieee754@1.2.0': {} + + '@xtuc/long@4.2.2': {} + abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 @@ -10923,18 +11920,43 @@ snapshots: mime-types: 3.0.2 negotiator: 1.0.0 + acorn-import-attributes@1.9.5(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn-import-phases@1.0.4(acorn@8.17.0): + dependencies: + acorn: 8.17.0 + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 acorn@8.15.0: {} + acorn@8.17.0: {} + + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + agent-base@7.1.4: {} + ajv-formats@2.1.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + ajv-formats@3.0.1(ajv@8.20.0): optionalDependencies: ajv: 8.20.0 + ajv-keywords@5.1.0(ajv@8.20.0): + dependencies: + ajv: 8.20.0 + fast-deep-equal: 3.1.3 + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -11077,6 +12099,8 @@ snapshots: dependencies: tslib: 2.8.1 + astring@1.9.0: {} + async-function@1.0.0: {} async-limiter@1.0.1: {} @@ -11377,6 +12401,8 @@ snapshots: transitivePeerDependencies: - supports-color + chrome-trace-event@1.0.4: {} + chromium-edge-launcher@0.2.0: dependencies: '@types/node': 22.15.3 @@ -11392,6 +12418,8 @@ snapshots: ci-info@3.9.0: {} + cjs-module-lexer@2.2.0: {} + class-variance-authority@0.7.1: dependencies: clsx: 2.1.1 @@ -11460,6 +12488,8 @@ snapshots: commander@7.2.0: {} + commondir@1.0.1: {} + compressible@2.0.18: dependencies: mime-db: 1.54.0 @@ -11748,6 +12778,11 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.2 + enhanced-resolve@5.24.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + entities@4.5.0: {} env-editor@0.4.2: {} @@ -11842,6 +12877,8 @@ snapshots: iterator.prototype: 1.1.5 safe-array-concat: 1.1.3 + es-module-lexer@2.2.0: {} + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -12054,6 +13091,11 @@ snapshots: optionalDependencies: '@typescript-eslint/eslint-plugin': 8.50.0(@typescript-eslint/parser@8.50.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.2))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.2) + eslint-scope@5.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + eslint-scope@8.4.0: dependencies: esrecurse: 4.3.0 @@ -12116,18 +13158,28 @@ snapshots: dependencies: estraverse: 5.3.0 + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + esrecurse@4.3.0: dependencies: estraverse: 5.3.0 + estraverse@4.3.0: {} + estraverse@5.3.0: {} + estree-walker@2.0.2: {} + esutils@2.0.3: {} etag@1.8.1: {} event-target-shim@5.0.1: {} + events@3.3.0: {} + eventsource-parser@3.0.8: {} eventsource@3.0.7: @@ -12898,6 +13950,13 @@ snapshots: http-parser-js@0.5.10: {} + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 @@ -12932,6 +13991,13 @@ snapshots: parent-module: 1.0.1 resolve-from: 4.0.0 + import-in-the-middle@3.2.0: + dependencies: + acorn: 8.15.0 + acorn-import-attributes: 1.9.5(acorn@8.15.0) + cjs-module-lexer: 2.2.0 + module-details-from-path: 1.0.4 + imurmurhash@0.1.4: {} inflight@1.0.6: @@ -13069,6 +14135,10 @@ snapshots: is-promise@4.0.0: {} + is-reference@1.2.1: + dependencies: + '@types/estree': 1.0.8 + is-regex@1.2.1: dependencies: call-bound: 1.0.4 @@ -13226,6 +14296,12 @@ snapshots: leven: 3.1.0 pretty-format: 29.7.0 + jest-worker@27.5.1: + dependencies: + '@types/node': 22.15.3 + merge-stream: 2.0.0 + supports-color: 8.1.1 + jest-worker@29.7.0: dependencies: '@types/node': 22.15.3 @@ -13368,6 +14444,8 @@ snapshots: lines-and-columns@1.2.4: {} + loader-runner@4.3.2: {} + locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -13443,6 +14521,8 @@ snapshots: merge2@1.4.1: {} + meriyah@6.1.4: {} + metro-babel-transformer@0.83.3: dependencies: '@babel/core': 7.29.0 @@ -13831,6 +14911,16 @@ snapshots: minimist@1.2.8: {} + minimizer-webpack-plugin@5.6.1(postcss@8.5.8)(webpack@5.108.3(postcss@8.5.8)): + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + jest-worker: 27.5.1 + schema-utils: 4.3.3 + terser: 5.46.1 + webpack: 5.108.3(postcss@8.5.8) + optionalDependencies: + postcss: 8.5.8 + minipass@7.1.3: {} minizlib@3.1.0: @@ -13839,6 +14929,8 @@ snapshots: mkdirp@1.0.4: {} + module-details-from-path@1.0.4: {} + ms@2.0.0: {} ms@2.1.3: {} @@ -13888,9 +14980,11 @@ snapshots: negotiator@1.0.0: {} + neo-async@2.6.2: {} + nested-error-stacks@2.0.1: {} - next@16.2.0(@babel/core@7.29.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + next@16.2.0(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): dependencies: '@next/env': 16.2.0 '@swc/helpers': 0.5.15 @@ -13909,6 +15003,7 @@ snapshots: '@next/swc-linux-x64-musl': 16.2.0 '@next/swc-win32-arm64-msvc': 16.2.0 '@next/swc-win32-x64-msvc': 16.2.0 + '@opentelemetry/api': 1.9.1 babel-plugin-react-compiler: 1.0.0 sharp: 0.34.5 transitivePeerDependencies: @@ -14299,6 +15394,8 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 + proxy-from-env@1.1.0: {} + proxy-from-env@2.1.0: {} punycode@2.3.1: {} @@ -14650,6 +15747,13 @@ snapshots: require-from-string@2.0.2: {} + require-in-the-middle@8.0.1: + dependencies: + debug: 4.4.3 + module-details-from-path: 1.0.4 + transitivePeerDependencies: + - supports-color + requireg@0.2.2: dependencies: nested-error-stacks: 2.0.1 @@ -14712,6 +15816,37 @@ snapshots: dependencies: glob: 7.2.3 + rollup@4.62.2: + dependencies: + '@types/estree': 1.0.9 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.62.2 + '@rollup/rollup-android-arm64': 4.62.2 + '@rollup/rollup-darwin-arm64': 4.62.2 + '@rollup/rollup-darwin-x64': 4.62.2 + '@rollup/rollup-freebsd-arm64': 4.62.2 + '@rollup/rollup-freebsd-x64': 4.62.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.62.2 + '@rollup/rollup-linux-arm-musleabihf': 4.62.2 + '@rollup/rollup-linux-arm64-gnu': 4.62.2 + '@rollup/rollup-linux-arm64-musl': 4.62.2 + '@rollup/rollup-linux-loong64-gnu': 4.62.2 + '@rollup/rollup-linux-loong64-musl': 4.62.2 + '@rollup/rollup-linux-ppc64-gnu': 4.62.2 + '@rollup/rollup-linux-ppc64-musl': 4.62.2 + '@rollup/rollup-linux-riscv64-gnu': 4.62.2 + '@rollup/rollup-linux-riscv64-musl': 4.62.2 + '@rollup/rollup-linux-s390x-gnu': 4.62.2 + '@rollup/rollup-linux-x64-gnu': 4.62.2 + '@rollup/rollup-linux-x64-musl': 4.62.2 + '@rollup/rollup-openbsd-x64': 4.62.2 + '@rollup/rollup-openharmony-arm64': 4.62.2 + '@rollup/rollup-win32-arm64-msvc': 4.62.2 + '@rollup/rollup-win32-ia32-msvc': 4.62.2 + '@rollup/rollup-win32-x64-gnu': 4.62.2 + '@rollup/rollup-win32-x64-msvc': 4.62.2 + fsevents: 2.3.3 + router@2.2.0: dependencies: debug: 4.4.3 @@ -14755,6 +15890,15 @@ snapshots: scheduler@0.26.0: {} + schema-utils@4.3.3: + dependencies: + '@types/json-schema': 7.0.15 + ajv: 8.20.0 + ajv-formats: 2.1.1(ajv@8.20.0) + ajv-keywords: 5.1.0(ajv@8.20.0) + + semifies@1.0.0: {} + semver@6.3.1: {} semver@7.6.3: {} @@ -15210,6 +16354,8 @@ snapshots: tapable@2.3.2: {} + tapable@2.3.3: {} + tar@7.5.13: dependencies: '@isaacs/fs-minipass': 4.0.1 @@ -15508,6 +16654,10 @@ snapshots: warn-once@0.1.1: {} + watchpack@2.5.2: + dependencies: + graceful-fs: 4.2.11 + wcwidth@1.0.1: dependencies: defaults: 1.0.4 @@ -15520,6 +16670,46 @@ snapshots: webidl-conversions@5.0.0: {} + webpack-sources@3.5.0: {} + + webpack@5.108.3(postcss@8.5.8): + dependencies: + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.17.0 + acorn-import-phases: 1.0.4(acorn@8.17.0) + browserslist: 4.28.2 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.24.1 + es-module-lexer: 2.2.0 + eslint-scope: 5.1.1 + events: 3.3.0 + graceful-fs: 4.2.11 + loader-runner: 4.3.2 + mime-db: 1.54.0 + minimizer-webpack-plugin: 5.6.1(postcss@8.5.8)(webpack@5.108.3(postcss@8.5.8)) + neo-async: 2.6.2 + schema-utils: 4.3.3 + tapable: 2.3.2 + watchpack: 2.5.2 + webpack-sources: 3.5.0 + transitivePeerDependencies: + - '@minify-html/node' + - '@swc/core' + - '@swc/css' + - '@swc/html' + - clean-css + - cssnano + - csso + - esbuild + - html-minifier-terser + - lightningcss + - postcss + - uglify-js + websocket-driver@0.7.5: dependencies: http-parser-js: 0.5.10 diff --git a/turbo.json b/turbo.json index 837390a4..0a37f57c 100644 --- a/turbo.json +++ b/turbo.json @@ -11,7 +11,12 @@ "VERCEL_GIT_COMMIT_REF", "VERCEL_GIT_REPO_OWNER", "VERCEL_GIT_REPO_SLUG", - "GITHUB_TOKEN" + "GITHUB_TOKEN", + "CI", + "NEXT_RUNTIME", + "NEXT_PUBLIC_STAGE", + "NEXT_PUBLIC_SENTRY_DSN", + "SENTRY_AUTH_TOKEN" ], "outputs": [".next/**", "!.next/cache/**"] }, From 75fa3479ded26d5ee4f7fc450d19456980775b7c Mon Sep 17 00:00:00 2001 From: Jung Sun A Date: Thu, 2 Jul 2026 10:30:28 +0900 Subject: [PATCH 02/12] =?UTF-8?q?feat:=20app=20Sentry=20=EC=97=90=EB=9F=AC?= =?UTF-8?q?=20=EB=AA=A8=EB=8B=88=ED=84=B0=EB=A7=81=20=EB=8F=84=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/app/app.json | 7 ++ apps/app/app/_layout.tsx | 16 ++- apps/app/metro.config.js | 5 +- apps/app/package.json | 1 + pnpm-lock.yaml | 209 ++++++++++++++++++++++++++++++++++++++- 5 files changed, 233 insertions(+), 5 deletions(-) diff --git a/apps/app/app.json b/apps/app/app.json index 2733db92..386e1e12 100644 --- a/apps/app/app.json +++ b/apps/app/app.json @@ -149,6 +149,13 @@ { "nativeAppKey": "326734abdf8de5c7e090a2fc72e1dce6" } + ], + [ + "@sentry/react-native", + { + "organization": "piki-92", + "project": "piki-app" + } ] ], "experiments": { diff --git a/apps/app/app/_layout.tsx b/apps/app/app/_layout.tsx index 75d4d2e3..c409c878 100644 --- a/apps/app/app/_layout.tsx +++ b/apps/app/app/_layout.tsx @@ -1,5 +1,6 @@ import { GoogleSignin } from '@react-native-google-signin/google-signin'; import { initializeKakaoSDK } from '@react-native-kakao/core'; +import * as Sentry from '@sentry/react-native'; import { Stack } from 'expo-router'; import { ShareIntentProvider } from 'expo-share-intent'; import * as SplashScreen from 'expo-splash-screen'; @@ -9,6 +10,19 @@ import 'react-native-reanimated'; import PushNotificationProvider from '@/components/PushNotificationProvider'; import { SplashScreenControllerProvider } from '@/hooks/useSplashScreenController'; +/** 배포 환경(production/staging/dev). Sentry 는 production/staging 에서만 수집 (dev·로컬 비활성) */ +const stage = process.env.EXPO_PUBLIC_STAGE; + +Sentry.init({ + dsn: process.env.EXPO_PUBLIC_SENTRY_DSN, + environment: stage, + enabled: stage === 'production' || stage === 'staging', + /** Performance(Tracing)는 초기엔 off */ + tracesSampleRate: 0, + /** PII 기본 마스킹 (Session Replay 는 web 만, 앱은 에러/크래시만) */ + sendDefaultPii: false, +}); + initializeKakaoSDK(process.env.EXPO_PUBLIC_KAKAO_NATIVE_APP_KEY ?? ''); GoogleSignin.configure({ @@ -34,4 +48,4 @@ function RootLayout() { ); } -export default RootLayout; +export default Sentry.wrap(RootLayout); diff --git a/apps/app/metro.config.js b/apps/app/metro.config.js index 961981e8..1a5dcac8 100644 --- a/apps/app/metro.config.js +++ b/apps/app/metro.config.js @@ -1,5 +1,5 @@ // eslint-disable-next-line @typescript-eslint/no-require-imports -const { getDefaultConfig } = require('expo/metro-config'); +const { getSentryExpoConfig } = require('@sentry/react-native/metro'); // eslint-disable-next-line @typescript-eslint/no-require-imports const { withShareExtension } = require('expo-share-extension/metro'); // eslint-disable-next-line @typescript-eslint/no-require-imports @@ -8,7 +8,8 @@ const path = require('path'); const projectRoot = __dirname; const workspaceRoot = path.resolve(projectRoot, '../..'); -const config = getDefaultConfig(projectRoot); +/** Sentry 소스맵(Debug ID) 생성을 위해 getDefaultConfig 대신 사용 */ +const config = getSentryExpoConfig(projectRoot); config.watchFolders = [workspaceRoot]; config.resolver.nodeModulesPaths = [ diff --git a/apps/app/package.json b/apps/app/package.json index ebd33534..50e967c3 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -24,6 +24,7 @@ "@react-navigation/bottom-tabs": "^7.4.0", "@react-navigation/elements": "^2.6.3", "@react-navigation/native": "^7.1.8", + "@sentry/react-native": "~7.2.0", "expo": "~54.0.33", "expo-apple-authentication": "~8.0.8", "expo-application": "^7.0.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 970b267b..23cb2ea7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -94,6 +94,9 @@ importers: '@react-navigation/native': specifier: ^7.1.8 version: 7.2.2(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + '@sentry/react-native': + specifier: ~7.2.0 + version: 7.2.0(expo@54.0.33)(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) expo: specifier: ~54.0.33 version: 54.0.33(@babel/core@7.29.0)(@expo/metro-runtime@6.1.2)(expo-router@6.0.23)(graphql@16.14.0)(react-native-webview@13.16.1(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.2) @@ -2979,6 +2982,26 @@ packages: '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + '@sentry-internal/browser-utils@10.12.0': + resolution: {integrity: sha512-dozbx389jhKynj0d657FsgbBVOar7pX3mb6GjqCxslXF0VKpZH2Xks0U32RgDY/nK27O+o095IWz7YvjVmPkDw==} + engines: {node: '>=18'} + + '@sentry-internal/feedback@10.12.0': + resolution: {integrity: sha512-0+7ceO6yQPPqfxRc9ue/xoPHKcnB917ezPaehGQNfAFNQB9PNTG1y55+8mRu0Fw+ANbZeCt/HyoCmXuRdxmkpg==} + engines: {node: '>=18'} + + '@sentry-internal/replay-canvas@10.12.0': + resolution: {integrity: sha512-W/z1/+69i3INNfPjD1KuinSNaRQaApjzwb37IFmiyF440F93hxmEYgXHk3poOlYYaigl2JMYbysGPWOiXnqUXA==} + engines: {node: '>=18'} + + '@sentry-internal/replay@10.12.0': + resolution: {integrity: sha512-/1093gSNGN5KlOBsuyAl33JkzGiG38kCnxswQLZWpPpR6LBbR1Ddb18HjhDpoQNNEZybJBgJC3a5NKl43C2TSQ==} + engines: {node: '>=18'} + + '@sentry/babel-plugin-component-annotate@4.3.0': + resolution: {integrity: sha512-OuxqBprXRyhe8Pkfyz/4yHQJc5c3lm+TmYWSSx8u48g5yKewSQDOxkiLU5pAk3WnbLPy8XwU/PN+2BG0YFU9Nw==} + engines: {node: '>= 14'} + '@sentry/babel-plugin-component-annotate@5.3.0': resolution: {integrity: sha512-p4q8gn8wcFqZGP/s2MnJCAAd8fTikaU6A0mM97RDHQgStcrYiaS0Sc5zUNfb1V+UOLPuvdEdL6MwyxfzjYJQTA==} engines: {node: '>= 18'} @@ -2987,6 +3010,10 @@ packages: resolution: {integrity: sha512-DhUGNN+CH8fzAs6qAsueKPU70qShyTX3NxLhIP+l5DbGXDSXpYXBT6s8ubZus0/LhxpLvI0iSyNIDvZRD/gZaA==} engines: {node: '>=18'} + '@sentry/browser@10.12.0': + resolution: {integrity: sha512-lKyaB2NFmr7SxPjmMTLLhQ7xfxaY3kdkMhpzuRI5qwOngtKt4+FtvNYHRuz+PTtEFv4OaHhNNbRn6r91gWguQg==} + engines: {node: '>=18'} + '@sentry/browser@10.63.0': resolution: {integrity: sha512-0mi56YOkwgyjdLOcN5cB1//EcYzEOt3NZ2GLygE92B3zAAwVM1WgbmibZCXToKFClH7z1uH3VWVfBffmkwIMYw==} engines: {node: '>=18'} @@ -2995,53 +3022,105 @@ packages: resolution: {integrity: sha512-L5T60sWdAI3qWwdg3Ptwek/0TY59PERrxyqp4XMUkroayQvGd9r5dIW9Q1kSeXX9iJ442nXbFZKAOyCKV4Z13Q==} engines: {node: '>= 18'} + '@sentry/cli-darwin@2.55.0': + resolution: {integrity: sha512-jGHE7SHHzqXUmnsmRLgorVH6nmMmTjQQXdPZbSL5tRtH8d3OIYrVNr5D72DSgD26XAPBDMV0ibqOQ9NKoiSpfA==} + engines: {node: '>=10'} + os: [darwin] + '@sentry/cli-darwin@2.58.6': resolution: {integrity: sha512-udAVvcyfNa0R+95GvPz/+43/N3TC0TYKdkQ7D7jhPSzbcMc7l2fxRNN5yB3UpCA5fWFnW4toeaqwDBhb/Wh3LA==} engines: {node: '>=10'} os: [darwin] + '@sentry/cli-linux-arm64@2.55.0': + resolution: {integrity: sha512-jNB/0/gFcOuDCaY/TqeuEpsy/k52dwyk1SOV3s1ku4DUsln6govTppeAGRewY3T1Rj9B2vgIWTrnB8KVh9+Rgg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux, freebsd, android] + '@sentry/cli-linux-arm64@2.58.6': resolution: {integrity: sha512-q8mEcNNmeXMy5i+jWT30TVpH7LcP4HD21CD5XRSPAd/a912HF6EpK0ybf/1USO14WOhoXbAGi9txwaWabSe33g==} engines: {node: '>=10'} cpu: [arm64] os: [linux, freebsd, android] + '@sentry/cli-linux-arm@2.55.0': + resolution: {integrity: sha512-ATjU0PsiWADSPLF/kZroLZ7FPKd5W9TDWHVkKNwIUNTei702LFgTjNeRwOIzTgSvG3yTmVEqtwFQfFN/7hnVXQ==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux, freebsd, android] + '@sentry/cli-linux-arm@2.58.6': resolution: {integrity: sha512-pD0LAt5PcUzAinBwvDqc66x9+2CabHEv486yP0gRjWO7SakbaxmfVq/EXd8VLq/Tzi39LAu422UYK1lpW3MILw==} engines: {node: '>=10'} cpu: [arm] os: [linux, freebsd, android] + '@sentry/cli-linux-i686@2.55.0': + resolution: {integrity: sha512-8LZjo6PncTM6bWdaggscNOi5r7F/fqRREsCwvd51dcjGj7Kp1plqo9feEzYQ+jq+KUzVCiWfHrUjddFmYyZJrg==} + engines: {node: '>=10'} + cpu: [x86, ia32] + os: [linux, freebsd, android] + '@sentry/cli-linux-i686@2.58.6': resolution: {integrity: sha512-q8vNJi1eOV/4vxAFWBsEwLHoSYapaZHIf4j76KJGJXFKTkEbsjCOOsKbwUIBTQQhRgV4DFWh3ryfsPS/que4Kg==} engines: {node: '>=10'} cpu: [x86, ia32] os: [linux, freebsd, android] + '@sentry/cli-linux-x64@2.55.0': + resolution: {integrity: sha512-5LUVvq74Yj2cZZy5g5o/54dcWEaX4rf3myTHy73AKhRj1PABtOkfexOLbF9xSrZy95WXWaXyeH+k5n5z/vtHfA==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux, freebsd, android] + '@sentry/cli-linux-x64@2.58.6': resolution: {integrity: sha512-DZu956Mhi3ZRjTBe1WdbGV46ldVbA8d2rgp/fh51GsI25zjBHah4wZnPTSzpc+YqxU6pJpg579B/r3jrIK530Q==} engines: {node: '>=10'} cpu: [x64] os: [linux, freebsd, android] + '@sentry/cli-win32-arm64@2.55.0': + resolution: {integrity: sha512-cWIQdzm1pfLwPARsV6dUb8TVd6Y3V1A2VWxjTons3Ift6GvtVmiAe0OWL8t2Yt95i8v61kTD/6Tq21OAaogqzA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + '@sentry/cli-win32-arm64@2.58.6': resolution: {integrity: sha512-nj0Ff/kmAB73EPDhR8B4O9r+NUHK5GkPCkGWC+kXVemqAJWL5jcJ5KdxG0l/S0z6RoEoltID8/43/B+TaMlT7A==} engines: {node: '>=10'} cpu: [arm64] os: [win32] + '@sentry/cli-win32-i686@2.55.0': + resolution: {integrity: sha512-ldepCn2t9r4I0wvgk7NRaA7coJyy4rTQAzM66u9j5nTEsUldf66xym6esd5ZZRAaJUjffqvHqUIr/lrieTIrVg==} + engines: {node: '>=10'} + cpu: [x86, ia32] + os: [win32] + '@sentry/cli-win32-i686@2.58.6': resolution: {integrity: sha512-WNZiDzPbgsEMQWq4avsQ391v/xWKJDIWWWo9GYl+N/w5qcYKkoDW7wQG7T9FasI6ENn68phChTOAPXXxbfAdOg==} engines: {node: '>=10'} cpu: [x86, ia32] os: [win32] + '@sentry/cli-win32-x64@2.55.0': + resolution: {integrity: sha512-4hPc/I/9tXx+HLTdTGwlagtAfDSIa2AoTUP30tl32NAYQhx9a6niUbPAemK2qfxesiufJ7D2djX83rCw6WnJVA==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + '@sentry/cli-win32-x64@2.58.6': resolution: {integrity: sha512-R35WJ17oF4D2eqI1DR2sQQqr0fjRTt5xoP16WrTu91XM2lndRMFsnjh+/GttbxapLCBNlrjzia99MJ0PZHZpgA==} engines: {node: '>=10'} cpu: [x64] os: [win32] + '@sentry/cli@2.55.0': + resolution: {integrity: sha512-cynvcIM2xL8ddwELyFRSpZQw4UtFZzoM2rId2l9vg7+wDREPDocMJB9lEQpBIo3eqhp9JswqUT037yjO6iJ5Sw==} + engines: {node: '>= 10'} + hasBin: true + '@sentry/cli@2.58.6': resolution: {integrity: sha512-baBcNPLLfUi9WuL+Tpri9BFaAdvugZIKelC5X0tt0Zdy+K0K+PCVSrnNmwMWU/HyaF/SEv6b6UHnXIdqanBlcg==} engines: {node: '>= 10'} @@ -3051,6 +3130,10 @@ packages: resolution: {integrity: sha512-z1JQrl/1SLY+8wpzvork6vl+fpsg/oCCxM7HWWhUnI/R+OGNyoIzieQuggX3uUMY7NBtp8UWCQx6FeFazzOF9g==} engines: {node: '>=14'} + '@sentry/core@10.12.0': + resolution: {integrity: sha512-Jrf0Yo7DvmI/ZQcvBnA0xKNAFkJlVC/fMlvcin+5IrFNRcqOToZ2vtF+XqTgjRZymXQNE8s1QTD7IomPHk0TAw==} + engines: {node: '>=18'} + '@sentry/core@10.63.0': resolution: {integrity: sha512-OtUbsrnbEHffOF2S2+M5zXa3HIM0U2b4CDVLKMY1dgS0J3ivRF8XvkjvyIcEG/y8JXnwXbnprLyjhG+AqMdUZQ==} engines: {node: '>=18'} @@ -3098,6 +3181,23 @@ packages: '@opentelemetry/core': ^1.30.1 || ^2.1.0 '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 + '@sentry/react-native@7.2.0': + resolution: {integrity: sha512-rjqYgEjntPz1sPysud78wi4B9ui7LBVPsG6qr8s/htLMYho9GPGFA5dF+eqsQWqMX8NDReAxNkLTC4+gCNklLQ==} + hasBin: true + peerDependencies: + expo: '>=49.0.0' + react: 19.1.0 + react-native: '>=0.65.0' + peerDependenciesMeta: + expo: + optional: true + + '@sentry/react@10.12.0': + resolution: {integrity: sha512-TpqgdoYbkf5JynmmW2oQhHQ/h5w+XPYk0cEb/UrsGlvJvnBSR+5tgh0AqxCSi3gvtp82rAXI5w1TyRPBbhLDBw==} + engines: {node: '>=18'} + peerDependencies: + react: 19.1.0 + '@sentry/react@10.63.0': resolution: {integrity: sha512-+/Y0dd4EMqyqYBJ1D3bAYYuG+ccIx5+IFcbTZ9p+XWnW6nNIVjy5zttVftYo6xOmtTQbzRuPT/vO4dqDHKKmfw==} engines: {node: '>=18'} @@ -3116,6 +3216,10 @@ packages: resolution: {integrity: sha512-7NN//DG9Yak8t2+6WiEcNmN269iHRVdtZtZIwucEd0OXyZ3FEBBDaBF+bT9V6H/kPtUvVMkHQ72Bn2Xs5JYGxg==} engines: {node: '>=18'} + '@sentry/types@10.12.0': + resolution: {integrity: sha512-sKGj3l3V8ZKISh2Tu88bHfnm5ztkRtSLdmpZ6TmCeJdSM9pV+RRd6CMJ0RnSEXmYHselPNUod521t2NQFd4W1w==} + engines: {node: '>=18'} + '@sentry/vercel-edge@10.63.0': resolution: {integrity: sha512-6vay7/Skgjt1SiDchobaN7mOeSDRwhQUikVvuT7Q/0nX5Xg5TRlSMbqwcllqKxwDXdJiW3MVdqqLixY1c8WjJA==} engines: {node: '>=18'} @@ -11168,12 +11272,40 @@ snapshots: '@sec-ant/readable-stream@0.4.1': {} + '@sentry-internal/browser-utils@10.12.0': + dependencies: + '@sentry/core': 10.12.0 + + '@sentry-internal/feedback@10.12.0': + dependencies: + '@sentry/core': 10.12.0 + + '@sentry-internal/replay-canvas@10.12.0': + dependencies: + '@sentry-internal/replay': 10.12.0 + '@sentry/core': 10.12.0 + + '@sentry-internal/replay@10.12.0': + dependencies: + '@sentry-internal/browser-utils': 10.12.0 + '@sentry/core': 10.12.0 + + '@sentry/babel-plugin-component-annotate@4.3.0': {} + '@sentry/babel-plugin-component-annotate@5.3.0': {} '@sentry/browser-utils@10.63.0': dependencies: '@sentry/core': 10.63.0 + '@sentry/browser@10.12.0': + dependencies: + '@sentry-internal/browser-utils': 10.12.0 + '@sentry-internal/feedback': 10.12.0 + '@sentry-internal/replay': 10.12.0 + '@sentry-internal/replay-canvas': 10.12.0 + '@sentry/core': 10.12.0 + '@sentry/browser@10.63.0': dependencies: '@sentry/browser-utils': 10.63.0 @@ -11195,30 +11327,74 @@ snapshots: - encoding - supports-color + '@sentry/cli-darwin@2.55.0': + optional: true + '@sentry/cli-darwin@2.58.6': optional: true + '@sentry/cli-linux-arm64@2.55.0': + optional: true + '@sentry/cli-linux-arm64@2.58.6': optional: true + '@sentry/cli-linux-arm@2.55.0': + optional: true + '@sentry/cli-linux-arm@2.58.6': optional: true + '@sentry/cli-linux-i686@2.55.0': + optional: true + '@sentry/cli-linux-i686@2.58.6': optional: true + '@sentry/cli-linux-x64@2.55.0': + optional: true + '@sentry/cli-linux-x64@2.58.6': optional: true + '@sentry/cli-win32-arm64@2.55.0': + optional: true + '@sentry/cli-win32-arm64@2.58.6': optional: true + '@sentry/cli-win32-i686@2.55.0': + optional: true + '@sentry/cli-win32-i686@2.58.6': optional: true + '@sentry/cli-win32-x64@2.55.0': + optional: true + '@sentry/cli-win32-x64@2.58.6': optional: true + '@sentry/cli@2.55.0': + dependencies: + https-proxy-agent: 5.0.1 + node-fetch: 2.7.0 + progress: 2.0.3 + proxy-from-env: 1.1.0 + which: 2.0.2 + optionalDependencies: + '@sentry/cli-darwin': 2.55.0 + '@sentry/cli-linux-arm': 2.55.0 + '@sentry/cli-linux-arm64': 2.55.0 + '@sentry/cli-linux-i686': 2.55.0 + '@sentry/cli-linux-x64': 2.55.0 + '@sentry/cli-win32-arm64': 2.55.0 + '@sentry/cli-win32-i686': 2.55.0 + '@sentry/cli-win32-x64': 2.55.0 + transitivePeerDependencies: + - encoding + - supports-color + '@sentry/cli@2.58.6': dependencies: https-proxy-agent: 5.0.1 @@ -11241,6 +11417,8 @@ snapshots: '@sentry/conventions@0.12.0': {} + '@sentry/core@10.12.0': {} + '@sentry/core@10.63.0': {} '@sentry/feedback@10.63.0': @@ -11309,6 +11487,29 @@ snapshots: '@sentry/conventions': 0.12.0 '@sentry/core': 10.63.0 + '@sentry/react-native@7.2.0(expo@54.0.33)(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)': + dependencies: + '@sentry/babel-plugin-component-annotate': 4.3.0 + '@sentry/browser': 10.12.0 + '@sentry/cli': 2.55.0 + '@sentry/core': 10.12.0 + '@sentry/react': 10.12.0(react@19.1.0) + '@sentry/types': 10.12.0 + react: 19.1.0 + react-native: 0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0) + optionalDependencies: + expo: 54.0.33(@babel/core@7.29.0)(@expo/metro-runtime@6.1.2)(expo-router@6.0.23)(graphql@16.14.0)(react-native-webview@13.16.1(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.2) + transitivePeerDependencies: + - encoding + - supports-color + + '@sentry/react@10.12.0(react@19.1.0)': + dependencies: + '@sentry/browser': 10.12.0 + '@sentry/core': 10.12.0 + hoist-non-react-statics: 3.3.2 + react: 19.1.0 + '@sentry/react@10.63.0(react@19.1.0)': dependencies: '@sentry/browser': 10.63.0 @@ -11336,6 +11537,10 @@ snapshots: transitivePeerDependencies: - supports-color + '@sentry/types@10.12.0': + dependencies: + '@sentry/core': 10.12.0 + '@sentry/vercel-edge@10.63.0': dependencies: '@opentelemetry/api': 1.9.1 @@ -16674,7 +16879,7 @@ snapshots: webpack@5.108.3(postcss@8.5.8): dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/json-schema': 7.0.15 '@webassemblyjs/ast': 1.14.1 '@webassemblyjs/wasm-edit': 1.14.1 @@ -16693,7 +16898,7 @@ snapshots: minimizer-webpack-plugin: 5.6.1(postcss@8.5.8)(webpack@5.108.3(postcss@8.5.8)) neo-async: 2.6.2 schema-utils: 4.3.3 - tapable: 2.3.2 + tapable: 2.3.3 watchpack: 2.5.2 webpack-sources: 3.5.0 transitivePeerDependencies: From 522f5da38c74534e9fe782313eeba89725cdb2d2 Mon Sep 17 00:00:00 2001 From: Jung Sun A Date: Thu, 2 Jul 2026 10:30:52 +0900 Subject: [PATCH 03/12] =?UTF-8?q?feat:=20web/app=20sentry=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EB=A1=9C=EA=B9=85=20=EA=B7=9C=EC=95=BD=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - app: @sentry/react-native 셋업(_layout init+wrap, metro, 플러그인, eas 환경별 주입) - 공용 captureError 유틸(web/app) — 태그/컨텍스트 일관 부착 - API 5xx·네트워크 에러 중앙 수집(axios 인터셉터 / app fetch) - 유저 식별 setUser(id), 세션 만료 시 해제 - error.tsx 캡처, ignoreErrors 노이즈 필터 - app WebView onError/onHttpError, 백그라운드 FCM 핸들러 수집 --- apps/app/apis/postSocialLogin.ts | 36 ++++++++++++++++++++++-------- apps/app/app/_layout.tsx | 13 +---------- apps/app/app/index.tsx | 32 +++++++++++++++++++++++++- apps/app/index.js | 27 ++++++++++++++++++---- apps/app/types/env.d.ts | 3 +++ apps/app/utils/captureError.ts | 16 +++++++++++++ apps/web/instrumentation-client.ts | 11 +++++++++ apps/web/src/apis/client.ts | 24 ++++++++++++++++++++ apps/web/src/apis/server.ts | 29 ++++++++++++++++++++++++ apps/web/src/app/error.tsx | 8 ++++++- apps/web/src/hooks/useGetMe.ts | 7 ++++++ apps/web/src/utils/captureError.ts | 16 +++++++++++++ 12 files changed, 195 insertions(+), 27 deletions(-) create mode 100644 apps/app/utils/captureError.ts create mode 100644 apps/web/src/utils/captureError.ts diff --git a/apps/app/apis/postSocialLogin.ts b/apps/app/apis/postSocialLogin.ts index 5a8e73bf..6b436137 100644 --- a/apps/app/apis/postSocialLogin.ts +++ b/apps/app/apis/postSocialLogin.ts @@ -1,5 +1,7 @@ import type { SocialLoginSuccessPayloadT, SocialProviderT } from '@piki/core'; +import { captureError } from '@/utils/captureError'; + type PostSocialLoginRequestT = { accessToken: string; }; @@ -8,17 +10,33 @@ export const postSocialLogin = async ( provider: SocialProviderT, body: PostSocialLoginRequestT ): Promise => { - const response = await fetch(`${process.env.EXPO_PUBLIC_API_URL}/api/v1/auth/login/${provider}`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-Client-Type': 'app', - }, - body: JSON.stringify(body), - }); + let response: Response; + try { + response = await fetch(`${process.env.EXPO_PUBLIC_API_URL}/api/v1/auth/login/${provider}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-Client-Type': 'app', + }, + body: JSON.stringify(body), + }); + } catch (error) { + /** 네트워크 오류 */ + captureError(error, { tags: { source: 'api', api: 'postSocialLogin', provider } }); + throw error; + } const data = await response.json(); - if (!response.ok) throw new Error(data.detail ?? '로그인에 실패했습니다.'); + if (!response.ok) { + /** 5xx 서버 오류만 수집 (4xx는 예상된 흐름이라 제외) */ + if (response.status >= 500) { + captureError(new Error(`postSocialLogin ${response.status}: ${data.detail ?? 'unknown'}`), { + tags: { source: 'api', api: 'postSocialLogin', provider }, + extra: { status: response.status }, + }); + } + throw new Error(data.detail ?? '로그인에 실패했습니다.'); + } return data.data; }; diff --git a/apps/app/app/_layout.tsx b/apps/app/app/_layout.tsx index c409c878..98465eb3 100644 --- a/apps/app/app/_layout.tsx +++ b/apps/app/app/_layout.tsx @@ -10,18 +10,7 @@ import 'react-native-reanimated'; import PushNotificationProvider from '@/components/PushNotificationProvider'; import { SplashScreenControllerProvider } from '@/hooks/useSplashScreenController'; -/** 배포 환경(production/staging/dev). Sentry 는 production/staging 에서만 수집 (dev·로컬 비활성) */ -const stage = process.env.EXPO_PUBLIC_STAGE; - -Sentry.init({ - dsn: process.env.EXPO_PUBLIC_SENTRY_DSN, - environment: stage, - enabled: stage === 'production' || stage === 'staging', - /** Performance(Tracing)는 초기엔 off */ - tracesSampleRate: 0, - /** PII 기본 마스킹 (Session Replay 는 web 만, 앱은 에러/크래시만) */ - sendDefaultPii: false, -}); +/** Sentry 초기화는 진입점 index.js(initSentry)에서 수행 — 여기선 wrap 만 적용 */ initializeKakaoSDK(process.env.EXPO_PUBLIC_KAKAO_NATIVE_APP_KEY ?? ''); diff --git a/apps/app/app/index.tsx b/apps/app/app/index.tsx index 708b62fb..94bb33d7 100644 --- a/apps/app/app/index.tsx +++ b/apps/app/app/index.tsx @@ -8,6 +8,10 @@ import { useCallback, useEffect, useRef, useState } from 'react'; import { AppState, Linking, Platform } from 'react-native'; import type { WebView } from 'react-native-webview'; import Webview from 'react-native-webview'; +import type { + WebViewErrorEvent, + WebViewHttpErrorEvent, +} from 'react-native-webview/lib/WebViewTypes'; import { USER_AGENT } from '@/constants/userAgent'; import { useShareIntent } from '@/hooks/useShareIntent'; @@ -17,6 +21,7 @@ import { useWebBridgeMessage } from '@/hooks/useWebBridgeMessage'; import { useWebDeepLink } from '@/hooks/useWebDeepLink'; import { useWebviewCookieSync } from '@/hooks/useWebviewCookieSync'; import { logAnalyticsEvent, logAppOpenEvent } from '@/utils/analytics'; +import { captureError } from '@/utils/captureError'; import { handleOpenImagePicker } from '@/utils/handleImage'; import { handleRequestPushPermission, @@ -130,6 +135,30 @@ function Page() { const { onMessage } = useWebBridgeMessage(handleWebMessage); const { onWebViewLoadEnd, onWebViewLoadError } = useSplashScreenController(); + /** WebView 로드 실패(네이티브 측) 수집 + 기존 스플래시 처리 유지 */ + const handleWebViewError = useCallback( + (event: WebViewErrorEvent) => { + const { nativeEvent } = event; + captureError(new Error(`WebView load error: ${nativeEvent.description}`), { + tags: { source: 'webview' }, + extra: { url: nativeEvent.url, code: nativeEvent.code }, + }); + onWebViewLoadError(); + }, + [onWebViewLoadError] + ); + + /** WebView HTTP 5xx 응답만 수집 */ + const handleWebViewHttpError = useCallback((event: WebViewHttpErrorEvent) => { + const { nativeEvent } = event; + if (nativeEvent.statusCode >= 500) { + captureError(new Error(`WebView HTTP ${nativeEvent.statusCode}: ${nativeEvent.url}`), { + tags: { source: 'webview' }, + extra: { url: nativeEvent.url, statusCode: nativeEvent.statusCode }, + }); + } + }, []); + return ( <> {isSynced && ( @@ -140,7 +169,8 @@ function Page() { source={{ uri: webviewUri }} onMessage={onMessage} onLoadEnd={onWebViewLoadEnd} - onError={onWebViewLoadError} + onError={handleWebViewError} + onHttpError={handleWebViewHttpError} allowsBackForwardNavigationGestures cacheEnabled webviewDebuggingEnabled={__DEV__} diff --git a/apps/app/index.js b/apps/app/index.js index e6d68e89..2ad9ffe6 100644 --- a/apps/app/index.js +++ b/apps/app/index.js @@ -1,13 +1,32 @@ import { getMessaging, setBackgroundMessageHandler } from '@react-native-firebase/messaging'; +import * as Sentry from '@sentry/react-native'; import 'expo-router/entry'; +import { captureError } from '@/utils/captureError'; import { setAppBadgeCount } from '@/utils/pushNotification'; +/** foreground 메인 + background headless 둘 다 여기서 초기화 (쉐어 익스텐션 제외) */ +const stage = process.env.EXPO_PUBLIC_STAGE; + +Sentry.init({ + dsn: process.env.EXPO_PUBLIC_SENTRY_DSN, + environment: stage, + enabled: stage === 'production' || stage === 'staging', + /** Performance(Tracing)는 초기엔 off */ + tracesSampleRate: 0, + /** PII 기본 마스킹 (Session Replay 는 web 만, 앱은 에러/크래시만) */ + sendDefaultPii: false, +}); + /** 백그라운드 FCM 메시지 핸들러 */ setBackgroundMessageHandler(getMessaging(), async remoteMessage => { - console.warn('[FCM] Background message:', remoteMessage.messageId ?? 'unknown'); - const unreadCount = remoteMessage.data?.unreadCount; - if (unreadCount !== undefined) { - await setAppBadgeCount(Number(unreadCount)); + try { + console.warn('[FCM] Background message:', remoteMessage.messageId ?? 'unknown'); + const unreadCount = remoteMessage.data?.unreadCount; + if (unreadCount !== undefined) { + await setAppBadgeCount(Number(unreadCount)); + } + } catch (error) { + captureError(error, { tags: { source: 'fcm-background' } }); } }); diff --git a/apps/app/types/env.d.ts b/apps/app/types/env.d.ts index 068efab9..b0e8c49e 100644 --- a/apps/app/types/env.d.ts +++ b/apps/app/types/env.d.ts @@ -5,5 +5,8 @@ declare namespace NodeJS { EXPO_PUBLIC_KAKAO_NATIVE_APP_KEY: string; EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID: string; EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID: string; + /** 배포 환경: production | staging | dev */ + EXPO_PUBLIC_STAGE: string; + EXPO_PUBLIC_SENTRY_DSN: string; } } diff --git a/apps/app/utils/captureError.ts b/apps/app/utils/captureError.ts new file mode 100644 index 00000000..813ceee6 --- /dev/null +++ b/apps/app/utils/captureError.ts @@ -0,0 +1,16 @@ +import * as Sentry from '@sentry/react-native'; + +type CaptureErrorContextT = { + /** 검색/그룹핑용 태그 (예: { source: 'webview' }) */ + tags?: Record; + /** 디버깅용 부가 정보 (요청 URL, status 등) */ + extra?: Record; +}; + +/** 잡은(caught) 에러를 Sentry에 수동 리포트 — 태그/컨텍스트를 일관되게 부착 */ +export const captureError = (error: unknown, context?: CaptureErrorContextT) => { + Sentry.captureException(error, { + tags: context?.tags, + extra: context?.extra, + }); +}; diff --git a/apps/web/instrumentation-client.ts b/apps/web/instrumentation-client.ts index f02ffed7..34d11792 100644 --- a/apps/web/instrumentation-client.ts +++ b/apps/web/instrumentation-client.ts @@ -22,6 +22,17 @@ Sentry.init({ ], /** PII 기본 마스킹 */ sendDefaultPii: false, + /** 브라우저 확장·네트워크 취소 등 우리 코드와 무관한 노이즈 제외 */ + ignoreErrors: [ + 'Network Error', + 'Failed to fetch', + 'Load failed', + 'AbortError', + 'The operation was aborted', + 'ResizeObserver loop limit exceeded', + 'ResizeObserver loop completed with undelivered notifications', + 'Non-Error promise rejection captured', + ], }); export const onRouterTransitionStart = Sentry.captureRouterTransitionStart; diff --git a/apps/web/src/apis/client.ts b/apps/web/src/apis/client.ts index e6f91300..d4d8987d 100644 --- a/apps/web/src/apis/client.ts +++ b/apps/web/src/apis/client.ts @@ -1,3 +1,4 @@ +import * as Sentry from '@sentry/nextjs'; import type { AxiosError } from 'axios'; import axios from 'axios'; @@ -5,6 +6,7 @@ import { QUERY_ACTION } from '@/consts/queryAction'; import { ROUTES } from '@/consts/route'; import { CLIENT_TYPE } from '@/consts/webBridge'; import type { ApiErrorResponseT } from '@/types/api'; +import { captureError } from '@/utils/captureError'; import { getCookie } from '@/utils/cookie'; import { getLoginPath } from '@/utils/loginRedirect'; import { refreshClientToken } from '@/utils/refreshClientToken'; @@ -39,6 +41,9 @@ clientApi.interceptors.response.use( await refreshClientToken(); return clientApi(originalRequest); } catch (refreshError) { + /** 세션 만료 — Sentry 유저 컨텍스트 해제 */ + Sentry.setUser(null); + if (typeof window !== 'undefined') { const loginRedirectDisabled = window.location.pathname === ROUTES.LOGIN || @@ -56,6 +61,25 @@ clientApi.interceptors.response.use( } } + /** 5xx·네트워크 오류만 수집 (4xx는 예상된 흐름이라 제외) */ + const status = error.response?.status; + const shouldReport = + error.code !== 'ERR_CANCELED' && + (error.code === 'ERR_NETWORK' || (typeof status === 'number' && status >= 500)); + + if (shouldReport) { + captureError(error, { + tags: { source: 'api-client' }, + extra: { + url: originalRequest?.url, + method: originalRequest?.method, + status, + code: error.code, + detail: error.response?.data?.detail, + }, + }); + } + return Promise.reject(error); } ); diff --git a/apps/web/src/apis/server.ts b/apps/web/src/apis/server.ts index f0b93b55..029c90ff 100644 --- a/apps/web/src/apis/server.ts +++ b/apps/web/src/apis/server.ts @@ -1,6 +1,9 @@ +import type { AxiosError } from 'axios'; import axios from 'axios'; import { CLIENT_TYPE } from '@/consts/webBridge'; +import type { ApiErrorResponseT } from '@/types/api'; +import { captureError } from '@/utils/captureError'; import { isWebview } from '@/utils/webBridge'; // 서버 컴포넌트 전용 인스턴스 @@ -22,3 +25,29 @@ serverApi.interceptors.request.use(async config => { return config; }); + +serverApi.interceptors.response.use( + response => response, + (error: AxiosError) => { + /** 5xx·네트워크 오류만 수집 (4xx는 예상된 흐름이라 제외) */ + const status = error.response?.status; + const shouldReport = + error.code !== 'ERR_CANCELED' && + (error.code === 'ERR_NETWORK' || (typeof status === 'number' && status >= 500)); + + if (shouldReport) { + captureError(error, { + tags: { source: 'api-server' }, + extra: { + url: error.config?.url, + method: error.config?.method, + status, + code: error.code, + detail: error.response?.data?.detail, + }, + }); + } + + return Promise.reject(error); + } +); diff --git a/apps/web/src/app/error.tsx b/apps/web/src/app/error.tsx index 4266ac0e..4ca4dfda 100644 --- a/apps/web/src/app/error.tsx +++ b/apps/web/src/app/error.tsx @@ -1,6 +1,8 @@ 'use client'; +import * as Sentry from '@sentry/nextjs'; import Link from 'next/link'; +import { useEffect } from 'react'; import { WarningIconFill } from '@/assets/icons'; import { ROUTES } from '@/consts/route'; @@ -10,7 +12,11 @@ type Props = { reset: () => void; }; -function Error({ reset }: Props) { +function Error({ error, reset }: Props) { + useEffect(() => { + Sentry.captureException(error); + }, [error]); + return (
diff --git a/apps/web/src/hooks/useGetMe.ts b/apps/web/src/hooks/useGetMe.ts index 2c20c05e..f885362e 100644 --- a/apps/web/src/hooks/useGetMe.ts +++ b/apps/web/src/hooks/useGetMe.ts @@ -1,4 +1,6 @@ +import * as Sentry from '@sentry/nextjs'; import { useSuspenseQuery } from '@tanstack/react-query'; +import { useEffect } from 'react'; import { getMe } from '@/apis/getMe'; @@ -8,5 +10,10 @@ export const useGetMe = () => { queryFn: getMe, }); + /** 에러가 어떤 유저에게 발생했는지 식별 (PII 정책상 id만, 이메일/닉네임 제외) */ + useEffect(() => { + if (userData?.id) Sentry.setUser({ id: userData.id }); + }, [userData?.id]); + return { userData }; }; diff --git a/apps/web/src/utils/captureError.ts b/apps/web/src/utils/captureError.ts new file mode 100644 index 00000000..3f9799cd --- /dev/null +++ b/apps/web/src/utils/captureError.ts @@ -0,0 +1,16 @@ +import * as Sentry from '@sentry/nextjs'; + +type CaptureErrorContextT = { + /** 검색/그룹핑용 태그 (예: { source: 'api-client' }) */ + tags?: Record; + /** 디버깅용 부가 정보 (요청 URL, status 등) */ + extra?: Record; +}; + +/** 잡은(caught) 에러를 Sentry에 수동 리포트 — 태그/컨텍스트를 일관되게 부착 */ +export const captureError = (error: unknown, context?: CaptureErrorContextT) => { + Sentry.captureException(error, { + tags: context?.tags, + extra: context?.extra, + }); +}; From 87f9e5315ef3775bc069fe46a1aecb55c806a1a8 Mon Sep 17 00:00:00 2001 From: Jung Sun A Date: Thu, 2 Jul 2026 10:50:49 +0900 Subject: [PATCH 04/12] =?UTF-8?q?test:=20=EC=97=90=EB=9F=AC=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=EC=9A=A9=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/app/api/sentry-test-error/route.ts | 14 ++++++ apps/web/src/app/sentry-test/page.tsx | 47 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 apps/web/src/app/api/sentry-test-error/route.ts create mode 100644 apps/web/src/app/sentry-test/page.tsx diff --git a/apps/web/src/app/api/sentry-test-error/route.ts b/apps/web/src/app/api/sentry-test-error/route.ts new file mode 100644 index 00000000..e8c073cd --- /dev/null +++ b/apps/web/src/app/api/sentry-test-error/route.ts @@ -0,0 +1,14 @@ +import { NextResponse } from 'next/server'; + +/** ⚠️ 임시 Sentry 검증용 의도적 500 — 수집 확인 후 삭제 */ +export function GET() { + return NextResponse.json( + { + status: 500, + data: null, + detail: 'Sentry 테스트용 의도적 서버 오류', + code: 'SENTRY_TEST_ERROR', + }, + { status: 500 } + ); +} diff --git a/apps/web/src/app/sentry-test/page.tsx b/apps/web/src/app/sentry-test/page.tsx new file mode 100644 index 00000000..083370c3 --- /dev/null +++ b/apps/web/src/app/sentry-test/page.tsx @@ -0,0 +1,47 @@ +'use client'; + +import { clientApi } from '@/apis/client'; +import { captureError } from '@/utils/captureError'; + +/** ⚠️ 임시 Sentry 검증 페이지 — 수집 확인 후 삭제 (route: /sentry-test) */ +function SentryTestPage() { + /** 1. 클라이언트 uncaught 에러 — 자동 수집 + Session Replay 트리거 확인 */ + const handleThrow = () => { + throw new Error('Sentry test: 클라이언트 uncaught 에러'); + }; + + /** 2. 잡은 에러 수동 캡처 — captureError 유틸/태그 확인 */ + const handleCapture = () => { + captureError(new Error('Sentry test: handled 에러'), { tags: { source: 'sentry-test' } }); + alert('handled 에러 전송됨'); + }; + + /** 3. 5xx API — axios 인터셉터 중앙 수집 확인 */ + const handleApiError = async () => { + try { + await clientApi.get('/api/sentry-test-error'); + } catch { + alert('5xx API 에러 전송됨'); + } + }; + + const buttonClass = + 'w-full max-w-80 cursor-pointer rounded-2xl bg-gray-900 px-5 py-3 text-center font-medium text-white'; + + return ( +
+

Sentry 테스트

+ + + +
+ ); +} + +export default SentryTestPage; From e1e7f9eea15e233d382598a46d408ef3626bd899 Mon Sep 17 00:00:00 2001 From: Jung Sun A Date: Thu, 2 Jul 2026 11:38:29 +0900 Subject: [PATCH 05/12] =?UTF-8?q?fix:=20SENTRY=5FAUTH=5FTOKEN=20turbo=20pa?= =?UTF-8?q?ssThroughEnv=20=EC=B6=94=EA=B0=80=20(=EC=86=8C=EC=8A=A4?= =?UTF-8?q?=EB=A7=B5=20=EC=97=85=EB=A1=9C=EB=93=9C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- turbo.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/turbo.json b/turbo.json index 0a37f57c..4ceaf2bd 100644 --- a/turbo.json +++ b/turbo.json @@ -15,9 +15,9 @@ "CI", "NEXT_RUNTIME", "NEXT_PUBLIC_STAGE", - "NEXT_PUBLIC_SENTRY_DSN", - "SENTRY_AUTH_TOKEN" + "NEXT_PUBLIC_SENTRY_DSN" ], + "passThroughEnv": ["SENTRY_AUTH_TOKEN"], "outputs": [".next/**", "!.next/cache/**"] }, "lint": { From a91eb19a023594d91edf3c433746ecd726f4ac2c Mon Sep 17 00:00:00 2001 From: Jung Sun A Date: Thu, 2 Jul 2026 11:44:22 +0900 Subject: [PATCH 06/12] =?UTF-8?q?feat:=20Session=20Replay=20=EB=A7=88?= =?UTF-8?q?=EC=8A=A4=ED=82=B9=20=EC=99=84=ED=99=94=20(=EC=9D=B4=EB=A9=94?= =?UTF-8?q?=EC=9D=BC=EB=A7=8C=20=EB=A7=88=EC=8A=A4=ED=82=B9,=20=EB=82=98?= =?UTF-8?q?=EB=A8=B8=EC=A7=80=20=EB=85=B8=EC=B6=9C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/instrumentation-client.ts | 7 +++++-- apps/web/src/app/mypage/_components/ProfileSection.tsx | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/web/instrumentation-client.ts b/apps/web/instrumentation-client.ts index 34d11792..a5cc8030 100644 --- a/apps/web/instrumentation-client.ts +++ b/apps/web/instrumentation-client.ts @@ -16,8 +16,11 @@ Sentry.init({ replaysOnErrorSampleRate: 1.0, integrations: [ Sentry.replayIntegration({ - maskAllText: true, - blockAllMedia: true, + /** 소셜 로그인만이라 민감 입력 없음 — [data-sentry-mask](이메일)만 마스킹하고 나머진 노출 */ + maskAllText: false, + blockAllMedia: false, + maskAllInputs: false, + mask: ['[data-sentry-mask]'], }), ], /** PII 기본 마스킹 */ diff --git a/apps/web/src/app/mypage/_components/ProfileSection.tsx b/apps/web/src/app/mypage/_components/ProfileSection.tsx index 576bdfff..cbec9a47 100644 --- a/apps/web/src/app/mypage/_components/ProfileSection.tsx +++ b/apps/web/src/app/mypage/_components/ProfileSection.tsx @@ -32,7 +32,9 @@ function ProfileSection() {

{userData.nickname}

{userData.identityType === 'MEMBER' && ( -

{userData.email}

+

+ {userData.email} +

)}
From c25ab1d0293985ea4c7145984f66fa22e792f6e1 Mon Sep 17 00:00:00 2001 From: Jung Sun A Date: Thu, 2 Jul 2026 11:51:59 +0900 Subject: [PATCH 07/12] =?UTF-8?q?feat:=20API=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EB=A6=AC=ED=8F=AC=ED=8A=B8=20=EC=A0=9C=EB=AA=A9=EC=9D=84=20'AP?= =?UTF-8?q?I=20{status}=20{method}=20{path}'=20=ED=98=95=EC=8B=9D=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/src/apis/client.ts | 9 ++++++++- apps/web/src/apis/server.ts | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/web/src/apis/client.ts b/apps/web/src/apis/client.ts index d4d8987d..9f814190 100644 --- a/apps/web/src/apis/client.ts +++ b/apps/web/src/apis/client.ts @@ -68,7 +68,14 @@ clientApi.interceptors.response.use( (error.code === 'ERR_NETWORK' || (typeof status === 'number' && status >= 500)); if (shouldReport) { - captureError(error, { + const method = originalRequest?.method?.toUpperCase() ?? 'UNKNOWN'; + const path = originalRequest?.url?.split('?')[0] ?? 'unknown'; + + /** 디코/대시보드 제목을 알아보기 쉽게 (원본 axios 정보는 extra 유지) */ + const apiError = new Error(`API ${status ?? error.code} ${method} ${path}`); + apiError.name = 'ApiError'; + + captureError(apiError, { tags: { source: 'api-client' }, extra: { url: originalRequest?.url, diff --git a/apps/web/src/apis/server.ts b/apps/web/src/apis/server.ts index 029c90ff..59052209 100644 --- a/apps/web/src/apis/server.ts +++ b/apps/web/src/apis/server.ts @@ -36,7 +36,14 @@ serverApi.interceptors.response.use( (error.code === 'ERR_NETWORK' || (typeof status === 'number' && status >= 500)); if (shouldReport) { - captureError(error, { + const method = error.config?.method?.toUpperCase() ?? 'UNKNOWN'; + const path = error.config?.url?.split('?')[0] ?? 'unknown'; + + /** 디코/대시보드 제목을 알아보기 쉽게 (원본 axios 정보는 extra 유지) */ + const apiError = new Error(`API ${status ?? error.code} ${method} ${path}`); + apiError.name = 'ApiError'; + + captureError(apiError, { tags: { source: 'api-server' }, extra: { url: error.config?.url, From 735fa79dd52a613ccf7dae6837e53ef5fa141362 Mon Sep 17 00:00:00 2001 From: Jung Sun A Date: Thu, 2 Jul 2026 14:22:19 +0900 Subject: [PATCH 08/12] =?UTF-8?q?Revert=20"test:=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=EC=9A=A9=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=83=9D=EC=84=B1"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 87f9e5315ef3775bc069fe46a1aecb55c806a1a8. --- .../src/app/api/sentry-test-error/route.ts | 14 ------ apps/web/src/app/sentry-test/page.tsx | 47 ------------------- 2 files changed, 61 deletions(-) delete mode 100644 apps/web/src/app/api/sentry-test-error/route.ts delete mode 100644 apps/web/src/app/sentry-test/page.tsx diff --git a/apps/web/src/app/api/sentry-test-error/route.ts b/apps/web/src/app/api/sentry-test-error/route.ts deleted file mode 100644 index e8c073cd..00000000 --- a/apps/web/src/app/api/sentry-test-error/route.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { NextResponse } from 'next/server'; - -/** ⚠️ 임시 Sentry 검증용 의도적 500 — 수집 확인 후 삭제 */ -export function GET() { - return NextResponse.json( - { - status: 500, - data: null, - detail: 'Sentry 테스트용 의도적 서버 오류', - code: 'SENTRY_TEST_ERROR', - }, - { status: 500 } - ); -} diff --git a/apps/web/src/app/sentry-test/page.tsx b/apps/web/src/app/sentry-test/page.tsx deleted file mode 100644 index 083370c3..00000000 --- a/apps/web/src/app/sentry-test/page.tsx +++ /dev/null @@ -1,47 +0,0 @@ -'use client'; - -import { clientApi } from '@/apis/client'; -import { captureError } from '@/utils/captureError'; - -/** ⚠️ 임시 Sentry 검증 페이지 — 수집 확인 후 삭제 (route: /sentry-test) */ -function SentryTestPage() { - /** 1. 클라이언트 uncaught 에러 — 자동 수집 + Session Replay 트리거 확인 */ - const handleThrow = () => { - throw new Error('Sentry test: 클라이언트 uncaught 에러'); - }; - - /** 2. 잡은 에러 수동 캡처 — captureError 유틸/태그 확인 */ - const handleCapture = () => { - captureError(new Error('Sentry test: handled 에러'), { tags: { source: 'sentry-test' } }); - alert('handled 에러 전송됨'); - }; - - /** 3. 5xx API — axios 인터셉터 중앙 수집 확인 */ - const handleApiError = async () => { - try { - await clientApi.get('/api/sentry-test-error'); - } catch { - alert('5xx API 에러 전송됨'); - } - }; - - const buttonClass = - 'w-full max-w-80 cursor-pointer rounded-2xl bg-gray-900 px-5 py-3 text-center font-medium text-white'; - - return ( -
-

Sentry 테스트

- - - -
- ); -} - -export default SentryTestPage; From 4486a94fd8dba6bbc7ae92ba92b737c836e62f50 Mon Sep 17 00:00:00 2001 From: Jung Sun A Date: Mon, 6 Jul 2026 08:26:45 +0900 Subject: [PATCH 09/12] =?UTF-8?q?fix:=20=EC=86=8C=EC=85=9C=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=205xx=20=EC=9D=91=EB=8B=B5=20JSON=20?= =?UTF-8?q?=ED=8C=8C=EC=8B=B1=20=EC=8B=A4=ED=8C=A8=20=EC=8B=9C=20Sentry=20?= =?UTF-8?q?=EC=88=98=EC=A7=91=20=EB=88=84=EB=9D=BD=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/app/apis/postSocialLogin.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/app/apis/postSocialLogin.ts b/apps/app/apis/postSocialLogin.ts index 6b436137..57377da3 100644 --- a/apps/app/apis/postSocialLogin.ts +++ b/apps/app/apis/postSocialLogin.ts @@ -26,17 +26,25 @@ export const postSocialLogin = async ( throw error; } - const data = await response.json(); + let data: { data: SocialLoginSuccessPayloadT; detail?: string } | null = null; + try { + data = await response.json(); + } catch { + /** 바디가 JSON이 아님 (프록시 HTML 에러 페이지·빈 바디 등) — data는 null 유지 */ + } + if (!response.ok) { /** 5xx 서버 오류만 수집 (4xx는 예상된 흐름이라 제외) */ if (response.status >= 500) { - captureError(new Error(`postSocialLogin ${response.status}: ${data.detail ?? 'unknown'}`), { + captureError(new Error(`postSocialLogin ${response.status}: ${data?.detail ?? 'unknown'}`), { tags: { source: 'api', api: 'postSocialLogin', provider }, extra: { status: response.status }, }); } - throw new Error(data.detail ?? '로그인에 실패했습니다.'); + throw new Error(data?.detail ?? '로그인에 실패했습니다.'); } + if (!data) throw new Error('서버 응답을 해석할 수 없습니다.'); + return data.data; }; From ca122f0de412ee508cf601cd80e6a89185c98b22 Mon Sep 17 00:00:00 2001 From: Jung Sun A Date: Mon, 6 Jul 2026 08:26:48 +0900 Subject: [PATCH 10/12] =?UTF-8?q?fix:=20=EB=A1=9C=EA=B7=B8=EC=95=84?= =?UTF-8?q?=EC=9B=83=20=EC=8B=9C=20Sentry=20=EC=9C=A0=EC=A0=80=20=EC=BB=A8?= =?UTF-8?q?=ED=85=8D=EC=8A=A4=ED=8A=B8=20=ED=95=B4=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/src/app/mypage/_hooks/usePostLogout.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/web/src/app/mypage/_hooks/usePostLogout.ts b/apps/web/src/app/mypage/_hooks/usePostLogout.ts index 2bb8a24e..1ca6c86b 100644 --- a/apps/web/src/app/mypage/_hooks/usePostLogout.ts +++ b/apps/web/src/app/mypage/_hooks/usePostLogout.ts @@ -1,4 +1,5 @@ import { WEBBRIDGE_MESSAGE_TYPE } from '@piki/core'; +import * as Sentry from '@sentry/nextjs'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useRouter } from 'next/navigation'; @@ -22,6 +23,9 @@ export const usePostLogout = () => { WebBridge.postMessage({ type: WEBBRIDGE_MESSAGE_TYPE.WEB_REQ_LOGOUT }); } + /** 다음 유저 세션에 이전 id가 남지 않도록 Sentry 유저 컨텍스트 해제 */ + Sentry.setUser(null); + queryClient.clear(); router.replace(ROUTES.LOGIN); }, From 7972711e855635364a7ec60e374f6a4a20087f78 Mon Sep 17 00:00:00 2001 From: Jung Sun A Date: Mon, 6 Jul 2026 08:30:59 +0900 Subject: [PATCH 11/12] =?UTF-8?q?fix:=20Session=20Replay=20=ED=83=80?= =?UTF-8?q?=EC=9D=B4=ED=95=91=20=EC=9E=85=EB=A0=A5=EC=B0=BD=EB=A7=8C=20?= =?UTF-8?q?=EB=A7=88=EC=8A=A4=ED=82=B9=20(maskAllInputs)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/instrumentation-client.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/instrumentation-client.ts b/apps/web/instrumentation-client.ts index a5cc8030..c8536ac7 100644 --- a/apps/web/instrumentation-client.ts +++ b/apps/web/instrumentation-client.ts @@ -16,10 +16,10 @@ Sentry.init({ replaysOnErrorSampleRate: 1.0, integrations: [ Sentry.replayIntegration({ - /** 소셜 로그인만이라 민감 입력 없음 — [data-sentry-mask](이메일)만 마스킹하고 나머진 노출 */ + /** 렌더된 콘텐츠·이미지는 노출(디버깅용), 유저가 타이핑하는 입력창만 마스킹 */ maskAllText: false, blockAllMedia: false, - maskAllInputs: false, + maskAllInputs: true, mask: ['[data-sentry-mask]'], }), ], From 7ac61613de46f20bea7fbd087a05358a3eda8de1 Mon Sep 17 00:00:00 2001 From: Jung Sun A Date: Mon, 6 Jul 2026 11:12:32 +0900 Subject: [PATCH 12/12] =?UTF-8?q?fix:=20=EC=86=8C=EC=85=9C=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=202xx=20=EC=9D=91=EB=8B=B5=20=EB=B3=B8?= =?UTF-8?q?=EB=AC=B8=20=ED=8C=8C=EC=8B=B1=20=EC=8B=A4=ED=8C=A8=EB=8F=84=20?= =?UTF-8?q?Sentry=20=EC=88=98=EC=A7=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/app/apis/postSocialLogin.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/app/apis/postSocialLogin.ts b/apps/app/apis/postSocialLogin.ts index 57377da3..ed60995f 100644 --- a/apps/app/apis/postSocialLogin.ts +++ b/apps/app/apis/postSocialLogin.ts @@ -44,7 +44,14 @@ export const postSocialLogin = async ( throw new Error(data?.detail ?? '로그인에 실패했습니다.'); } - if (!data) throw new Error('서버 응답을 해석할 수 없습니다.'); + if (!data) { + /** 2xx인데 본문이 비었거나 깨짐 — 예상 못 한 이상 응답이라 수집 */ + captureError(new Error(`postSocialLogin ${response.status}: empty/invalid body`), { + tags: { source: 'api', api: 'postSocialLogin', provider }, + extra: { status: response.status }, + }); + throw new Error('서버 응답을 해석할 수 없습니다.'); + } return data.data; };