From a30a1e9a02fa6152cd020617f6ddf607ce612e1b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=EC=9D=B4=EC=A4=80=EC=98=81?=
<54898597+ff1451@users.noreply.github.com>
Date: Fri, 27 Feb 2026 01:35:11 +0900
Subject: [PATCH] =?UTF-8?q?[feat]=20sentry=20=EB=AA=A8=EB=8B=88=ED=84=B0?=
=?UTF-8?q?=EB=A7=81=20=EC=B6=94=EA=B0=80=20(#141)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* chore: sentry 의존성 추가
* feat: sentry 세팅
* chore: 워크플로우 수정 및 vite 세팅
* chore: 임시 추가
---
.github/workflows/deploy.yml | 57 ++++-
.gitignore | 1 +
package.json | 2 +
pnpm-lock.yaml | 391 ++++++++++++++++++++++++++++++++++-
src/App.tsx | 7 +-
src/config/sentry.ts | 54 +++++
src/global.d.ts | 16 ++
src/main.tsx | 45 +++-
vite.config.ts | 25 +++
9 files changed, 576 insertions(+), 22 deletions(-)
create mode 100644 src/config/sentry.ts
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 2fe7c9d..673810c 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -30,17 +30,70 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile
+ - name: Validate runtime secrets
+ run: |
+ missing=0
+
+ if [ "${{ github.ref_name }}" = "main" ]; then
+ [ -n "${{ secrets.VITE_API_PATH }}" ] || { echo "::error::Missing secret: VITE_API_PATH"; missing=1; }
+ [ -n "${{ secrets.VITE_SENTRY_DSN }}" ] || { echo "::error::Missing secret: VITE_SENTRY_DSN"; missing=1; }
+ else
+ [ -n "${{ secrets.VITE_API_PATH_STAGE }}" ] || { echo "::error::Missing secret: VITE_API_PATH_STAGE"; missing=1; }
+ [ -n "${{ secrets.VITE_SENTRY_DSN_STAGE }}" ] || { echo "::error::Missing secret: VITE_SENTRY_DSN_STAGE"; missing=1; }
+ fi
+
+ [ "$missing" -eq 0 ] || exit 1
+
+ - name: Validate production sourcemap secrets
+ if: github.ref_name == 'main'
+ run: |
+ missing=0
+ [ -n "${{ secrets.SENTRY_ORG }}" ] || { echo "::error::Missing secret: SENTRY_ORG"; missing=1; }
+ [ -n "${{ secrets.SENTRY_PROJECT }}" ] || { echo "::error::Missing secret: SENTRY_PROJECT"; missing=1; }
+ [ -n "${{ secrets.SENTRY_AUTH_TOKEN }}" ] || { echo "::error::Missing secret: SENTRY_AUTH_TOKEN"; missing=1; }
+ [ "$missing" -eq 0 ] || exit 1
+
+ - name: Resolve Sentry project
+ run: |
+ if [ "${{ github.ref_name }}" = "main" ]; then
+ echo "SENTRY_PROJECT_FOR_BUILD=${{ secrets.SENTRY_PROJECT }}" >> "$GITHUB_ENV"
+ else
+ echo "SENTRY_PROJECT_FOR_BUILD=${{ secrets.SENTRY_PROJECT_STAGE }}" >> "$GITHUB_ENV"
+ fi
+
- name: Create .env file
run: |
if [ "${{ github.ref_name }}" = "main" ]; then
- echo "VITE_API_PATH=${{ secrets.VITE_API_PATH }}" > .env
+ {
+ echo "VITE_API_PATH=${{ secrets.VITE_API_PATH }}"
+ echo "VITE_SENTRY_DSN=${{ secrets.VITE_SENTRY_DSN }}"
+ echo "VITE_SENTRY_ENABLED=true"
+ echo "VITE_SENTRY_ENVIRONMENT=production"
+ echo "VITE_SENTRY_RELEASE=${{ github.sha }}"
+ echo "VITE_SENTRY_TRACES_SAMPLE_RATE=0.1"
+ echo "VITE_SENTRY_REPLAY_SESSION_SAMPLE_RATE=0.0"
+ echo "VITE_SENTRY_REPLAY_ON_ERROR_SAMPLE_RATE=1.0"
+ } > .env
else
- echo "VITE_API_PATH=${{ secrets.VITE_API_PATH_STAGE }}" > .env
+ {
+ echo "VITE_API_PATH=${{ secrets.VITE_API_PATH_STAGE }}"
+ echo "VITE_SENTRY_DSN=${{ secrets.VITE_SENTRY_DSN_STAGE }}"
+ echo "VITE_SENTRY_ENABLED=true"
+ echo "VITE_SENTRY_ENVIRONMENT=staging"
+ echo "VITE_SENTRY_RELEASE=${{ github.sha }}"
+ echo "VITE_SENTRY_TRACES_SAMPLE_RATE=0.1"
+ echo "VITE_SENTRY_REPLAY_SESSION_SAMPLE_RATE=0.0"
+ echo "VITE_SENTRY_REPLAY_ON_ERROR_SAMPLE_RATE=1.0"
+ } > .env
fi
- name: Build project
env:
CI: true
+ SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
+ SENTRY_PROJECT: ${{ env.SENTRY_PROJECT_FOR_BUILD }}
+ SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
+ SENTRY_RELEASE: ${{ github.sha }}
run: pnpm build
- name: Setup SSH key
diff --git a/.gitignore b/.gitignore
index ecfc68a..83ef4ab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,3 +24,4 @@ dist-ssr
*.sw?
.env*
+.env.example
diff --git a/package.json b/package.json
index d3f19d4..9b79736 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
"pwa": "pwa-assets-generator --preset minimal public/logo.svg"
},
"dependencies": {
+ "@sentry/react": "^10.40.0",
"@tailwindcss/vite": "^4.1.17",
"@tanstack/react-query": "^5.90.10",
"clsx": "^2.1.1",
@@ -25,6 +26,7 @@
},
"devDependencies": {
"@eslint/js": "^9.39.1",
+ "@sentry/vite-plugin": "^5.1.1",
"@types/node": "^24.10.1",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c6b8e6b..bffed6d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -8,6 +8,9 @@ importers:
.:
dependencies:
+ '@sentry/react':
+ specifier: ^10.40.0
+ version: 10.40.0(react@19.2.3)
'@tailwindcss/vite':
specifier: ^4.1.17
version: 4.1.17(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1))
@@ -42,6 +45,9 @@ importers:
'@eslint/js':
specifier: ^9.39.1
version: 9.39.1
+ '@sentry/vite-plugin':
+ specifier: ^5.1.1
+ version: 5.1.1(rollup@4.53.3)
'@types/node':
specifier: ^24.10.1
version: 24.10.1
@@ -107,7 +113,7 @@ importers:
version: 1.2.0(@vite-pwa/assets-generator@1.0.2)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1))(workbox-build@7.4.0(@types/babel__core@7.20.5))(workbox-window@7.4.0)
vite-plugin-svgr:
specifier: ^4.5.0
- version: 4.5.0(rollup@2.79.2)(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1))
+ version: 4.5.0(rollup@4.53.3)(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1))
packages:
@@ -872,67 +878,79 @@ packages:
resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@img/sharp-libvips-linux-arm@1.0.5':
resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==}
cpu: [arm]
os: [linux]
+ libc: [glibc]
'@img/sharp-libvips-linux-s390x@1.0.4':
resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@img/sharp-libvips-linux-x64@1.0.4':
resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@img/sharp-libvips-linuxmusl-arm64@1.0.4':
resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@img/sharp-libvips-linuxmusl-x64@1.0.4':
resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@img/sharp-linux-arm64@0.33.5':
resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@img/sharp-linux-arm@0.33.5':
resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm]
os: [linux]
+ libc: [glibc]
'@img/sharp-linux-s390x@0.33.5':
resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@img/sharp-linux-x64@0.33.5':
resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@img/sharp-linuxmusl-arm64@0.33.5':
resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@img/sharp-linuxmusl-x64@0.33.5':
resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@img/sharp-wasm32@0.33.5':
resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==}
@@ -1090,56 +1108,67 @@ packages:
resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==}
cpu: [arm]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.53.3':
resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==}
cpu: [arm]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.53.3':
resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.53.3':
resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-loong64-gnu@4.53.3':
resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==}
cpu: [loong64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-ppc64-gnu@4.53.3':
resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==}
cpu: [ppc64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.53.3':
resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==}
cpu: [riscv64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.53.3':
resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==}
cpu: [riscv64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.53.3':
resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.53.3':
resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.53.3':
resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@rollup/rollup-openharmony-arm64@4.53.3':
resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==}
@@ -1169,6 +1198,106 @@ packages:
'@rtsao/scc@1.1.0':
resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
+ '@sentry-internal/browser-utils@10.40.0':
+ resolution: {integrity: sha512-3CDeVNBXYOIvBVdT0SOdMZx5LzYDLuhGK/z7A14sYZz4Cd2+f4mSeFDaEOoH/g2SaY2CKR5KGkAADy8IyjZ21w==}
+ engines: {node: '>=18'}
+
+ '@sentry-internal/feedback@10.40.0':
+ resolution: {integrity: sha512-V/ixkcdCNMo04KgsCEeNEu966xUUTD6czKT2LOAO5siZACqFjT/Rp9VR1n7QQrVo3sL7P3QNiTHtX0jaeWbwzg==}
+ engines: {node: '>=18'}
+
+ '@sentry-internal/replay-canvas@10.40.0':
+ resolution: {integrity: sha512-wzQwilFHO2baeCt0dTMf0eW+rgK8O+mkisf9sQzPXzG3Krr/iVtFg1T5T1Th3YsCsEdn6yQ3hcBPLEXjMSvccg==}
+ engines: {node: '>=18'}
+
+ '@sentry-internal/replay@10.40.0':
+ resolution: {integrity: sha512-vsH2Ut0KIIQIHNdS3zzEGLJ2C9btbpvJIWAVk7l7oft66JzlUNC89qNaQ5SAypjLQx4Ln2V/ZTqfEoNzXOAsoQ==}
+ engines: {node: '>=18'}
+
+ '@sentry/babel-plugin-component-annotate@5.1.1':
+ resolution: {integrity: sha512-x2wEpBHwsTyTF2rWsLKJlzrRF1TTIGOfX+ngdE+Yd5DBkoS58HwQv824QOviPGQRla4/ypISqAXzjdDPL/zalg==}
+ engines: {node: '>= 18'}
+
+ '@sentry/browser@10.40.0':
+ resolution: {integrity: sha512-nCt3FKUMFad0C6xl5wCK0Jz+qT4Vev4fv6HJRn0YoNRRDQCfsUVxAz7pNyyiPNGM/WCDp9wJpGJsRvbBRd2anw==}
+ engines: {node: '>=18'}
+
+ '@sentry/bundler-plugin-core@5.1.1':
+ resolution: {integrity: sha512-F+itpwR9DyQR7gEkrXd2tigREPTvtF5lC8qu6e4anxXYRTui1+dVR0fXNwjpyAZMhIesLfXRN7WY7ggdj7hi0Q==}
+ engines: {node: '>= 18'}
+
+ '@sentry/cli-darwin@2.58.5':
+ resolution: {integrity: sha512-lYrNzenZFJftfwSya7gwrHGxtE+Kob/e1sr9lmHMFOd4utDlmq0XFDllmdZAMf21fxcPRI1GL28ejZ3bId01fQ==}
+ engines: {node: '>=10'}
+ os: [darwin]
+
+ '@sentry/cli-linux-arm64@2.58.5':
+ resolution: {integrity: sha512-/4gywFeBqRB6tR/iGMRAJ3HRqY6Z7Yp4l8ZCbl0TDLAfHNxu7schEw4tSnm2/Hh9eNMiOVy4z58uzAWlZXAYBQ==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [linux, freebsd, android]
+
+ '@sentry/cli-linux-arm@2.58.5':
+ resolution: {integrity: sha512-KtHweSIomYL4WVDrBrYSYJricKAAzxUgX86kc6OnlikbyOhoK6Fy8Vs6vwd52P6dvWPjgrMpUYjW2M5pYXQDUw==}
+ engines: {node: '>=10'}
+ cpu: [arm]
+ os: [linux, freebsd, android]
+
+ '@sentry/cli-linux-i686@2.58.5':
+ resolution: {integrity: sha512-G7261dkmyxqlMdyvyP06b+RTIVzp1gZNgglj5UksxSouSUqRd/46W/2pQeOMPhloDYo9yLtCN2YFb3Mw4aUsWw==}
+ engines: {node: '>=10'}
+ cpu: [x86, ia32]
+ os: [linux, freebsd, android]
+
+ '@sentry/cli-linux-x64@2.58.5':
+ resolution: {integrity: sha512-rP04494RSmt86xChkQ+ecBNRYSPbyXc4u0IA7R7N1pSLCyO74e5w5Al+LnAq35cMfVbZgz5Sm0iGLjyiUu4I1g==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [linux, freebsd, android]
+
+ '@sentry/cli-win32-arm64@2.58.5':
+ resolution: {integrity: sha512-AOJ2nCXlQL1KBaCzv38m3i2VmSHNurUpm7xVKd6yAHX+ZoVBI8VT0EgvwmtJR2TY2N2hNCC7UrgRmdUsQ152bA==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@sentry/cli-win32-i686@2.58.5':
+ resolution: {integrity: sha512-EsuboLSOnlrN7MMPJ1eFvfMDm+BnzOaSWl8eYhNo8W/BIrmNgpRUdBwnWn9Q2UOjJj5ZopukmsiMYtU/D7ml9g==}
+ engines: {node: '>=10'}
+ cpu: [x86, ia32]
+ os: [win32]
+
+ '@sentry/cli-win32-x64@2.58.5':
+ resolution: {integrity: sha512-IZf+XIMiQwj+5NzqbOQfywlOitmCV424Vtf9c+ep61AaVScUFD1TSrQbOcJJv5xGxhlxNOMNgMeZhdexdzrKZg==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [win32]
+
+ '@sentry/cli@2.58.5':
+ resolution: {integrity: sha512-tavJ7yGUZV+z3Ct2/ZB6mg339i08sAk6HDkgqmSRuQEu2iLS5sl9HIvuXfM6xjv8fwlgFOSy++WNABNAcGHUbg==}
+ engines: {node: '>= 10'}
+ hasBin: true
+
+ '@sentry/core@10.40.0':
+ resolution: {integrity: sha512-/wrcHPp9Avmgl6WBimPjS4gj810a1wU5oX9fF1bzJfeIIbF3jTsAbv0oMbgDp0cSDnkwv2+NvcPnn3+c5J6pBA==}
+ engines: {node: '>=18'}
+
+ '@sentry/react@10.40.0':
+ resolution: {integrity: sha512-3T5W/e3QJMimXRIOx8xMEZbxeIuFiKlXvHLcMTLGygGBYnxQGeb8Oz/8heov+3zF1JoCIxeVQNFW0woySApfyA==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ react: ^16.14.0 || 17.x || 18.x || 19.x
+
+ '@sentry/rollup-plugin@5.1.1':
+ resolution: {integrity: sha512-1d5NkdRR6aKWBP7czkY8sFFWiKnfmfRpQOj+m9bJTsyTjbMiEQJst6315w5pCVlRItPhBqpAraqAhutZFgvyVg==}
+ engines: {node: '>= 18'}
+ peerDependencies:
+ rollup: '>=3.2.0'
+
+ '@sentry/vite-plugin@5.1.1':
+ resolution: {integrity: sha512-i6NWUDi2SDikfSUeMJvJTRdwEKYSfTd+mvBO2Ja51S1YK+hnickBuDfD+RvPerIXLuyRu3GamgNPbNqgCGUg/Q==}
+ engines: {node: '>= 18'}
+
'@surma/rollup-plugin-off-main-thread@2.2.3':
resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==}
@@ -1278,24 +1407,28 @@ packages:
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@tailwindcss/oxide-linux-arm64-musl@4.1.17':
resolution: {integrity: sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@tailwindcss/oxide-linux-x64-gnu@4.1.17':
resolution: {integrity: sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@tailwindcss/oxide-linux-x64-musl@4.1.17':
resolution: {integrity: sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@tailwindcss/oxide-wasm32-wasi@4.1.17':
resolution: {integrity: sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==}
@@ -1480,41 +1613,49 @@ packages:
resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
'@unrs/resolver-binding-linux-arm64-musl@1.11.1':
resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==}
cpu: [arm64]
os: [linux]
+ libc: [musl]
'@unrs/resolver-binding-linux-ppc64-gnu@1.11.1':
resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==}
cpu: [ppc64]
os: [linux]
+ libc: [glibc]
'@unrs/resolver-binding-linux-riscv64-gnu@1.11.1':
resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==}
cpu: [riscv64]
os: [linux]
+ libc: [glibc]
'@unrs/resolver-binding-linux-riscv64-musl@1.11.1':
resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==}
cpu: [riscv64]
os: [linux]
+ libc: [musl]
'@unrs/resolver-binding-linux-s390x-gnu@1.11.1':
resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==}
cpu: [s390x]
os: [linux]
+ libc: [glibc]
'@unrs/resolver-binding-linux-x64-gnu@1.11.1':
resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==}
cpu: [x64]
os: [linux]
+ libc: [glibc]
'@unrs/resolver-binding-linux-x64-musl@1.11.1':
resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==}
cpu: [x64]
os: [linux]
+ libc: [musl]
'@unrs/resolver-binding-wasm32-wasi@1.11.1':
resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==}
@@ -1557,6 +1698,10 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
+ agent-base@6.0.2:
+ resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
+ engines: {node: '>= 6.0.0'}
+
ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
@@ -1650,9 +1795,9 @@ packages:
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
- baseline-browser-mapping@2.9.11:
- resolution: {integrity: sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==}
- hasBin: true
+ balanced-match@4.0.4:
+ resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
+ engines: {node: 18 || 20 || >=22}
baseline-browser-mapping@2.9.19:
resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==}
@@ -1664,6 +1809,10 @@ packages:
brace-expansion@2.0.2:
resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
+ brace-expansion@5.0.3:
+ resolution: {integrity: sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==}
+ engines: {node: 18 || 20 || >=22}
+
braces@3.0.3:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
engines: {node: '>=8'}
@@ -1846,6 +1995,10 @@ packages:
dot-case@3.0.4:
resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==}
+ dotenv@16.6.1:
+ resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==}
+ engines: {node: '>=12'}
+
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
@@ -2184,8 +2337,13 @@ packages:
glob@11.1.0:
resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==}
engines: {node: 20 || >=22}
+ deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
hasBin: true
+ glob@13.0.6:
+ resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==}
+ engines: {node: 18 || 20 || >=22}
+
globals@14.0.0:
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
engines: {node: '>=18'}
@@ -2241,6 +2399,10 @@ packages:
hermes-parser@0.25.1:
resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==}
+ https-proxy-agent@5.0.1:
+ resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
+ engines: {node: '>= 6'}
+
ico-endec@0.1.6:
resolution: {integrity: sha512-ZdLU38ZoED3g1j3iEyzcQj+wAkY2xfWNkymszfJPoxucIUhK7NayQ+/C4Kv0nDFMIsbtbEHldv3V8PU494/ueQ==}
@@ -2514,24 +2676,28 @@ packages:
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
+ libc: [glibc]
lightningcss-linux-arm64-musl@1.30.2:
resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
+ libc: [musl]
lightningcss-linux-x64-gnu@1.30.2:
resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
+ libc: [glibc]
lightningcss-linux-x64-musl@1.30.2:
resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
+ libc: [musl]
lightningcss-win32-arm64-msvc@1.30.2:
resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==}
@@ -2604,6 +2770,10 @@ packages:
resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==}
engines: {node: 20 || >=22}
+ minimatch@10.2.4:
+ resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==}
+ engines: {node: 18 || 20 || >=22}
+
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
@@ -2622,6 +2792,10 @@ packages:
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
engines: {node: '>=16 || 14 >=14.17'}
+ minipass@7.1.3:
+ resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==}
+ engines: {node: '>=16 || 14 >=14.17'}
+
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@@ -2641,6 +2815,15 @@ packages:
no-case@3.0.4:
resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
+ node-fetch@2.7.0:
+ resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
+ engines: {node: 4.x || >=6.0.0}
+ peerDependencies:
+ encoding: ^0.1.0
+ peerDependenciesMeta:
+ encoding:
+ optional: true
+
node-releases@2.0.27:
resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==}
@@ -2718,6 +2901,10 @@ packages:
resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==}
engines: {node: 20 || >=22}
+ path-scurry@2.0.2:
+ resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==}
+ engines: {node: 18 || 20 || >=22}
+
path-type@4.0.0:
resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
engines: {node: '>=8'}
@@ -2817,9 +3004,16 @@ packages:
resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==}
engines: {node: ^14.13.1 || >=16.0.0}
+ progress@2.0.3:
+ resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
+ engines: {node: '>=0.4.0'}
+
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
+ proxy-from-env@1.1.0:
+ resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
+
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
@@ -3149,6 +3343,9 @@ packages:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
+ tr46@0.0.3:
+ resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
+
tr46@1.0.1:
resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==}
@@ -3316,9 +3513,15 @@ packages:
yaml:
optional: true
+ webidl-conversions@3.0.1:
+ resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
+
webidl-conversions@4.0.2:
resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
+ whatwg-url@5.0.0:
+ resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
+
whatwg-url@7.1.0:
resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==}
@@ -4455,6 +4658,14 @@ snapshots:
optionalDependencies:
rollup: 2.79.2
+ '@rollup/pluginutils@5.3.0(rollup@4.53.3)':
+ dependencies:
+ '@types/estree': 1.0.8
+ estree-walker: 2.0.2
+ picomatch: 4.0.3
+ optionalDependencies:
+ rollup: 4.53.3
+
'@rollup/rollup-android-arm-eabi@4.53.3':
optional: true
@@ -4523,6 +4734,117 @@ snapshots:
'@rtsao/scc@1.1.0': {}
+ '@sentry-internal/browser-utils@10.40.0':
+ dependencies:
+ '@sentry/core': 10.40.0
+
+ '@sentry-internal/feedback@10.40.0':
+ dependencies:
+ '@sentry/core': 10.40.0
+
+ '@sentry-internal/replay-canvas@10.40.0':
+ dependencies:
+ '@sentry-internal/replay': 10.40.0
+ '@sentry/core': 10.40.0
+
+ '@sentry-internal/replay@10.40.0':
+ dependencies:
+ '@sentry-internal/browser-utils': 10.40.0
+ '@sentry/core': 10.40.0
+
+ '@sentry/babel-plugin-component-annotate@5.1.1': {}
+
+ '@sentry/browser@10.40.0':
+ dependencies:
+ '@sentry-internal/browser-utils': 10.40.0
+ '@sentry-internal/feedback': 10.40.0
+ '@sentry-internal/replay': 10.40.0
+ '@sentry-internal/replay-canvas': 10.40.0
+ '@sentry/core': 10.40.0
+
+ '@sentry/bundler-plugin-core@5.1.1':
+ dependencies:
+ '@babel/core': 7.28.5
+ '@sentry/babel-plugin-component-annotate': 5.1.1
+ '@sentry/cli': 2.58.5
+ dotenv: 16.6.1
+ find-up: 5.0.0
+ glob: 13.0.6
+ magic-string: 0.30.21
+ transitivePeerDependencies:
+ - encoding
+ - supports-color
+
+ '@sentry/cli-darwin@2.58.5':
+ optional: true
+
+ '@sentry/cli-linux-arm64@2.58.5':
+ optional: true
+
+ '@sentry/cli-linux-arm@2.58.5':
+ optional: true
+
+ '@sentry/cli-linux-i686@2.58.5':
+ optional: true
+
+ '@sentry/cli-linux-x64@2.58.5':
+ optional: true
+
+ '@sentry/cli-win32-arm64@2.58.5':
+ optional: true
+
+ '@sentry/cli-win32-i686@2.58.5':
+ optional: true
+
+ '@sentry/cli-win32-x64@2.58.5':
+ optional: true
+
+ '@sentry/cli@2.58.5':
+ 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.5
+ '@sentry/cli-linux-arm': 2.58.5
+ '@sentry/cli-linux-arm64': 2.58.5
+ '@sentry/cli-linux-i686': 2.58.5
+ '@sentry/cli-linux-x64': 2.58.5
+ '@sentry/cli-win32-arm64': 2.58.5
+ '@sentry/cli-win32-i686': 2.58.5
+ '@sentry/cli-win32-x64': 2.58.5
+ transitivePeerDependencies:
+ - encoding
+ - supports-color
+
+ '@sentry/core@10.40.0': {}
+
+ '@sentry/react@10.40.0(react@19.2.3)':
+ dependencies:
+ '@sentry/browser': 10.40.0
+ '@sentry/core': 10.40.0
+ react: 19.2.3
+
+ '@sentry/rollup-plugin@5.1.1(rollup@4.53.3)':
+ dependencies:
+ '@sentry/bundler-plugin-core': 5.1.1
+ magic-string: 0.30.21
+ rollup: 4.53.3
+ transitivePeerDependencies:
+ - encoding
+ - supports-color
+
+ '@sentry/vite-plugin@5.1.1(rollup@4.53.3)':
+ dependencies:
+ '@sentry/bundler-plugin-core': 5.1.1
+ '@sentry/rollup-plugin': 5.1.1(rollup@4.53.3)
+ transitivePeerDependencies:
+ - encoding
+ - rollup
+ - supports-color
+
'@surma/rollup-plugin-off-main-thread@2.2.3':
dependencies:
ejs: 3.1.10
@@ -4904,6 +5226,12 @@ snapshots:
acorn@8.15.0: {}
+ agent-base@6.0.2:
+ dependencies:
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
ajv@6.12.6:
dependencies:
fast-deep-equal: 3.1.3
@@ -5037,7 +5365,7 @@ snapshots:
balanced-match@1.0.2: {}
- baseline-browser-mapping@2.9.11: {}
+ balanced-match@4.0.4: {}
baseline-browser-mapping@2.9.19: {}
@@ -5050,6 +5378,10 @@ snapshots:
dependencies:
balanced-match: 1.0.2
+ brace-expansion@5.0.3:
+ dependencies:
+ balanced-match: 4.0.4
+
braces@3.0.3:
dependencies:
fill-range: 7.1.1
@@ -5064,7 +5396,7 @@ snapshots:
browserslist@4.28.1:
dependencies:
- baseline-browser-mapping: 2.9.11
+ baseline-browser-mapping: 2.9.19
caniuse-lite: 1.0.30001762
electron-to-chromium: 1.5.267
node-releases: 2.0.27
@@ -5225,6 +5557,8 @@ snapshots:
no-case: 3.0.4
tslib: 2.8.1
+ dotenv@16.6.1: {}
+
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
@@ -5715,6 +6049,12 @@ snapshots:
package-json-from-dist: 1.0.1
path-scurry: 2.0.1
+ glob@13.0.6:
+ dependencies:
+ minimatch: 10.2.4
+ minipass: 7.1.3
+ path-scurry: 2.0.2
+
globals@14.0.0: {}
globals@16.5.0: {}
@@ -5758,6 +6098,13 @@ snapshots:
dependencies:
hermes-estree: 0.25.1
+ https-proxy-agent@5.0.1:
+ dependencies:
+ agent-base: 6.0.2
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
ico-endec@0.1.6: {}
idb@7.1.1: {}
@@ -6080,6 +6427,10 @@ snapshots:
dependencies:
'@isaacs/brace-expansion': 5.0.0
+ minimatch@10.2.4:
+ dependencies:
+ brace-expansion: 5.0.3
+
minimatch@3.1.2:
dependencies:
brace-expansion: 1.1.12
@@ -6096,6 +6447,8 @@ snapshots:
minipass@7.1.2: {}
+ minipass@7.1.3: {}
+
ms@2.1.3: {}
nanoid@3.3.11: {}
@@ -6109,6 +6462,10 @@ snapshots:
lower-case: 2.0.2
tslib: 2.8.1
+ node-fetch@2.7.0:
+ dependencies:
+ whatwg-url: 5.0.0
+
node-releases@2.0.27: {}
object-assign@4.1.1: {}
@@ -6200,6 +6557,11 @@ snapshots:
lru-cache: 11.2.4
minipass: 7.1.2
+ path-scurry@2.0.2:
+ dependencies:
+ lru-cache: 11.2.4
+ minipass: 7.1.3
+
path-type@4.0.0: {}
picocolors@1.1.1: {}
@@ -6232,12 +6594,16 @@ snapshots:
pretty-bytes@6.1.1: {}
+ progress@2.0.3: {}
+
prop-types@15.8.1:
dependencies:
loose-envify: 1.4.0
object-assign: 4.1.1
react-is: 16.13.1
+ proxy-from-env@1.1.0: {}
+
punycode@2.3.1: {}
quansync@0.2.11: {}
@@ -6649,6 +7015,8 @@ snapshots:
dependencies:
is-number: 7.0.0
+ tr46@0.0.3: {}
+
tr46@1.0.1:
dependencies:
punycode: 2.3.1
@@ -6812,9 +7180,9 @@ snapshots:
transitivePeerDependencies:
- supports-color
- vite-plugin-svgr@4.5.0(rollup@2.79.2)(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)):
+ vite-plugin-svgr@4.5.0(rollup@4.53.3)(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)):
dependencies:
- '@rollup/pluginutils': 5.3.0(rollup@2.79.2)
+ '@rollup/pluginutils': 5.3.0(rollup@4.53.3)
'@svgr/core': 8.1.0(typescript@5.9.3)
'@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3))
vite: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)
@@ -6838,8 +7206,15 @@ snapshots:
lightningcss: 1.30.2
terser: 5.44.1
+ webidl-conversions@3.0.1: {}
+
webidl-conversions@4.0.2: {}
+ whatwg-url@5.0.0:
+ dependencies:
+ tr46: 0.0.3
+ webidl-conversions: 3.0.1
+
whatwg-url@7.1.0:
dependencies:
lodash.sortby: 4.7.0
diff --git a/src/App.tsx b/src/App.tsx
index 25fc1fc..3125b1b 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,3 +1,4 @@
+import * as Sentry from '@sentry/react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import AuthGuard from './components/auth/AuthGuard';
import ProtectedRoute from './components/auth/ProtectedRoute';
@@ -41,11 +42,13 @@ import Timer from './pages/Timer';
import MyPage from './pages/User/MyPage';
import Profile from './pages/User/Profile';
+const SentryRoutes = Sentry.withSentryReactRouterV7Routing(Routes);
+
function App() {
return (
-
+
}>
}>
} />
@@ -114,7 +117,7 @@ function App() {
-
+
);
diff --git a/src/config/sentry.ts b/src/config/sentry.ts
new file mode 100644
index 0000000..271f537
--- /dev/null
+++ b/src/config/sentry.ts
@@ -0,0 +1,54 @@
+import { useEffect } from 'react';
+import * as Sentry from '@sentry/react';
+import { createRoutesFromChildren, matchRoutes, useLocation, useNavigationType } from 'react-router-dom';
+
+const clampSampleRate = (value: string | undefined, fallback: number): number => {
+ if (value == null || value.trim() === '') return fallback;
+
+ const parsed = Number(value);
+ if (!Number.isFinite(parsed)) return fallback;
+
+ if (parsed < 0) return 0;
+ if (parsed > 1) return 1;
+ return parsed;
+};
+
+export function initSentry() {
+ const dsn = import.meta.env.VITE_SENTRY_DSN;
+ if (!dsn) return;
+
+ const enabledFromEnv = import.meta.env.VITE_SENTRY_ENABLED;
+ const enabled = enabledFromEnv === undefined ? import.meta.env.PROD : enabledFromEnv === 'true';
+ const shouldDebugTransactions = import.meta.env.DEV && import.meta.env.VITE_SENTRY_DEBUG_TRANSACTIONS === 'true';
+
+ Sentry.init({
+ dsn,
+ enabled,
+ debug: shouldDebugTransactions,
+ environment: import.meta.env.VITE_SENTRY_ENVIRONMENT ?? import.meta.env.MODE,
+ release: import.meta.env.VITE_SENTRY_RELEASE,
+ integrations: [
+ Sentry.reactRouterV7BrowserTracingIntegration({
+ useEffect,
+ useLocation,
+ useNavigationType,
+ createRoutesFromChildren,
+ matchRoutes,
+ }),
+ Sentry.replayIntegration({
+ maskAllText: true,
+ blockAllMedia: true,
+ }),
+ ],
+ tracePropagationTargets: ['localhost', ...(import.meta.env.VITE_API_PATH ? [import.meta.env.VITE_API_PATH] : [])],
+ tracesSampleRate: clampSampleRate(import.meta.env.VITE_SENTRY_TRACES_SAMPLE_RATE, 0.1),
+ replaysSessionSampleRate: clampSampleRate(import.meta.env.VITE_SENTRY_REPLAY_SESSION_SAMPLE_RATE, 0.0),
+ replaysOnErrorSampleRate: clampSampleRate(import.meta.env.VITE_SENTRY_REPLAY_ON_ERROR_SAMPLE_RATE, 1.0),
+ beforeSendTransaction: shouldDebugTransactions
+ ? (event) => {
+ console.log('[Sentry tx]', event.transaction, event.transaction_info?.source);
+ return event;
+ }
+ : undefined,
+ });
+}
diff --git a/src/global.d.ts b/src/global.d.ts
index c591fa3..48db795 100644
--- a/src/global.d.ts
+++ b/src/global.d.ts
@@ -3,3 +3,19 @@ interface Window {
postMessage: (message: string) => void;
};
}
+
+interface ImportMetaEnv {
+ readonly VITE_API_PATH: string;
+ readonly VITE_SENTRY_DSN?: string;
+ readonly VITE_SENTRY_ENABLED?: 'true' | 'false';
+ readonly VITE_SENTRY_ENVIRONMENT?: string;
+ readonly VITE_SENTRY_RELEASE?: string;
+ readonly VITE_SENTRY_TRACES_SAMPLE_RATE?: string;
+ readonly VITE_SENTRY_REPLAY_SESSION_SAMPLE_RATE?: string;
+ readonly VITE_SENTRY_REPLAY_ON_ERROR_SAMPLE_RATE?: string;
+ readonly VITE_SENTRY_DEBUG_TRANSACTIONS?: 'true' | 'false';
+}
+
+interface ImportMeta {
+ readonly env: ImportMetaEnv;
+}
diff --git a/src/main.tsx b/src/main.tsx
index a119752..884e6b7 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -1,12 +1,14 @@
import { StrictMode } from 'react';
+import * as Sentry from '@sentry/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { createRoot } from 'react-dom/client';
import './index.css';
-import App from './App.tsx';
+import { initSentry } from './config/sentry.ts';
import ToastProvider from './contexts/ToastContext';
import { installViewportVars } from './utils/ts/viewport.ts';
installViewportVars();
+initSentry();
const queryClient = new QueryClient({
defaultOptions: {
@@ -17,12 +19,35 @@ const queryClient = new QueryClient({
},
});
-createRoot(document.getElementById('root')!).render(
-
-
-
-
-
-
-
-);
+async function bootstrap() {
+ const { default: App } = await import('./App.tsx');
+
+ createRoot(document.getElementById('root')!).render(
+
+
+
+
Something went wrong.
+
+
+
+ }
+ >
+
+
+
+
+
+
+
+ );
+}
+
+void bootstrap();
diff --git a/vite.config.ts b/vite.config.ts
index 1d48bca..ef646eb 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,11 +1,22 @@
+import { sentryVitePlugin } from '@sentry/vite-plugin';
import tailwindcss from '@tailwindcss/vite';
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
import { VitePWA } from 'vite-plugin-pwa';
import svgr from 'vite-plugin-svgr';
+const sentryOrg = process.env.SENTRY_ORG;
+const sentryProject = process.env.SENTRY_PROJECT;
+const sentryAuthToken = process.env.SENTRY_AUTH_TOKEN;
+const sentryRelease = process.env.SENTRY_RELEASE;
+
+const shouldUploadSourcemaps = Boolean(sentryOrg && sentryProject && sentryAuthToken);
+
// https://vite.dev/config/
export default defineConfig({
+ build: {
+ sourcemap: shouldUploadSourcemaps ? 'hidden' : false,
+ },
plugins: [
react({
babel: {
@@ -82,6 +93,20 @@ export default defineConfig({
tailwindcss(),
svgr({ include: '**/*.svg' }),
+ ...(shouldUploadSourcemaps
+ ? [
+ sentryVitePlugin({
+ org: sentryOrg,
+ project: sentryProject,
+ authToken: sentryAuthToken,
+ telemetry: false,
+ release: sentryRelease ? { name: sentryRelease } : undefined,
+ sourcemaps: {
+ filesToDeleteAfterUpload: ['dist/**/*.map'],
+ },
+ }),
+ ]
+ : []),
],
resolve: {
alias: {