From b808281cff042693c5bdf9726bba2c1635b43c17 Mon Sep 17 00:00:00 2001 From: stepandel Date: Sat, 30 May 2026 18:54:26 -0700 Subject: [PATCH 1/7] Add Sentry Electron dependency --- package.json | 1 + pnpm-lock.yaml | 844 ++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 806 insertions(+), 39 deletions(-) diff --git a/package.json b/package.json index 19aad1e..3877d20 100644 --- a/package.json +++ b/package.json @@ -96,6 +96,7 @@ "@radix-ui/react-popover": "^1.1.15", "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-slot": "^1.2.4", + "@sentry/electron": "^7.13.0", "@tanstack/react-query": "^5.90.16", "@tanstack/react-table": "^8.21.3", "bufferutil": "^4.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index de87fc8..d5e038e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -74,6 +74,9 @@ importers: '@radix-ui/react-slot': specifier: ^1.2.4 version: 1.2.4(@types/react@19.2.7)(react@19.2.3) + '@sentry/electron': + specifier: ^7.13.0 + version: 7.13.0 '@tanstack/react-query': specifier: ^5.90.16 version: 5.90.16(react@19.2.3) @@ -176,7 +179,7 @@ importers: version: 0.14.6 vitest: specifier: ^4.1.7 - version: 4.1.7(@types/node@25.0.3)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.2)) + version: 4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.0.3)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.2)) packages: @@ -624,6 +627,11 @@ packages: resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} + '@fastify/otel@0.18.0': + resolution: {integrity: sha512-3TASCATfw+ctICSb4ymrv7iCm0qJ0N9CarB+CZ7zIJ7KqNbwI5JjyDL1/sxoC0ccTO1Zyd1iQ+oqncPg5FJXaA==} + peerDependencies: + '@opentelemetry/api': ^1.9.0 + '@floating-ui/core@1.7.3': resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} @@ -697,105 +705,89 @@ packages: resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.4': resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.4': resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-riscv64@1.2.4': resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.4': resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.4': resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.2.4': resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.4': resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-linux-arm64@0.34.5': resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [glibc] '@img/sharp-linux-arm@0.34.5': resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] - libc: [glibc] '@img/sharp-linux-ppc64@0.34.5': resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] - libc: [glibc] '@img/sharp-linux-riscv64@0.34.5': resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [riscv64] os: [linux] - libc: [glibc] '@img/sharp-linux-s390x@0.34.5': resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] - libc: [glibc] '@img/sharp-linux-x64@0.34.5': resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.5': resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] - libc: [musl] '@img/sharp-linuxmusl-x64@0.34.5': resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] - libc: [musl] '@img/sharp-wasm32@0.34.5': resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} @@ -875,6 +867,198 @@ packages: engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} deprecated: This functionality has been moved to @npmcli/fs + '@opentelemetry/api-logs@0.207.0': + resolution: {integrity: sha512-lAb0jQRVyleQQGiuuvCOTDVspc14nx6XJjP4FspJ1sNARo3Regq4ZZbrc3rN4b1TYSuUCvgH+UXUPug4SLOqEQ==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/api-logs@0.212.0': + resolution: {integrity: sha512-TEEVrLbNROUkYY51sBJGk7lO/OLjuepch8+hmpM6ffMJQ2z/KVCjdHuCFX6fJj8OkJP2zckPjrJzQtXU3IAsFg==} + engines: {node: '>=8.0.0'} + + '@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.6.1': + resolution: {integrity: sha512-8xHSGWpJP9wBxgBpnqGL0R3PbdWQndL1Qp50qrg71+B28zK5OQmUgcDKLJgzyAAV38t4tOyLMGDD60LneR5W8g==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/core@2.7.1': + resolution: {integrity: sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/instrumentation-amqplib@0.61.0': + resolution: {integrity: sha512-mCKoyTGfRNisge4br0NpOFSy2Z1NnEW8hbCJdUDdJFHrPqVzc4IIBPA/vX0U+LUcQqrQvJX+HMIU0dbDRe0i0Q==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-connect@0.57.0': + resolution: {integrity: sha512-FMEBChnI4FLN5TE9DHwfH7QpNir1JzXno1uz/TAucVdLCyrG0jTrKIcNHt/i30A0M2AunNBCkcd8Ei26dIPKdg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-dataloader@0.31.0': + resolution: {integrity: sha512-f654tZFQXS5YeLDNb9KySrwtg7SnqZN119FauD7acBoTzuLduaiGTNz88ixcVSOOMGZ+EjJu/RFtx5klObC95g==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-fs@0.33.0': + resolution: {integrity: sha512-sCZWXGalQ01wr3tAhSR9ucqFJ0phidpAle6/17HVjD6gN8FLmZMK/8sKxdXYHy3PbnlV1P4zeiSVFNKpbFMNLA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-generic-pool@0.57.0': + resolution: {integrity: sha512-orhmlaK+ZIW9hKU+nHTbXrCSXZcH83AescTqmpamHRobRmYSQwRbD0a1odc0yAzuzOtxYiHiXAnpnIpaSSY7Ow==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-graphql@0.62.0': + resolution: {integrity: sha512-3YNuLVPUxafXkH1jBAbGsKNsP3XVzcFDhCDCE3OqBwCwShlqQbLMRMFh1T/d5jaVZiGVmSsfof+ICKD2iOV8xg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-hapi@0.60.0': + resolution: {integrity: sha512-aNljZKYrEa7obLAxd1bCEDxF7kzCLGXTuTJZ8lMR9rIVEjmuKBXN1gfqpm/OB//Zc2zP4iIve1jBp7sr3mQV6w==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-http@0.214.0': + resolution: {integrity: sha512-FlkDhZDRjDJDcO2LcSCtjRpkal1NJ8y0fBqBhTvfAR3JSYY2jAIj1kSS5IjmEBt4c3aWv+u/lqLuoCDrrKCSKg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-ioredis@0.62.0': + resolution: {integrity: sha512-ZYt//zcPve8qklaZX+5Z4MkU7UpEkFRrxsf2cnaKYBitqDnsCN69CPAuuMOX6NYdW2rG9sFy7V/QWtBlP5XiNQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-kafkajs@0.23.0': + resolution: {integrity: sha512-4K+nVo+zI+aDz0Z85SObwbdixIbzS9moIuKJaYsdlzcHYnKOPtB7ya8r8Ezivy/GVIBHiKJVq4tv+BEkgOMLaQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-knex@0.58.0': + resolution: {integrity: sha512-Hc/o8fSsaWxZ8r1Yw4rNDLwTpUopTf4X32y4W6UhlHmW8Wizz8wfhgOKIelSeqFVTKBBPIDUOsQWuIMxBmu8Bw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-koa@0.62.0': + resolution: {integrity: sha512-uVip0VuGUQXZ+vFxkKxAUNq8qNl+VFlyHDh/U6IQ8COOEDfbEchdaHnpFrMYF3psZRUuoSIgb7xOeXj00RdwDA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.9.0 + + '@opentelemetry/instrumentation-lru-memoizer@0.58.0': + resolution: {integrity: sha512-6grM3TdMyHzlGY1cUA+mwoPueB1F3dYKgKtZIH6jOFXqfHAByyLTc+6PFjGM9tKh52CFBJaDwodNlL/Td39z7Q==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-mongodb@0.67.0': + resolution: {integrity: sha512-1WJp5N1lYfHq2IhECOTewFs5Tf2NfUOwQRqs/rZdXKTezArMlucxgzAaqcgp3A3YREXopXTpXHsxZTGHjNhMdQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-mongoose@0.60.0': + resolution: {integrity: sha512-8BahAZpKsOoc+lrZGb7Ofn4g3z8qtp5IxDfvAVpKXsEheQN7ONMH5djT5ihy6yf8yyeQJGS0gXFfpEAEeEHqQg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-mysql2@0.60.0': + resolution: {integrity: sha512-m/5d3bxQALllCzezYDk/6vajh0tj5OijMMvOZGr+qN1NMXm1dzMNwyJ0gNZW7Fo3YFRyj/jJMxIw+W7d525dlw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-mysql@0.60.0': + resolution: {integrity: sha512-08pO8GFPEIz2zquKDGteBZDNmwketdgH8hTe9rVYgW9kCJXq1Psj3wPQGx+VaX4ZJKCfPeoLMYup9+cxHvZyVQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-pg@0.66.0': + resolution: {integrity: sha512-KxfLGXBb7k2ueaPJfq2GXBDXBly8P+SpR/4Mj410hhNgmQF3sCqwXvUBQxZQkDAmsdBAoenM+yV1LhtsMRamcA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-redis@0.62.0': + resolution: {integrity: sha512-y3pPpot7WzR/8JtHcYlTYsyY8g+pbFhAqbwAuG5bLPnR6v6pt1rQc0DpH0OlGP/9CZbWBP+Zhwp9yFoygf/ZXQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation-tedious@0.33.0': + resolution: {integrity: sha512-Q6WQwAD01MMTub31GlejoiFACYNw26J426wyjvU7by7fDIr2nZXNW4vhTGs7i7F0TnXBO3xN688g1tdUgYwJ5w==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation@0.207.0': + resolution: {integrity: sha512-y6eeli9+TLKnznrR8AZlQMSJT7wILpXH+6EYq5Vf/4Ao+huI7EedxQHwRgVUOMLFbe7VFDvHJrX9/f4lcwnJsA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/instrumentation@0.212.0': + resolution: {integrity: sha512-IyXmpNnifNouMOe0I/gX7ENfv2ZCNdYTF0FpCsoBcpbIHzk81Ww9rQTYTnvghszCg7qGrIhNvWC8dhEifgX9Jg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.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/redis-common@0.38.3': + resolution: {integrity: sha512-VCghU1JYs/4gP6Gqf/xro9MEsZ7LrMv2uONVsaESKL38ZOB9BqnI98FfS23wjMnHlpuE+TTaWSoAVNpTwYXzjw==} + engines: {node: ^18.19.0 || >=20.6.0} + + '@opentelemetry/resources@2.7.1': + resolution: {integrity: sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-trace-base@2.7.1': + resolution: {integrity: sha512-NAYIlsF8MPUsKqJMiDQJTMPOmlbawC1Iz/omMLygZ1C9am8fTKYjTaI+OZM+WTY3t3Glo0wnOg/6/pac6RGPPw==} + 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'} + + '@opentelemetry/sql-common@0.41.2': + resolution: {integrity: sha512-4mhWm3Z8z+i508zQJ7r6Xi7y4mmoJpdvH0fZPFRkWrdp5fq7hhZ2HhYokEOLkfqSMgPR4Z9EyB3DBkbKGOqZiQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -884,6 +1068,11 @@ packages: engines: {node: '>=18'} hasBin: true + '@prisma/instrumentation@7.6.0': + resolution: {integrity: sha512-ZPW2gRiwpPzEfgeZgaekhqXrbW+Y2RJKHVqUmlhZhKzRNCcvR6DykzylDrynpArKKRQtLxoZy36fK7U0p3pdgQ==} + peerDependencies: + '@opentelemetry/api': ^1.8 + '@protobufjs/aspromise@1.1.2': resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} @@ -1287,67 +1476,56 @@ packages: resolution: {integrity: sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==} cpu: [arm] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.54.0': resolution: {integrity: sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==} cpu: [arm] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.54.0': resolution: {integrity: sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==} cpu: [arm64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.54.0': resolution: {integrity: sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==} cpu: [arm64] os: [linux] - libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.54.0': resolution: {integrity: sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==} cpu: [loong64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.54.0': resolution: {integrity: sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==} cpu: [ppc64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.54.0': resolution: {integrity: sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==} cpu: [riscv64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.54.0': resolution: {integrity: sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==} cpu: [riscv64] os: [linux] - libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.54.0': resolution: {integrity: sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==} cpu: [s390x] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.54.0': resolution: {integrity: sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==} cpu: [x64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-musl@4.54.0': resolution: {integrity: sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==} cpu: [x64] os: [linux] - libc: [musl] '@rollup/rollup-openharmony-arm64@4.54.0': resolution: {integrity: sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==} @@ -1374,6 +1552,75 @@ packages: cpu: [x64] os: [win32] + '@sentry-internal/browser-utils@10.50.0': + resolution: {integrity: sha512-42bxyRTxnCmYlWnvz4CxikuQNanw8UNma2WJrtxJ0f1MAJV2GhQGSHDLnA+lvFlmiz6qct3pfen/NXGyOTegTA==} + engines: {node: '>=18'} + + '@sentry-internal/feedback@10.50.0': + resolution: {integrity: sha512-0k9XZF0wn86f77mIO2U3gNNyDZooy139CnEanRzHinrN106vVzvBZ6TUEQoHtoO1fqQxr+nWWVrqV/PXUqk47w==} + engines: {node: '>=18'} + + '@sentry-internal/replay-canvas@10.50.0': + resolution: {integrity: sha512-jx6RKBmcJSWdI92qDGS/sBv1w+7Cww879Z/moX7bw7ipHa/Ts3iDcB3rgZwvhmi17U+mvYsbJeL2DXkPo3TjPw==} + engines: {node: '>=18'} + + '@sentry-internal/replay@10.50.0': + resolution: {integrity: sha512-51FYNfnvVLAWw1rrEWPFfwHuMRb9mkVCFGA4J9/un7SpeGBsQDziGB0Di4fsCxI7+EdSBpfLHPF0csKtCCw0oQ==} + engines: {node: '>=18'} + + '@sentry/browser@10.50.0': + resolution: {integrity: sha512-1f6rAvET6myiTaSeYqvaaBwvq1LfxqWjAPIoAW/NVC9bPMkeEcuvgDajHrnZMrBeWoJ81NMyoLkyX+iOc7MoFA==} + engines: {node: '>=18'} + + '@sentry/core@10.50.0': + resolution: {integrity: sha512-J4A+vzUO3adl0TkFCjaN1+4miamrjHiEIYuLHiuu1lmAjq5WIVw32ObvAh4yMwNtxyaEMosTrrh5M6f12XSJFg==} + engines: {node: '>=18'} + + '@sentry/electron@7.13.0': + resolution: {integrity: sha512-zW/1c9fKafCZsvhRRp9mIDH9bSvzBiIUwoN087zDDHc0vatVsqqai8nUk0bUewwYZY4Inia7r5w+kPWi8LXZzg==} + peerDependencies: + '@sentry/node-native': 10.50.0 + peerDependenciesMeta: + '@sentry/node-native': + optional: true + + '@sentry/node-core@10.50.0': + resolution: {integrity: sha512-Eb1BYf4Lc7ZYmdX3acKP6SgyGikrBA370gbGHaWI5jRu7G7vig8sIu1ghPmY5AlvqBPOetado7GniXr6fAXbTw==} + 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 + '@opentelemetry/semantic-conventions': ^1.39.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 + '@opentelemetry/semantic-conventions': + optional: true + + '@sentry/node@10.50.0': + resolution: {integrity: sha512-TvwzFQu8MGKzMQ2/tqxcNzFA8UG2kKTB+GDmA4uOzx3+GT849YZRRSJzEXCmYhk1teVd2fbmgqyYY2nyLF5a+Q==} + engines: {node: '>=18'} + + '@sentry/opentelemetry@10.50.0': + resolution: {integrity: sha512-axn3pgDPveGdaMUC0abMCmFN7ux2pA5ebPufCef4lMIsyg7BBQvaEJ+vE19wjstMaBCAJGsdZlL3eeP2rtgRMw==} + 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 + '@opentelemetry/semantic-conventions': ^1.39.0 + '@sindresorhus/is@4.6.0': resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} @@ -1599,28 +1846,24 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.1.18': resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.1.18': resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.1.18': resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.1.18': resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} @@ -1682,6 +1925,9 @@ packages: '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} @@ -1709,6 +1955,9 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/mysql@2.15.27': + resolution: {integrity: sha512-YfWiV16IY0OeBfBCk8+hXKmdTKrKlwKN1MNKAPBu5JYxLwBEZl7QzeEpGnlZb3VMGJrrGmB84gXiH+ofs/TezA==} + '@types/node-fetch@2.6.13': resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} @@ -1727,6 +1976,12 @@ packages: '@types/parquetjs@0.10.6': resolution: {integrity: sha512-ZCsD6j97YD0mGU8/VnVs3NjORXa7zeHvqlpJpCqy4jU8a1O21dalL+MFn9QNbdEfy8rszR1N7NHeT7/LdtHf+A==} + '@types/pg-pool@2.0.7': + resolution: {integrity: sha512-U4CwmGVQcbEuqpyju8/ptOKg6gEC+Tqsvj2xS9o1g71bUh8twxnC6ZL5rZKCsGN0iyH0CwgUyc9VR5owNQF9Ng==} + + '@types/pg@8.15.6': + resolution: {integrity: sha512-NoaMtzhxOrubeL/7UZuNTrejB4MPAJ0RpxZqXQf2qXuVlTPuG6Y8p4u9dKRaue4yjmC7ZhzVO2/Yyyn25znrPQ==} + '@types/plist@3.0.5': resolution: {integrity: sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==} @@ -1753,6 +2008,9 @@ packages: '@types/ssh2@1.15.5': resolution: {integrity: sha512-N1ASjp/nXH3ovBHddRJpli4ozpk6UdDYIX4RJWFa9L1YKnzdhTlVmiGHm4DZnj/jLbqZpes4aeR30EFGQtvhQQ==} + '@types/tedious@4.0.14': + resolution: {integrity: sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==} + '@types/verror@1.10.11': resolution: {integrity: sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==} @@ -1799,6 +2057,16 @@ packages: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} + acorn-import-attributes@1.9.5: + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} + peerDependencies: + acorn: ^8 + + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -1931,6 +2199,10 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + bare-events@2.8.2: resolution: {integrity: sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==} peerDependencies: @@ -2001,6 +2273,10 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@5.0.6: + resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} + engines: {node: 18 || 20 || >=22} + brotli@1.3.3: resolution: {integrity: sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==} @@ -2114,14 +2390,12 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] chromadb-js-bindings-linux-x64-gnu@1.2.0: resolution: {integrity: sha512-0E65eSuWICoD2jhQ+ZLi5Me08+VxICG0f5lZ4ceiMPXTemc60QmkmhtKQVK5lEhqRWu2CLSYXqlusnD5qEoa1Q==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] chromadb-js-bindings-win32-x64-msvc@1.2.0: resolution: {integrity: sha512-1gmVdgw/spSSYvbc7Ogms9FXf+Zad41Cp7Enqfvrp7m9qQ+Nz4NqZINfOEX5OVzPHEj6cfXA11NdGeNHTPPHOg==} @@ -2141,6 +2415,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==} @@ -2548,6 +2825,9 @@ packages: resolution: {integrity: sha512-8e1++BCiTzUno9v5IZ2J6bv4RU+3UKDmqWUQD0MIMVCd9AdhWkO1gw57oo1mNEX1dMq2EGI+FbWz4B92pscSQg==} engines: {node: '>= 18'} + forwarded-parse@2.1.2: + resolution: {integrity: sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==} + fraction.js@5.3.4: resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} @@ -2734,6 +3014,13 @@ packages: ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + import-in-the-middle@2.0.6: + resolution: {integrity: sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw==} + + import-in-the-middle@3.0.1: + resolution: {integrity: sha512-pYkiyXVL2Mf3pozdlDGV6NAObxQx13Ae8knZk1UJRJ6uRW/ZRmTGHlQYtrsSl7ubuE5F8CD1z+s1n4RHNuTtuA==} + engines: {node: '>=18'} + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -2895,28 +3182,24 @@ 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==} @@ -3028,6 +3311,10 @@ packages: resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} engines: {node: 20 || >=22} + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -3094,6 +3381,9 @@ packages: engines: {node: '>=10'} hasBin: true + module-details-from-path@1.0.4: + resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -3251,6 +3541,17 @@ packages: pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + pg-protocol@1.14.0: + resolution: {integrity: sha512-n5taZ1kO3s9ngDTVxsEznOqCyToTgz0FLuPq0B33COy5pPpuWJpY3/2oRBVETuOgzdqRXfWpM9HIhp2LBBT1BA==} + + pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -3282,6 +3583,22 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + postgres-bytea@1.0.1: + resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} + engines: {node: '>=0.10.0'} + + postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + postject@1.0.0-alpha.6: resolution: {integrity: sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==} engines: {node: '>=14.0.0'} @@ -3425,6 +3742,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'} + resedit@1.7.2: resolution: {integrity: sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==} engines: {node: '>=12', npm: '>=6'} @@ -4823,6 +5144,16 @@ snapshots: '@fastify/busboy@2.1.1': {} + '@fastify/otel@0.18.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.212.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + minimatch: 10.2.5 + transitivePeerDependencies: + - supports-color + '@floating-ui/core@1.7.3': dependencies: '@floating-ui/utils': 0.2.10 @@ -5046,6 +5377,252 @@ snapshots: mkdirp: 1.0.4 rimraf: 3.0.2 + '@opentelemetry/api-logs@0.207.0': + dependencies: + '@opentelemetry/api': 1.9.1 + + '@opentelemetry/api-logs@0.212.0': + dependencies: + '@opentelemetry/api': 1.9.1 + + '@opentelemetry/api-logs@0.214.0': + dependencies: + '@opentelemetry/api': 1.9.1 + + '@opentelemetry/api@1.9.1': {} + + '@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/semantic-conventions': 1.41.1 + + '@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/semantic-conventions': 1.41.1 + + '@opentelemetry/instrumentation-amqplib@0.61.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-connect@0.57.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + '@types/connect': 3.4.38 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-dataloader@0.31.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-fs@0.33.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-generic-pool@0.57.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-graphql@0.62.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-hapi@0.60.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-http@0.214.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.6.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + forwarded-parse: 2.1.2 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-ioredis@0.62.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/redis-common': 0.38.3 + '@opentelemetry/semantic-conventions': 1.41.1 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-kafkajs@0.23.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-knex@0.58.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-koa@0.62.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-lru-memoizer@0.58.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-mongodb@0.67.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-mongoose@0.60.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-mysql2@0.60.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + '@opentelemetry/sql-common': 0.41.2(@opentelemetry/api@1.9.1) + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-mysql@0.60.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + '@types/mysql': 2.15.27 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-pg@0.66.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + '@opentelemetry/sql-common': 0.41.2(@opentelemetry/api@1.9.1) + '@types/pg': 8.15.6 + '@types/pg-pool': 2.0.7 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-redis@0.62.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/redis-common': 0.38.3 + '@opentelemetry/semantic-conventions': 1.41.1 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation-tedious@0.33.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + '@types/tedious': 4.0.14 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation@0.207.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.207.0 + import-in-the-middle: 2.0.6 + require-in-the-middle: 8.0.1 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/instrumentation@0.212.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.212.0 + import-in-the-middle: 2.0.6 + require-in-the-middle: 8.0.1 + transitivePeerDependencies: + - supports-color + + '@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.0.1 + require-in-the-middle: 8.0.1 + transitivePeerDependencies: + - supports-color + + '@opentelemetry/redis-common@0.38.3': {} + + '@opentelemetry/resources@2.7.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + + '@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + + '@opentelemetry/semantic-conventions@1.41.1': {} + + '@opentelemetry/sql-common@0.41.2(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@pkgjs/parseargs@0.11.0': optional: true @@ -5053,6 +5630,13 @@ snapshots: dependencies: playwright: 1.60.0 + '@prisma/instrumentation@7.6.0(@opentelemetry/api@1.9.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/instrumentation': 0.207.0(@opentelemetry/api@1.9.1) + transitivePeerDependencies: + - supports-color + '@protobufjs/aspromise@1.1.2': {} '@protobufjs/base64@1.1.2': {} @@ -5456,6 +6040,100 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.54.0': optional: true + '@sentry-internal/browser-utils@10.50.0': + dependencies: + '@sentry/core': 10.50.0 + + '@sentry-internal/feedback@10.50.0': + dependencies: + '@sentry/core': 10.50.0 + + '@sentry-internal/replay-canvas@10.50.0': + dependencies: + '@sentry-internal/replay': 10.50.0 + '@sentry/core': 10.50.0 + + '@sentry-internal/replay@10.50.0': + dependencies: + '@sentry-internal/browser-utils': 10.50.0 + '@sentry/core': 10.50.0 + + '@sentry/browser@10.50.0': + dependencies: + '@sentry-internal/browser-utils': 10.50.0 + '@sentry-internal/feedback': 10.50.0 + '@sentry-internal/replay': 10.50.0 + '@sentry-internal/replay-canvas': 10.50.0 + '@sentry/core': 10.50.0 + + '@sentry/core@10.50.0': {} + + '@sentry/electron@7.13.0': + dependencies: + '@sentry/browser': 10.50.0 + '@sentry/core': 10.50.0 + '@sentry/node': 10.50.0 + transitivePeerDependencies: + - '@opentelemetry/exporter-trace-otlp-http' + - supports-color + + '@sentry/node-core@10.50.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.41.1)': + dependencies: + '@sentry/core': 10.50.0 + '@sentry/opentelemetry': 10.50.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.41.1) + import-in-the-middle: 3.0.1 + optionalDependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + + '@sentry/node@10.50.0': + dependencies: + '@fastify/otel': 0.18.0(@opentelemetry/api@1.9.1) + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-amqplib': 0.61.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-connect': 0.57.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-dataloader': 0.31.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-fs': 0.33.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-generic-pool': 0.57.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-graphql': 0.62.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-hapi': 0.60.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-http': 0.214.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-ioredis': 0.62.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-kafkajs': 0.23.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-knex': 0.58.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-koa': 0.62.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-lru-memoizer': 0.58.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-mongodb': 0.67.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-mongoose': 0.60.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-mysql': 0.60.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-mysql2': 0.60.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-pg': 0.66.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-redis': 0.62.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation-tedious': 0.33.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + '@prisma/instrumentation': 7.6.0(@opentelemetry/api@1.9.1) + '@sentry/core': 10.50.0 + '@sentry/node-core': 10.50.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.214.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.41.1) + '@sentry/opentelemetry': 10.50.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.41.1) + import-in-the-middle: 3.0.1 + transitivePeerDependencies: + - '@opentelemetry/exporter-trace-otlp-http' + - supports-color + + '@sentry/opentelemetry@10.50.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.7.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.41.1)': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.7.1(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.41.1 + '@sentry/core': 10.50.0 + '@sindresorhus/is@4.6.0': {} '@smithy/abort-controller@4.2.7': @@ -5842,6 +6520,10 @@ snapshots: '@types/deep-eql': 4.0.2 assertion-error: 2.0.1 + '@types/connect@3.4.38': + dependencies: + '@types/node': 25.0.3 + '@types/debug@4.1.12': dependencies: '@types/ms': 2.1.0 @@ -5873,6 +6555,10 @@ snapshots: '@types/ms@2.1.0': {} + '@types/mysql@2.15.27': + dependencies: + '@types/node': 25.0.3 + '@types/node-fetch@2.6.13': dependencies: '@types/node': 25.0.3 @@ -5898,6 +6584,16 @@ snapshots: dependencies: '@types/node-int64': 0.4.32 + '@types/pg-pool@2.0.7': + dependencies: + '@types/pg': 8.15.6 + + '@types/pg@8.15.6': + dependencies: + '@types/node': 25.0.3 + pg-protocol: 1.14.0 + pg-types: 2.2.0 + '@types/plist@3.0.5': dependencies: '@types/node': 25.0.3 @@ -5933,6 +6629,10 @@ snapshots: dependencies: '@types/node': 18.19.130 + '@types/tedious@4.0.14': + dependencies: + '@types/node': 25.0.3 + '@types/verror@1.10.11': optional: true @@ -5990,6 +6690,12 @@ snapshots: dependencies: event-target-shim: 5.0.1 + acorn-import-attributes@1.9.5(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + + acorn@8.16.0: {} + agent-base@6.0.2: dependencies: debug: 4.4.3 @@ -6159,6 +6865,8 @@ snapshots: balanced-match@1.0.2: {} + balanced-match@4.0.4: {} + bare-events@2.8.2: {} bare-fs@4.5.2: @@ -6228,6 +6936,10 @@ snapshots: dependencies: balanced-match: 1.0.2 + brace-expansion@5.0.6: + dependencies: + balanced-match: 4.0.4 + brotli@1.3.3: dependencies: base64-js: 1.5.1 @@ -6394,6 +7106,8 @@ snapshots: ci-info@3.9.0: {} + cjs-module-lexer@2.2.0: {} + class-variance-authority@0.7.1: dependencies: clsx: 2.1.1 @@ -6889,6 +7603,8 @@ snapshots: formdata-node@6.0.3: {} + forwarded-parse@2.1.2: {} + fraction.js@5.3.4: {} fs-constants@1.0.0: {} @@ -7140,6 +7856,20 @@ snapshots: ieee754@1.2.1: {} + import-in-the-middle@2.0.6: + dependencies: + acorn: 8.16.0 + acorn-import-attributes: 1.9.5(acorn@8.16.0) + cjs-module-lexer: 2.2.0 + module-details-from-path: 1.0.4 + + import-in-the-middle@3.0.1: + dependencies: + acorn: 8.16.0 + acorn-import-attributes: 1.9.5(acorn@8.16.0) + cjs-module-lexer: 2.2.0 + module-details-from-path: 1.0.4 + imurmurhash@0.1.4: {} indent-string@4.0.0: {} @@ -7383,6 +8113,10 @@ snapshots: dependencies: '@isaacs/brace-expansion': 5.0.0 + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.6 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -7446,6 +8180,8 @@ snapshots: mkdirp@1.0.4: {} + module-details-from-path@1.0.4: {} + ms@2.1.3: {} nan@2.24.0: @@ -7596,6 +8332,18 @@ snapshots: pend@1.2.0: {} + pg-int8@1.0.1: {} + + pg-protocol@1.14.0: {} + + pg-types@2.2.0: + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.1 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + picocolors@1.1.1: {} picomatch@4.0.3: {} @@ -7624,6 +8372,16 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postgres-array@2.0.0: {} + + postgres-bytea@1.0.1: {} + + postgres-date@1.0.7: {} + + postgres-interval@1.2.0: + dependencies: + xtend: 4.0.2 + postject@1.0.0-alpha.6: dependencies: commander: 9.5.0 @@ -7768,6 +8526,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 + resedit@1.7.2: dependencies: pe-library: 0.4.1 @@ -8320,7 +9085,7 @@ snapshots: lightningcss: 1.30.2 yaml: 2.8.2 - vitest@4.1.7(@types/node@25.0.3)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.2)): + vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.0.3)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.2)): dependencies: '@vitest/expect': 4.1.7 '@vitest/mocker': 4.1.7(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.2)) @@ -8343,6 +9108,7 @@ snapshots: vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: + '@opentelemetry/api': 1.9.1 '@types/node': 25.0.3 transitivePeerDependencies: - msw From d843813ff1028573a997418d05c13fd91146242d Mon Sep 17 00:00:00 2001 From: stepandel Date: Sat, 30 May 2026 18:57:57 -0700 Subject: [PATCH 2/7] Wire Sentry error monitoring --- electron/error-monitoring.ts | 115 +++++++++++++++++++++++++++++++ electron/ipc-contract.ts | 8 +++ electron/main.ts | 32 +++++++++ electron/preload.ts | 18 +++++ electron/settings-store.ts | 11 +++ src/components/ErrorBoundary.tsx | 39 +++++++++++ src/error-monitoring.ts | 44 ++++++++++++ src/main.tsx | 16 +++-- src/windows/SettingsWindow.tsx | 58 ++++++++++++++-- vite.config.js | 2 + 10 files changed, 333 insertions(+), 10 deletions(-) create mode 100644 electron/error-monitoring.ts create mode 100644 src/components/ErrorBoundary.tsx create mode 100644 src/error-monitoring.ts diff --git a/electron/error-monitoring.ts b/electron/error-monitoring.ts new file mode 100644 index 0000000..1597b3c --- /dev/null +++ b/electron/error-monitoring.ts @@ -0,0 +1,115 @@ +import { app } from 'electron' +import * as Sentry from '@sentry/electron/main' + +const SENSITIVE_KEY_PATTERN = /(api[-_]?key|token|secret|password|credential|authorization|document|metadata|embedding|query|url)/i +const URL_PATTERN = /\bhttps?:\/\/[^\s"'<>]+/gi +const LONG_TOKEN_PATTERN = /\b[A-Za-z0-9_-]{32,}\b/g +const MAX_STRING_LENGTH = 500 + +let initialized = false + +function redactString(value: string): string { + return value + .replace(URL_PATTERN, '[redacted-url]') + .replace(LONG_TOKEN_PATTERN, '[redacted-token]') + .slice(0, MAX_STRING_LENGTH) +} + +function sanitizeValue(value: unknown, key = ''): unknown { + if (SENSITIVE_KEY_PATTERN.test(key)) { + return '[redacted]' + } + + if (typeof value === 'string') { + return redactString(value) + } + + if (Array.isArray(value)) { + return value.slice(0, 10).map((item) => sanitizeValue(item)) + } + + if (value && typeof value === 'object') { + const entries = Object.entries(value as Record).slice(0, 30) + return Object.fromEntries(entries.map(([entryKey, entryValue]) => [ + entryKey, + sanitizeValue(entryValue, entryKey), + ])) + } + + return value +} + +function getSentryDsn(): string { + return process.env.SENTRY_DSN || process.env.VITE_SENTRY_DSN || '' +} + +export function initErrorMonitoring(enabled: boolean): void { + if (initialized || Sentry.isInitialized()) { + initialized = true + return + } + + const dsn = getSentryDsn() + if (!enabled || !dsn) { + if (!dsn) { + console.log('[ErrorMonitoring] SENTRY_DSN not configured, error reporting disabled') + } + return + } + + Sentry.init({ + dsn, + environment: app.isPackaged ? 'production' : 'development', + release: `chroma-explorer@${app.getVersion()}`, + sendDefaultPii: false, + tracesSampleRate: 0, + beforeBreadcrumb(breadcrumb) { + return sanitizeValue(breadcrumb) as Sentry.Breadcrumb + }, + beforeSend(event) { + const sanitized = sanitizeValue(event) as Sentry.ErrorEvent + delete sanitized.request + delete sanitized.user + return sanitized + }, + }) + + Sentry.setTags({ + packaged: String(app.isPackaged), + platform: process.platform, + arch: process.arch, + electron: process.versions.electron || 'unknown', + }) + + initialized = true + console.log('[ErrorMonitoring] Initialized successfully') +} + +export function setErrorMonitoringEnabled(enabled: boolean): void { + if (enabled) { + initErrorMonitoring(true) + return + } + + if (initialized || Sentry.isInitialized()) { + void Sentry.close(2000).finally(() => { + initialized = false + console.log('[ErrorMonitoring] Disabled') + }) + } +} + +export function captureMainError(error: unknown, context?: Record): void { + if (!initialized && !Sentry.isInitialized()) { + return + } + + Sentry.withScope((scope) => { + if (context) { + scope.setTags(Object.fromEntries( + Object.entries(context).map(([key, value]) => [key, String(value)]) + )) + } + Sentry.captureException(error) + }) +} diff --git a/electron/ipc-contract.ts b/electron/ipc-contract.ts index 72ee256..9de0eae 100644 --- a/electron/ipc-contract.ts +++ b/electron/ipc-contract.ts @@ -236,6 +236,9 @@ export interface ElectronAPI { setApiKeys: (apiKeys: Record) => Promise getTheme: () => Promise<'light' | 'dark' | 'system'> setTheme: (theme: 'light' | 'dark' | 'system') => Promise + getErrorReportingEnabled: () => Promise + setErrorReportingEnabled: (enabled: boolean) => Promise + onErrorReportingChange: (callback: (enabled: boolean) => void) => () => void onThemeChange: (callback: (theme: string) => void) => () => void openWindow: () => Promise onSwitchTab: (callback: (tab: string) => void) => () => void @@ -482,6 +485,11 @@ export function parseTheme(value: unknown): 'light' | 'dark' | 'system' { return parseEnum(value, 'theme', ['light', 'dark', 'system']) } +export function parseErrorReportingEnabled(value: unknown): boolean { + if (typeof value !== 'boolean') throw new Error('errorReportingEnabled must be a boolean') + return value +} + export function validateExternalUrl(value: unknown): string { const url = parseString(value, 'url') const parsed = new URL(url) diff --git a/electron/main.ts b/electron/main.ts index 09fbf92..fab8f1c 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -26,6 +26,7 @@ import { parseCreateDocumentsBatchParams, parseDeleteDocumentsParams, parseEmbeddingOverride, + parseErrorReportingEnabled, parseProfileId, parseSearchDocumentsParams, parseTheme, @@ -35,10 +36,12 @@ import { openValidatedExternalUrl } from './external-url' import { initAutoUpdater, checkForUpdates } from './auto-updater' import { initAnalytics, track } from './analytics' import { configureTransformersCache } from './transformers-cache' +import { initErrorMonitoring, setErrorMonitoringEnabled } from './error-monitoring' // Inject stored API keys into process.env at startup configureTransformersCache() settingsStore.injectIntoProcessEnv() +initErrorMonitoring(settingsStore.isErrorReportingEnabled()) // Track active copy operations per profile for cancellation const activeCopyOperations: Map = new Map() @@ -621,6 +624,35 @@ ipcMain.handle('settings:setTheme', async (event, rawTheme: unknown) => { } }) +ipcMain.handle('settings:getErrorReportingEnabled', async () => { + try { + return { success: true, data: settingsStore.isErrorReportingEnabled() } + } catch (error) { + const message = error instanceof Error ? error.message : 'Failed to get error reporting setting' + return { success: false, error: message } + } +}) + +ipcMain.handle('settings:setErrorReportingEnabled', async (event, rawEnabled: unknown) => { + try { + const enabled = parseErrorReportingEnabled(rawEnabled) + settingsStore.setErrorReportingEnabled(enabled) + setErrorMonitoringEnabled(enabled) + + const senderWindow = BrowserWindow.fromWebContents(event.sender) + BrowserWindow.getAllWindows().forEach(win => { + if (win !== senderWindow) { + win.webContents.send('settings:error-reporting-changed', enabled) + } + }) + + return { success: true } + } catch (error) { + const message = error instanceof Error ? error.message : 'Failed to set error reporting setting' + return { success: false, error: message } + } +}) + ipcMain.handle('settings:openWindow', async () => { try { windowManager.createSettingsWindow() diff --git a/electron/preload.ts b/electron/preload.ts index db686f5..95539be 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -242,6 +242,24 @@ contextBridge.exposeInMainWorld('electronAPI', { throw new Error(result.error) } }, + getErrorReportingEnabled: async (): Promise => { + const result = await ipcRenderer.invoke('settings:getErrorReportingEnabled') + if (!result.success) { + throw new Error(result.error) + } + return result.data + }, + setErrorReportingEnabled: async (enabled: boolean): Promise => { + const result = await ipcRenderer.invoke('settings:setErrorReportingEnabled', enabled) + if (!result.success) { + throw new Error(result.error) + } + }, + onErrorReportingChange: (callback: (enabled: boolean) => void): (() => void) => { + const handler = (_event: any, enabled: boolean) => callback(enabled) + ipcRenderer.on('settings:error-reporting-changed', handler) + return () => ipcRenderer.removeListener('settings:error-reporting-changed', handler) + }, onThemeChange: (callback: (theme: string) => void): (() => void) => { const handler = (_event: any, theme: string) => callback(theme) ipcRenderer.on('settings:theme-changed', handler) diff --git a/electron/settings-store.ts b/electron/settings-store.ts index 3791f4c..c5b1322 100644 --- a/electron/settings-store.ts +++ b/electron/settings-store.ts @@ -23,6 +23,7 @@ export type Theme = 'light' | 'dark' | 'system' interface SettingsSchema { apiKeys: ApiKeys theme: Theme + errorReportingEnabled: boolean } // Legacy store schema (v1 - before theme was added) @@ -75,6 +76,7 @@ function getStore(): Store { defaults: { apiKeys: {}, theme: 'system', + errorReportingEnabled: false, }, encryptionKey: getEncryptionKey(), clearInvalidConfig: true, @@ -100,6 +102,7 @@ function getStore(): Store { defaults: { apiKeys: {}, theme: 'system', + errorReportingEnabled: false, }, encryptionKey: getEncryptionKey(), clearInvalidConfig: true, @@ -147,6 +150,14 @@ export class SettingsStore { setTheme(theme: Theme): void { getStore().set('theme', theme) } + + isErrorReportingEnabled(): boolean { + return getStore().get('errorReportingEnabled', false) + } + + setErrorReportingEnabled(enabled: boolean): void { + getStore().set('errorReportingEnabled', enabled) + } } export const settingsStore = new SettingsStore() diff --git a/src/components/ErrorBoundary.tsx b/src/components/ErrorBoundary.tsx new file mode 100644 index 0000000..fc47e35 --- /dev/null +++ b/src/components/ErrorBoundary.tsx @@ -0,0 +1,39 @@ +import React from 'react' +import { captureRendererError } from '../error-monitoring' + +interface ErrorBoundaryState { + error: Error | null +} + +export class ErrorBoundary extends React.Component { + state: ErrorBoundaryState = { + error: null, + } + + static getDerivedStateFromError(error: Error): ErrorBoundaryState { + return { error } + } + + componentDidCatch(error: Error, info: React.ErrorInfo): void { + captureRendererError(error, { + componentStack: info.componentStack ? 'present' : 'missing', + }) + } + + render() { + if (this.state.error) { + return ( +
+
+

Something went wrong

+

+ Restart Chroma Explorer and try the action again. +

+
+
+ ) + } + + return this.props.children + } +} diff --git a/src/error-monitoring.ts b/src/error-monitoring.ts new file mode 100644 index 0000000..8a93e6a --- /dev/null +++ b/src/error-monitoring.ts @@ -0,0 +1,44 @@ +import * as Sentry from '@sentry/electron/renderer' + +let initialized = false + +export async function initRendererErrorMonitoring(): Promise { + try { + const enabled = await window.electronAPI.settings.getErrorReportingEnabled() + setRendererErrorMonitoringEnabled(enabled) + + window.electronAPI.settings.onErrorReportingChange((nextEnabled) => { + setRendererErrorMonitoringEnabled(nextEnabled) + }) + } catch (error) { + console.warn('[ErrorMonitoring] Failed to read renderer setting:', error) + } +} + +export function setRendererErrorMonitoringEnabled(enabled: boolean): void { + if (enabled && !initialized && !Sentry.isInitialized()) { + Sentry.init() + initialized = true + return + } + + if (!enabled && (initialized || Sentry.isInitialized())) { + const client = Sentry.getClient() + void Promise.resolve(client?.close(2000)).finally(() => { + initialized = false + }) + } +} + +export function captureRendererError(error: unknown, context?: Record): void { + if (!initialized && !Sentry.isInitialized()) { + return + } + + Sentry.withScope((scope) => { + if (context) { + scope.setTags(context) + } + Sentry.captureException(error) + }) +} diff --git a/src/main.tsx b/src/main.tsx index aa08c8e..c94350a 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -3,6 +3,8 @@ import ReactDOM from 'react-dom/client' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { ThemeProvider } from './context/ThemeContext' import App from './App' +import { ErrorBoundary } from './components/ErrorBoundary' +import { initRendererErrorMonitoring } from './error-monitoring' import './index.css' // Create a client @@ -22,12 +24,16 @@ if (!root) { throw new Error('Root element not found') } +void initRendererErrorMonitoring() + ReactDOM.createRoot(root).render( - - - - - + + + + + + + ) diff --git a/src/windows/SettingsWindow.tsx b/src/windows/SettingsWindow.tsx index 0879d69..415d22d 100644 --- a/src/windows/SettingsWindow.tsx +++ b/src/windows/SettingsWindow.tsx @@ -2,23 +2,25 @@ import { useState, useEffect, useMemo } from 'react' import { API_KEY_PROVIDERS } from '../constants/api-key-providers' import { getShortcutsByCategory } from '../constants/keyboard-shortcuts' import { useTheme, Theme } from '../context/ThemeContext' -import { ExternalLink, Check, Eye, EyeOff, KeyRound, Keyboard, Palette, Sun, Moon, Monitor } from 'lucide-react' +import { Checkbox } from '../components/ui/checkbox' +import { ExternalLink, Check, Eye, EyeOff, KeyRound, Keyboard, Palette, Sun, Moon, Monitor, ShieldCheck } from 'lucide-react' const inputClassName = "flex-1 h-7 text-[12px] px-2.5 rounded bg-black/[0.06] dark:bg-white/[0.08] text-foreground placeholder:text-foreground/30 focus:outline-none focus:bg-black/[0.08] dark:focus:bg-white/[0.12] transition-colors border-0 font-mono" -type TabId = 'api-keys' | 'shortcuts' | 'appearance' +type TabId = 'api-keys' | 'shortcuts' | 'appearance' | 'privacy' const TABS: { id: TabId; label: string; icon: typeof KeyRound }[] = [ { id: 'api-keys', label: 'API Keys', icon: KeyRound }, { id: 'shortcuts', label: 'Shortcuts', icon: Keyboard }, { id: 'appearance', label: 'Appearance', icon: Palette }, + { id: 'privacy', label: 'Privacy', icon: ShieldCheck }, ] // Get initial tab from URL params function getInitialTab(): TabId { const params = new URLSearchParams(window.location.search) const tab = params.get('tab') - if (tab === 'shortcuts' || tab === 'api-keys' || tab === 'appearance') { + if (tab === 'shortcuts' || tab === 'api-keys' || tab === 'appearance' || tab === 'privacy') { return tab } return 'api-keys' @@ -30,6 +32,8 @@ export function SettingsWindow() { const [apiKeys, setApiKeys] = useState>({}) const [saving, setSaving] = useState(false) const [saved, setSaved] = useState(false) + const [errorReportingEnabled, setErrorReportingEnabled] = useState(false) + const [savingErrorReporting, setSavingErrorReporting] = useState(false) const [visibleKeys, setVisibleKeys] = useState>(new Set()) // Make body transparent for vibrancy effect @@ -45,7 +49,7 @@ export function SettingsWindow() { // Listen for tab switch messages from main process useEffect(() => { const unsubscribe = window.electronAPI.settings.onSwitchTab((tab) => { - if (tab === 'shortcuts' || tab === 'api-keys' || tab === 'appearance') { + if (tab === 'shortcuts' || tab === 'api-keys' || tab === 'appearance' || tab === 'privacy') { setActiveTab(tab) } }) @@ -59,9 +63,11 @@ export function SettingsWindow() { const loadSettings = async () => { try { const keys = await window.electronAPI.settings.getApiKeys() + const reportingEnabled = await window.electronAPI.settings.getErrorReportingEnabled() setApiKeys(keys) + setErrorReportingEnabled(reportingEnabled) } catch (error) { - console.error('Failed to load API keys:', error) + console.error('Failed to load settings:', error) } } @@ -102,6 +108,19 @@ export function SettingsWindow() { }) } + const handleErrorReportingChange = async (checked: boolean) => { + setErrorReportingEnabled(checked) + setSavingErrorReporting(true) + try { + await window.electronAPI.settings.setErrorReportingEnabled(checked) + } catch (error) { + setErrorReportingEnabled(!checked) + console.error('Failed to save error reporting setting:', error) + } finally { + setSavingErrorReporting(false) + } + } + // Compute theme-aware styles const isDark = resolvedTheme === 'dark' @@ -318,6 +337,35 @@ export function SettingsWindow() {

)} + + {activeTab === 'privacy' && ( + <> +
+
+ +
+
+ +

+ Database contents, API keys, connection URLs, tokens, metadata, documents, and embeddings are redacted. +

+ + )} {/* Footer - only show Save button for API Keys tab */} diff --git a/vite.config.js b/vite.config.js index 9d97b5c..7ccb3d5 100644 --- a/vite.config.js +++ b/vite.config.js @@ -34,6 +34,8 @@ export default defineConfig({ vite: { define: { 'process.env.APTABASE_APP_KEY': JSON.stringify(env.APTABASE_APP_KEY || ''), + 'process.env.SENTRY_DSN': JSON.stringify(env.SENTRY_DSN || ''), + 'process.env.VITE_SENTRY_DSN': JSON.stringify(env.VITE_SENTRY_DSN || env.SENTRY_DSN || ''), 'process.env.CHROMA_EXPLORER_RELEASE': JSON.stringify(env.CHROMA_EXPLORER_RELEASE || ''), }, build: { From 7db7529216167b98bc0021bae1b025fe10b88be8 Mon Sep 17 00:00:00 2001 From: stepandel Date: Sat, 30 May 2026 18:58:16 -0700 Subject: [PATCH 3/7] Document telemetry privacy rules --- README.md | 2 ++ docs/TELEMETRY.md | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 docs/TELEMETRY.md diff --git a/README.md b/README.md index 469cb8d..d1a1327 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,8 @@ pnpm build API keys for embedding providers can be configured in **Settings** (Cmd+,). Keys are stored encrypted at rest. +Error reporting is opt-in from **Settings > Privacy**. See `docs/TELEMETRY.md` for release configuration and privacy rules. + ## License MIT diff --git a/docs/TELEMETRY.md b/docs/TELEMETRY.md new file mode 100644 index 0000000..2df2e82 --- /dev/null +++ b/docs/TELEMETRY.md @@ -0,0 +1,52 @@ +# Telemetry + +Chroma Explorer keeps product analytics and error reporting separate. + +## Product Analytics + +`electron/analytics.ts` owns Aptabase event tracking. Analytics is disabled unless +`APTABASE_APP_KEY` is provided at build time. + +Only coarse product events should be tracked. Do not include user document +contents, collection data, embeddings, metadata values, connection URLs, API +keys, auth tokens, or provider credentials in event names or properties. + +## Error Reporting + +`electron/error-monitoring.ts` owns Sentry initialization for the Electron main +process. `src/error-monitoring.ts` owns renderer initialization. + +Error reporting is opt-in and defaults to off. The setting is stored as +`errorReportingEnabled` in `electron/settings-store.ts` and exposed through the +canonical IPC contract in `electron/ipc-contract.ts`. + +Release builds must provide a public DSN at build time: + +```bash +SENTRY_DSN=https://public-key@o0.ingest.sentry.io/project-id pnpm build:release +``` + +`vite.config.js` embeds `SENTRY_DSN` for the main process. Renderer events are +forwarded through the Electron SDK once the renderer initializes. + +## Privacy Rules + +Sentry events are scrubbed before sending: + +- URL-like values are replaced with `[redacted-url]`. +- Long token-like strings are replaced with `[redacted-token]`. +- Keys containing API key, token, secret, password, credential, authorization, + document, metadata, embedding, query, or URL are replaced with `[redacted]`. +- Event `request` and `user` fields are removed. + +Do not add manual Sentry context that contains: + +- document text; +- metadata values; +- embeddings; +- collection names when they may reveal user data; +- connection URLs; +- auth headers, tokens, credentials, or API keys. + +Prefer tags with stable categories such as window type, operation category, +platform, packaged status, and app version. From 9a8131ceb960c73a6196dc3594bfd7730a913561 Mon Sep 17 00:00:00 2001 From: stepandel Date: Sat, 30 May 2026 20:52:27 -0700 Subject: [PATCH 4/7] Wire Sentry release source maps --- electron/error-monitoring.ts | 6 +- electron/preload.ts | 1 + package.json | 1 + pnpm-lock.yaml | 450 +++++++++++++++++++++++++++++++++++ vite.config.js | 20 ++ 5 files changed, 477 insertions(+), 1 deletion(-) diff --git a/electron/error-monitoring.ts b/electron/error-monitoring.ts index 1597b3c..0b18205 100644 --- a/electron/error-monitoring.ts +++ b/electron/error-monitoring.ts @@ -43,6 +43,10 @@ function getSentryDsn(): string { return process.env.SENTRY_DSN || process.env.VITE_SENTRY_DSN || '' } +function getSentryRelease(): string { + return process.env.SENTRY_RELEASE || `chroma-explorer@${app.getVersion()}` +} + export function initErrorMonitoring(enabled: boolean): void { if (initialized || Sentry.isInitialized()) { initialized = true @@ -60,7 +64,7 @@ export function initErrorMonitoring(enabled: boolean): void { Sentry.init({ dsn, environment: app.isPackaged ? 'production' : 'development', - release: `chroma-explorer@${app.getVersion()}`, + release: getSentryRelease(), sendDefaultPii: false, tracesSampleRate: 0, beforeBreadcrumb(breadcrumb) { diff --git a/electron/preload.ts b/electron/preload.ts index 95539be..0459af0 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -1,3 +1,4 @@ +import '@sentry/electron/preload' import { contextBridge, ipcRenderer } from 'electron' import type { ConnectionProfile, diff --git a/package.json b/package.json index 3877d20..26c7d36 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "license": "MIT", "devDependencies": { "@playwright/test": "^1.60.0", + "@sentry/vite-plugin": "^5.3.0", "@tailwindcss/postcss": "^4.1.18", "@types/node": "^25.0.3", "@types/react": "^19.2.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d5e038e..eeb9cd2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -135,6 +135,9 @@ importers: '@playwright/test': specifier: ^1.60.0 version: 1.60.0 + '@sentry/vite-plugin': + specifier: ^5.3.0 + version: 5.3.0(encoding@0.1.13)(rollup@4.54.0) '@tailwindcss/postcss': specifier: ^4.1.18 version: 4.1.18 @@ -324,6 +327,73 @@ packages: resolution: {integrity: sha512-oLvsaPMTBejkkmHhjf09xTgk71mOqyr/409NKhRIL08If7AhVfUsJhVsx386uJaqNd42v9kWamQ9lFbkoC2dYw==} engines: {node: '>=18.0.0'} + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.7': + resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.7': + resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + engines: {node: '>=6.9.0'} + '@balena/dockerignore@1.0.2': resolution: {integrity: sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==} @@ -705,89 +775,105 @@ packages: resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.4': resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.4': resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-riscv64@1.2.4': resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.4': resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.4': resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.2.4': resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.4': resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.34.5': resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.34.5': resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-ppc64@0.34.5': resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-linux-riscv64@0.34.5': resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.34.5': resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.34.5': resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.5': resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.34.5': resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.34.5': resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} @@ -1476,56 +1562,67 @@ packages: resolution: {integrity: sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.54.0': resolution: {integrity: sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.54.0': resolution: {integrity: sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.54.0': resolution: {integrity: sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.54.0': resolution: {integrity: sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.54.0': resolution: {integrity: sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.54.0': resolution: {integrity: sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.54.0': resolution: {integrity: sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.54.0': resolution: {integrity: sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.54.0': resolution: {integrity: sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.54.0': resolution: {integrity: sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openharmony-arm64@4.54.0': resolution: {integrity: sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==} @@ -1568,10 +1665,70 @@ packages: resolution: {integrity: sha512-51FYNfnvVLAWw1rrEWPFfwHuMRb9mkVCFGA4J9/un7SpeGBsQDziGB0Di4fsCxI7+EdSBpfLHPF0csKtCCw0oQ==} engines: {node: '>=18'} + '@sentry/babel-plugin-component-annotate@5.3.0': + resolution: {integrity: sha512-p4q8gn8wcFqZGP/s2MnJCAAd8fTikaU6A0mM97RDHQgStcrYiaS0Sc5zUNfb1V+UOLPuvdEdL6MwyxfzjYJQTA==} + engines: {node: '>= 18'} + '@sentry/browser@10.50.0': resolution: {integrity: sha512-1f6rAvET6myiTaSeYqvaaBwvq1LfxqWjAPIoAW/NVC9bPMkeEcuvgDajHrnZMrBeWoJ81NMyoLkyX+iOc7MoFA==} 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/core@10.50.0': resolution: {integrity: sha512-J4A+vzUO3adl0TkFCjaN1+4miamrjHiEIYuLHiuu1lmAjq5WIVw32ObvAh4yMwNtxyaEMosTrrh5M6f12XSJFg==} engines: {node: '>=18'} @@ -1621,6 +1778,19 @@ packages: '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 '@opentelemetry/semantic-conventions': ^1.39.0 + '@sentry/rollup-plugin@5.3.0': + resolution: {integrity: sha512-hgPGPYdQJ/G1cGYOxAb7d4z3V+/k/E5/P/5TFPEEBLuIbFFk+JG0CISUDJdzXJjO382Lb99PBJuXGbueBmO79w==} + engines: {node: '>= 18'} + peerDependencies: + rollup: '>=3.2.0' + peerDependenciesMeta: + rollup: + optional: true + + '@sentry/vite-plugin@5.3.0': + resolution: {integrity: sha512-qcoSzo4n2MulVQ70UUPLq6dTleb2a2HwL2wuwvAgWhPChrYTuk6A6mDg6aQb9fairPAwFPiU9PzOANpoDJcz1A==} + engines: {node: '>= 18'} + '@sindresorhus/is@4.6.0': resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} @@ -1846,24 +2016,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.1.18': resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.1.18': resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.1.18': resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.1.18': resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} @@ -2390,12 +2564,14 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] chromadb-js-bindings-linux-x64-gnu@1.2.0: resolution: {integrity: sha512-0E65eSuWICoD2jhQ+ZLi5Me08+VxICG0f5lZ4ceiMPXTemc60QmkmhtKQVK5lEhqRWu2CLSYXqlusnD5qEoa1Q==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] chromadb-js-bindings-win32-x64-msvc@1.2.0: resolution: {integrity: sha512-1gmVdgw/spSSYvbc7Ogms9FXf+Zad41Cp7Enqfvrp7m9qQ+Nz4NqZINfOEX5OVzPHEj6cfXA11NdGeNHTPPHOg==} @@ -2790,6 +2966,10 @@ packages: filelist@1.0.4: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + flatbuffers@25.9.23: resolution: {integrity: sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ==} @@ -2882,6 +3062,10 @@ packages: resolution: {integrity: sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==} engines: {node: '>=14'} + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -2910,6 +3094,10 @@ packages: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} hasBin: true + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported @@ -3098,10 +3286,18 @@ packages: js-base64@3.7.2: resolution: {integrity: sha512-NnRs6dsyqUXejqk/yv2aiXlAvOs56sLkX6nUdeaNezI5LFFLlsZjOThmwnrcwh5ZZRwZlCMnVAY3CvhIhoVEKQ==} + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-yaml@4.1.1: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + json-bigint@1.0.0: resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} @@ -3182,24 +3378,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==} @@ -3217,6 +3417,10 @@ packages: resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} engines: {node: '>= 12.0.0'} + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + lodash.camelcase@4.3.0: resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} @@ -3247,6 +3451,13 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.5.1: + resolution: {integrity: sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==} + engines: {node: 20 || >=22} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} @@ -3361,6 +3572,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'} + minizlib@2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} engines: {node: '>= 8'} @@ -3508,6 +3723,10 @@ packages: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + p-map@4.0.0: resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} engines: {node: '>=10'} @@ -3519,6 +3738,10 @@ packages: resolution: {integrity: sha512-Y6FOc3Oi2AxY4TzJPz7fhICCR8tQNL3p+2xGQoUAMbmlJBR7+JJmMrwuyMjIpDiM7G8Wj/8oqOH4UDUmu4I5ZA==} engines: {node: '>=7.6'} + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -3531,6 +3754,10 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -4331,6 +4558,9 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} @@ -4831,6 +5061,106 @@ snapshots: '@aws/lambda-invoke-store@0.2.3': {} + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.7': {} + + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.7': + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/parser@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/traverse@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.7': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@balena/dockerignore@1.0.2': {} '@chroma-core/ai-embeddings-common@0.1.9': @@ -6058,6 +6388,8 @@ snapshots: '@sentry-internal/browser-utils': 10.50.0 '@sentry/core': 10.50.0 + '@sentry/babel-plugin-component-annotate@5.3.0': {} + '@sentry/browser@10.50.0': dependencies: '@sentry-internal/browser-utils': 10.50.0 @@ -6066,6 +6398,63 @@ snapshots: '@sentry-internal/replay-canvas': 10.50.0 '@sentry/core': 10.50.0 + '@sentry/bundler-plugin-core@5.3.0(encoding@0.1.13)': + dependencies: + '@babel/core': 7.29.7 + '@sentry/babel-plugin-component-annotate': 5.3.0 + '@sentry/cli': 2.58.6(encoding@0.1.13) + 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.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(encoding@0.1.13)': + dependencies: + https-proxy-agent: 5.0.1 + node-fetch: 2.7.0(encoding@0.1.13) + 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/core@10.50.0': {} '@sentry/electron@7.13.0': @@ -6134,6 +6523,25 @@ snapshots: '@opentelemetry/semantic-conventions': 1.41.1 '@sentry/core': 10.50.0 + '@sentry/rollup-plugin@5.3.0(encoding@0.1.13)(rollup@4.54.0)': + dependencies: + '@sentry/bundler-plugin-core': 5.3.0(encoding@0.1.13) + magic-string: 0.30.21 + optionalDependencies: + rollup: 4.54.0 + transitivePeerDependencies: + - encoding + - supports-color + + '@sentry/vite-plugin@5.3.0(encoding@0.1.13)(rollup@4.54.0)': + dependencies: + '@sentry/bundler-plugin-core': 5.3.0(encoding@0.1.13) + '@sentry/rollup-plugin': 5.3.0(encoding@0.1.13)(rollup@4.54.0) + transitivePeerDependencies: + - encoding + - rollup + - supports-color + '@sindresorhus/is@4.6.0': {} '@smithy/abort-controller@4.2.7': @@ -7575,6 +7983,11 @@ snapshots: dependencies: minimatch: 5.1.6 + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + flatbuffers@25.9.23: {} follow-redirects@1.15.11: {} @@ -7674,6 +8087,8 @@ snapshots: - encoding - supports-color + gensync@1.0.0-beta.2: {} + get-caller-file@2.0.5: {} get-intrinsic@1.3.0: @@ -7711,6 +8126,12 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 + glob@13.0.6: + dependencies: + minimatch: 10.2.5 + minipass: 7.1.3 + path-scurry: 2.0.2 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -7925,10 +8346,14 @@ snapshots: js-base64@3.7.2: {} + js-tokens@4.0.0: {} + js-yaml@4.1.1: dependencies: argparse: 2.0.1 + jsesc@3.1.0: {} + json-bigint@1.0.0: dependencies: bignumber.js: 9.3.1 @@ -8025,6 +8450,10 @@ snapshots: lightningcss-win32-arm64-msvc: 1.30.2 lightningcss-win32-x64-msvc: 1.30.2 + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + lodash.camelcase@4.3.0: {} lodash.clonedeep@4.5.0: {} @@ -8046,6 +8475,12 @@ snapshots: lru-cache@10.4.3: {} + lru-cache@11.5.1: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + lru-cache@6.0.0: dependencies: yallist: 4.0.0 @@ -8163,6 +8598,8 @@ snapshots: minipass@7.1.2: {} + minipass@7.1.3: {} + minizlib@2.1.2: dependencies: minipass: 3.3.6 @@ -8296,6 +8733,10 @@ snapshots: dependencies: yocto-queue: 0.1.0 + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + p-map@4.0.0: dependencies: aggregate-error: 3.1.0 @@ -8317,6 +8758,8 @@ snapshots: - bufferutil - utf-8-validate + path-exists@4.0.0: {} + path-is-absolute@1.0.1: {} path-key@3.1.1: {} @@ -8326,6 +8769,11 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 + path-scurry@2.0.2: + dependencies: + lru-cache: 11.5.1 + minipass: 7.1.3 + pathe@2.0.3: {} pe-library@0.4.1: {} @@ -9176,6 +9624,8 @@ snapshots: y18n@5.0.8: {} + yallist@3.1.1: {} + yallist@4.0.0: {} yallist@5.0.0: {} diff --git a/vite.config.js b/vite.config.js index 7ccb3d5..453758f 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,5 +1,6 @@ import { defineConfig, loadEnv } from 'vite' import electron from 'vite-plugin-electron/simple' +import { sentryVitePlugin } from '@sentry/vite-plugin' import path from 'path' import { fileURLToPath } from 'url' @@ -7,6 +8,9 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)) // Load .env file for build-time environment variables const env = loadEnv('', process.cwd(), '') +const sentryRelease = env.SENTRY_RELEASE || `chroma-explorer@${process.env.npm_package_version || '0.0.0'}` +const shouldBuildSourceMaps = Boolean(env.SENTRY_DSN || env.VITE_SENTRY_DSN) +const shouldUploadSourceMaps = Boolean(env.SENTRY_AUTH_TOKEN && env.SENTRY_ORG && env.SENTRY_PROJECT) export default defineConfig({ @@ -19,6 +23,7 @@ export default defineConfig({ exclude: ['chromadb'] }, build: { + sourcemap: shouldBuildSourceMaps ? 'hidden' : false, commonjsOptions: { include: [/chromadb/, /node_modules/] } @@ -36,9 +41,11 @@ export default defineConfig({ 'process.env.APTABASE_APP_KEY': JSON.stringify(env.APTABASE_APP_KEY || ''), 'process.env.SENTRY_DSN': JSON.stringify(env.SENTRY_DSN || ''), 'process.env.VITE_SENTRY_DSN': JSON.stringify(env.VITE_SENTRY_DSN || env.SENTRY_DSN || ''), + 'process.env.SENTRY_RELEASE': JSON.stringify(sentryRelease), 'process.env.CHROMA_EXPLORER_RELEASE': JSON.stringify(env.CHROMA_EXPLORER_RELEASE || ''), }, build: { + sourcemap: shouldBuildSourceMaps ? 'hidden' : false, rollupOptions: { external: [ '@chroma-core/sentence-transformer', @@ -54,5 +61,18 @@ export default defineConfig({ }, renderer: {}, }), + shouldUploadSourceMaps && sentryVitePlugin({ + authToken: env.SENTRY_AUTH_TOKEN, + org: env.SENTRY_ORG, + project: env.SENTRY_PROJECT, + release: { + name: sentryRelease, + }, + sourcemaps: { + assets: ['./dist/**/*', './dist-electron/**/*'], + ignore: ['**/node_modules/**'], + filesToDeleteAfterUpload: ['./dist/**/*.map', './dist-electron/**/*.map'], + }, + }), ], }) From 1a72bd4597664dbef3057e13dde6d52ab6f54fc4 Mon Sep 17 00:00:00 2001 From: stepandel Date: Sat, 30 May 2026 20:54:10 -0700 Subject: [PATCH 5/7] Harden Sentry telemetry wiring --- .github/workflows/release.yml | 31 ++++++++++ docs/TELEMETRY.md | 35 ++++++++++- electron/error-monitoring.ts | 36 ++++++++--- electron/main.ts | 101 ++++++++++++------------------- src/components/ErrorBoundary.tsx | 2 +- src/error-monitoring.ts | 2 +- src/windows/SettingsWindow.tsx | 8 ++- 7 files changed, 139 insertions(+), 76 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..99f762b --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,31 @@ +name: Release + +on: + workflow_dispatch: + +jobs: + mac: + runs-on: macos-latest + permissions: + contents: write + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SENTRY_DSN: ${{ secrets.SENTRY_DSN }} + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_ORG: ${{ secrets.SENTRY_ORG }} + SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }} + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: 10.29.2 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm check + - run: pnpm build:release --publish always diff --git a/docs/TELEMETRY.md b/docs/TELEMETRY.md index 2df2e82..4fb3d95 100644 --- a/docs/TELEMETRY.md +++ b/docs/TELEMETRY.md @@ -26,8 +26,39 @@ Release builds must provide a public DSN at build time: SENTRY_DSN=https://public-key@o0.ingest.sentry.io/project-id pnpm build:release ``` -`vite.config.js` embeds `SENTRY_DSN` for the main process. Renderer events are -forwarded through the Electron SDK once the renderer initializes. +`vite.config.js` embeds `SENTRY_DSN` for the main process and renderer bridge. +Renderer events are forwarded through the Electron SDK preload integration once +the renderer initializes. + +Sentry releases use `chroma-explorer@` by default. Set +`SENTRY_RELEASE` only when the Sentry upload release and runtime +`Sentry.init({ release })` value need to be overridden together. + +Readable production stack traces require source map upload. Release builds +generate hidden source maps when a DSN is present. They upload maps only when all +of these build-time values are present: + +```bash +SENTRY_AUTH_TOKEN=sntrys_... +SENTRY_ORG=your-org-slug +SENTRY_PROJECT=your-project-slug +``` + +The manual GitHub Actions release workflow (`.github/workflows/release.yml`) +passes those secrets into `pnpm build:release --publish always`. Configure the +same repository secrets there, along with the existing Apple notarization +secrets, before publishing production artifacts. + +## Production Validation + +Before shipping a release: + +1. Run the manual `Release` workflow from GitHub Actions. +2. Install the produced app artifact. +3. Enable **Settings > Privacy > Error reporting**. +4. Trigger a known renderer and main-process failure in a test build. +5. Confirm Sentry receives events under the expected + `chroma-explorer@` release with readable stack traces. ## Privacy Rules diff --git a/electron/error-monitoring.ts b/electron/error-monitoring.ts index 0b18205..56bf0f5 100644 --- a/electron/error-monitoring.ts +++ b/electron/error-monitoring.ts @@ -5,34 +5,56 @@ const SENSITIVE_KEY_PATTERN = /(api[-_]?key|token|secret|password|credential|aut const URL_PATTERN = /\bhttps?:\/\/[^\s"'<>]+/gi const LONG_TOKEN_PATTERN = /\b[A-Za-z0-9_-]{32,}\b/g const MAX_STRING_LENGTH = 500 +const MAX_DEBUG_STRING_LENGTH = 10_000 +const MAX_SANITIZE_DEPTH = 12 +const DEBUG_STRING_KEY_PATTERN = /^(message|stack|componentStack|exception|value|type)$/i let initialized = false -function redactString(value: string): string { - return value +function redactString(value: string, maxLength = MAX_STRING_LENGTH): string { + const redacted = value .replace(URL_PATTERN, '[redacted-url]') .replace(LONG_TOKEN_PATTERN, '[redacted-token]') - .slice(0, MAX_STRING_LENGTH) + + return redacted.length > maxLength ? redacted.slice(0, maxLength) : redacted } -function sanitizeValue(value: unknown, key = ''): unknown { +function sanitizeValue( + value: unknown, + key = '', + depth = 0, + seen = new WeakSet() +): unknown { + if (depth >= MAX_SANITIZE_DEPTH) { + return '[max-depth-exceeded]' + } + if (SENSITIVE_KEY_PATTERN.test(key)) { return '[redacted]' } if (typeof value === 'string') { - return redactString(value) + const maxLength = DEBUG_STRING_KEY_PATTERN.test(key) ? MAX_DEBUG_STRING_LENGTH : MAX_STRING_LENGTH + return redactString(value, maxLength) } if (Array.isArray(value)) { - return value.slice(0, 10).map((item) => sanitizeValue(item)) + if (seen.has(value)) { + return '[circular]' + } + seen.add(value) + return value.slice(0, 10).map((item) => sanitizeValue(item, '', depth + 1, seen)) } if (value && typeof value === 'object') { + if (seen.has(value)) { + return '[circular]' + } + seen.add(value) const entries = Object.entries(value as Record).slice(0, 30) return Object.fromEntries(entries.map(([entryKey, entryValue]) => [ entryKey, - sanitizeValue(entryValue, entryKey), + sanitizeValue(entryValue, entryKey, depth + 1, seen), ])) } diff --git a/electron/main.ts b/electron/main.ts index fab8f1c..fb0bd52 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -36,7 +36,7 @@ import { openValidatedExternalUrl } from './external-url' import { initAutoUpdater, checkForUpdates } from './auto-updater' import { initAnalytics, track } from './analytics' import { configureTransformersCache } from './transformers-cache' -import { initErrorMonitoring, setErrorMonitoringEnabled } from './error-monitoring' +import { captureMainError, initErrorMonitoring, setErrorMonitoringEnabled } from './error-monitoring' // Inject stored API keys into process.env at startup configureTransformersCache() @@ -53,6 +53,12 @@ process.env.VITE_PUBLIC = app.isPackaged ? process.env.DIST : path.join(process.env.DIST, '../public') +function reportIpcError(error: unknown, operation: string, fallbackMessage: string) { + captureMainError(error, { operation }) + const message = error instanceof Error ? error.message : fallbackMessage + return { success: false, error: message } +} + // Set up IPC handlers ipcMain.handle('chromadb:connect', async (_event, rawProfileId: unknown, rawProfile: unknown) => { try { @@ -62,8 +68,7 @@ ipcMain.handle('chromadb:connect', async (_event, rawProfileId: unknown, rawProf track('chroma_connected') return { success: true } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to connect to ChromaDB' - return { success: false, error: message } + return reportIpcError(error, 'chromadb.connect', 'Failed to connect to ChromaDB') } }) @@ -77,8 +82,7 @@ ipcMain.handle('chromadb:listCollections', async (_event, rawProfileId: unknown) const collections = await service.listCollections() return { success: true, data: collections } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to fetch collections' - return { success: false, error: message } + return reportIpcError(error, 'chromadb.listCollections', 'Failed to fetch collections') } }) @@ -93,8 +97,7 @@ ipcMain.handle('chromadb:getDocuments', async (_event, rawProfileId: unknown, ra const documents = await service.getCollectionDocuments(collectionName) return { success: true, data: documents } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to fetch documents' - return { success: false, error: message } + return reportIpcError(error, 'chromadb.getDocuments', 'Failed to fetch documents') } }) @@ -111,8 +114,7 @@ ipcMain.handle('chromadb:searchDocuments', async (_event, rawProfileId: unknown, const documents = await service.searchDocuments(params, embeddingOverride) return { success: true, data: documents } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to search documents' - return { success: false, error: message } + return reportIpcError(error, 'chromadb.searchDocuments', 'Failed to search documents') } }) @@ -130,8 +132,7 @@ ipcMain.handle('chromadb:updateDocument', async (_event, rawProfileId: unknown, track('document_updated') return { success: true } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to update document' - return { success: false, error: message } + return reportIpcError(error, 'chromadb.updateDocument', 'Failed to update document') } }) @@ -149,8 +150,7 @@ ipcMain.handle('chromadb:createDocument', async (_event, rawProfileId: unknown, track('document_created') return { success: true } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to create document' - return { success: false, error: message } + return reportIpcError(error, 'chromadb.createDocument', 'Failed to create document') } }) @@ -168,8 +168,7 @@ ipcMain.handle('chromadb:deleteDocuments', async (_event, rawProfileId: unknown, }) return { success: true } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to delete documents' - return { success: false, error: message } + return reportIpcError(error, 'chromadb.deleteDocuments', 'Failed to delete documents') } }) @@ -189,8 +188,7 @@ ipcMain.handle('chromadb:createDocumentsBatch', async (_event, rawProfileId: unk }) return { success: true, data: result } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to create documents' - return { success: false, error: message } + return reportIpcError(error, 'chromadb.createDocumentsBatch', 'Failed to create documents') } }) @@ -209,8 +207,7 @@ ipcMain.handle('chromadb:createCollection', async (_event, rawProfileId: unknown }) return { success: true, data: collection } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to create collection' - return { success: false, error: message } + return reportIpcError(error, 'chromadb.createCollection', 'Failed to create collection') } }) @@ -226,8 +223,7 @@ ipcMain.handle('chromadb:deleteCollection', async (_event, rawProfileId: unknown track('collection_deleted') return { success: true } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to delete collection' - return { success: false, error: message } + return reportIpcError(error, 'chromadb.deleteCollection', 'Failed to delete collection') } }) @@ -267,8 +263,7 @@ ipcMain.handle('chromadb:copyCollection', async (event, rawProfileId: unknown, r return { success: result.success, data: result, error: result.error } } catch (error) { activeCopyOperations.delete(profileId) - const message = error instanceof Error ? error.message : 'Failed to copy collection' - return { success: false, error: message } + return reportIpcError(error, 'chromadb.copyCollection', 'Failed to copy collection') } }) @@ -393,8 +388,7 @@ ipcMain.handle('profiles:getAll', async () => { const profiles = connectionStore.getProfiles() return { success: true, data: profiles } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to fetch profiles' - return { success: false, error: message } + return reportIpcError(error, 'profiles.getAll', 'Failed to fetch profiles') } }) @@ -404,8 +398,7 @@ ipcMain.handle('profiles:save', async (_event, rawProfile: unknown) => { connectionStore.saveProfile(profile) return { success: true } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to save profile' - return { success: false, error: message } + return reportIpcError(error, 'profiles.save', 'Failed to save profile') } }) @@ -415,8 +408,7 @@ ipcMain.handle('profiles:delete', async (_event, rawId: unknown) => { connectionStore.deleteProfile(id) return { success: true } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to delete profile' - return { success: false, error: message } + return reportIpcError(error, 'profiles.delete', 'Failed to delete profile') } }) @@ -425,8 +417,7 @@ ipcMain.handle('profiles:getLastActive', async () => { const id = connectionStore.getLastActiveProfileId() return { success: true, data: id } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to fetch last active profile' - return { success: false, error: message } + return reportIpcError(error, 'profiles.getLastActive', 'Failed to fetch last active profile') } }) @@ -436,8 +427,7 @@ ipcMain.handle('profiles:setLastActive', async (_event, rawId: unknown) => { connectionStore.setLastActiveProfileId(id) return { success: true } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to set last active profile' - return { success: false, error: message } + return reportIpcError(error, 'profiles.setLastActive', 'Failed to set last active profile') } }) @@ -448,8 +438,7 @@ ipcMain.handle('profiles:getEmbeddingOverride', async (_event, rawProfileId: unk const override = connectionStore.getEmbeddingOverride(profileId, collectionName) return { success: true, data: override } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to get embedding override' - return { success: false, error: message } + return reportIpcError(error, 'profiles.getEmbeddingOverride', 'Failed to get embedding override') } }) @@ -461,8 +450,7 @@ ipcMain.handle('profiles:setEmbeddingOverride', async (_event, rawProfileId: unk connectionStore.setEmbeddingOverride(profileId, collectionName, override) return { success: true } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to set embedding override' - return { success: false, error: message } + return reportIpcError(error, 'profiles.setEmbeddingOverride', 'Failed to set embedding override') } }) @@ -473,8 +461,7 @@ ipcMain.handle('profiles:clearEmbeddingOverride', async (_event, rawProfileId: u connectionStore.clearEmbeddingOverride(profileId, collectionName) return { success: true } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to clear embedding override' - return { success: false, error: message } + return reportIpcError(error, 'profiles.clearEmbeddingOverride', 'Failed to clear embedding override') } }) @@ -485,8 +472,7 @@ ipcMain.handle('window:create-connection', async (_event, rawProfile: unknown) = const { window: win, windowId } = windowManager.createConnectionWindow(profile) return { success: true, data: { windowId } } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to create connection window' - return { success: false, error: message } + return reportIpcError(error, 'window.createConnection', 'Failed to create connection window') } }) @@ -526,8 +512,7 @@ ipcMain.handle('window:get-info', async (event) => { return { success: false, error: 'Window type unknown' } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to get window info' - return { success: false, error: message } + return reportIpcError(error, 'window.getInfo', 'Failed to get window info') } }) @@ -543,8 +528,7 @@ ipcMain.handle('window:close-current', async (event) => { win.close() return { success: true } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to close window' - return { success: false, error: message } + return reportIpcError(error, 'window.closeCurrent', 'Failed to close window') } }) @@ -567,8 +551,7 @@ ipcMain.handle('window:get-profile', async (_event, rawProfileId: unknown) => { return { success: true, data: profile } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to get profile' - return { success: false, error: message } + return reportIpcError(error, 'window.getProfile', 'Failed to get profile') } }) @@ -578,8 +561,7 @@ ipcMain.handle('settings:getApiKeys', async () => { const apiKeys = settingsStore.getApiKeys() return { success: true, data: apiKeys } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to get API keys' - return { success: false, error: message } + return reportIpcError(error, 'settings.getApiKeys', 'Failed to get API keys') } }) @@ -589,8 +571,7 @@ ipcMain.handle('settings:setApiKeys', async (_event, rawApiKeys: unknown) => { settingsStore.setApiKeys(apiKeys) return { success: true } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to save API keys' - return { success: false, error: message } + return reportIpcError(error, 'settings.setApiKeys', 'Failed to save API keys') } }) @@ -599,8 +580,7 @@ ipcMain.handle('settings:getTheme', async () => { const theme = settingsStore.getTheme() return { success: true, data: theme } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to get theme' - return { success: false, error: message } + return reportIpcError(error, 'settings.getTheme', 'Failed to get theme') } }) @@ -619,8 +599,7 @@ ipcMain.handle('settings:setTheme', async (event, rawTheme: unknown) => { updateThemeMenu() return { success: true } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to set theme' - return { success: false, error: message } + return reportIpcError(error, 'settings.setTheme', 'Failed to set theme') } }) @@ -628,8 +607,7 @@ ipcMain.handle('settings:getErrorReportingEnabled', async () => { try { return { success: true, data: settingsStore.isErrorReportingEnabled() } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to get error reporting setting' - return { success: false, error: message } + return reportIpcError(error, 'settings.getErrorReportingEnabled', 'Failed to get error reporting setting') } }) @@ -648,8 +626,7 @@ ipcMain.handle('settings:setErrorReportingEnabled', async (event, rawEnabled: un return { success: true } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to set error reporting setting' - return { success: false, error: message } + return reportIpcError(error, 'settings.setErrorReportingEnabled', 'Failed to set error reporting setting') } }) @@ -658,8 +635,7 @@ ipcMain.handle('settings:openWindow', async () => { windowManager.createSettingsWindow() return { success: true } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to open settings' - return { success: false, error: message } + return reportIpcError(error, 'settings.openWindow', 'Failed to open settings') } }) @@ -669,8 +645,7 @@ ipcMain.handle('shell:openExternal', async (_event, rawUrl: unknown) => { await openValidatedExternalUrl(rawUrl) return { success: true } } catch (error) { - const message = error instanceof Error ? error.message : 'Failed to open URL' - return { success: false, error: message } + return reportIpcError(error, 'shell.openExternal', 'Failed to open URL') } }) diff --git a/src/components/ErrorBoundary.tsx b/src/components/ErrorBoundary.tsx index fc47e35..51a893d 100644 --- a/src/components/ErrorBoundary.tsx +++ b/src/components/ErrorBoundary.tsx @@ -16,7 +16,7 @@ export class ErrorBoundary extends React.Component { if (context) { - scope.setTags(context) + scope.setContext('renderer', context) } Sentry.captureException(error) }) diff --git a/src/windows/SettingsWindow.tsx b/src/windows/SettingsWindow.tsx index 415d22d..b863a95 100644 --- a/src/windows/SettingsWindow.tsx +++ b/src/windows/SettingsWindow.tsx @@ -16,11 +16,15 @@ const TABS: { id: TabId; label: string; icon: typeof KeyRound }[] = [ { id: 'privacy', label: 'Privacy', icon: ShieldCheck }, ] +function isTabId(value: string | null): value is TabId { + return TABS.some(tab => tab.id === value) +} + // Get initial tab from URL params function getInitialTab(): TabId { const params = new URLSearchParams(window.location.search) const tab = params.get('tab') - if (tab === 'shortcuts' || tab === 'api-keys' || tab === 'appearance' || tab === 'privacy') { + if (isTabId(tab)) { return tab } return 'api-keys' @@ -49,7 +53,7 @@ export function SettingsWindow() { // Listen for tab switch messages from main process useEffect(() => { const unsubscribe = window.electronAPI.settings.onSwitchTab((tab) => { - if (tab === 'shortcuts' || tab === 'api-keys' || tab === 'appearance' || tab === 'privacy') { + if (isTabId(tab)) { setActiveTab(tab) } }) From d09b321a6b940c4f107dcf74797b845019a57232 Mon Sep 17 00:00:00 2001 From: stepandel Date: Sat, 30 May 2026 21:03:28 -0700 Subject: [PATCH 6/7] Make Sentry error reporting default on --- README.md | 2 +- docs/TELEMETRY.md | 9 +++++---- electron/settings-store.ts | 6 +++--- src/windows/SettingsWindow.tsx | 6 +++--- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index e852ed1..e9e8b49 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ pnpm build API keys for embedding providers can be configured in **Settings** (Cmd+,). Keys are stored encrypted at rest. -Error reporting is opt-in from **Settings > Privacy**. See `docs/TELEMETRY.md` for release configuration and privacy rules. +Error reporting is enabled by default and can be disabled from **Settings > Privacy**. See `docs/TELEMETRY.md` for release configuration and privacy rules. ### Feedback Collection diff --git a/docs/TELEMETRY.md b/docs/TELEMETRY.md index 4fb3d95..52e9223 100644 --- a/docs/TELEMETRY.md +++ b/docs/TELEMETRY.md @@ -16,9 +16,10 @@ keys, auth tokens, or provider credentials in event names or properties. `electron/error-monitoring.ts` owns Sentry initialization for the Electron main process. `src/error-monitoring.ts` owns renderer initialization. -Error reporting is opt-in and defaults to off. The setting is stored as -`errorReportingEnabled` in `electron/settings-store.ts` and exposed through the -canonical IPC contract in `electron/ipc-contract.ts`. +Error reporting is enabled by default and can be disabled from +**Settings > Privacy**. The setting is stored as `errorReportingEnabled` in +`electron/settings-store.ts` and exposed through the canonical IPC contract in +`electron/ipc-contract.ts`. Release builds must provide a public DSN at build time: @@ -55,7 +56,7 @@ Before shipping a release: 1. Run the manual `Release` workflow from GitHub Actions. 2. Install the produced app artifact. -3. Enable **Settings > Privacy > Error reporting**. +3. Confirm **Settings > Privacy > Error reporting** is enabled. 4. Trigger a known renderer and main-process failure in a test build. 5. Confirm Sentry receives events under the expected `chroma-explorer@` release with readable stack traces. diff --git a/electron/settings-store.ts b/electron/settings-store.ts index c5b1322..f5a3ce1 100644 --- a/electron/settings-store.ts +++ b/electron/settings-store.ts @@ -76,7 +76,7 @@ function getStore(): Store { defaults: { apiKeys: {}, theme: 'system', - errorReportingEnabled: false, + errorReportingEnabled: true, }, encryptionKey: getEncryptionKey(), clearInvalidConfig: true, @@ -102,7 +102,7 @@ function getStore(): Store { defaults: { apiKeys: {}, theme: 'system', - errorReportingEnabled: false, + errorReportingEnabled: true, }, encryptionKey: getEncryptionKey(), clearInvalidConfig: true, @@ -152,7 +152,7 @@ export class SettingsStore { } isErrorReportingEnabled(): boolean { - return getStore().get('errorReportingEnabled', false) + return getStore().get('errorReportingEnabled', true) } setErrorReportingEnabled(enabled: boolean): void { diff --git a/src/windows/SettingsWindow.tsx b/src/windows/SettingsWindow.tsx index 0338422..8bbbca6 100644 --- a/src/windows/SettingsWindow.tsx +++ b/src/windows/SettingsWindow.tsx @@ -36,7 +36,7 @@ export function SettingsWindow() { const [apiKeys, setApiKeys] = useState>({}) const [saving, setSaving] = useState(false) const [saved, setSaved] = useState(false) - const [errorReportingEnabled, setErrorReportingEnabled] = useState(false) + const [errorReportingEnabled, setErrorReportingEnabled] = useState(true) const [savingErrorReporting, setSavingErrorReporting] = useState(false) const [visibleKeys, setVisibleKeys] = useState>(new Set()) @@ -362,7 +362,7 @@ export function SettingsWindow() { Error reporting
- Send crash reports and sanitized error details. + Send sanitized crash reports and error details.
@@ -370,7 +370,7 @@ export function SettingsWindow() {

- Database contents, API keys, connection URLs, tokens, metadata, documents, and embeddings are redacted. + Enabled by default. Database contents, API keys, connection URLs, tokens, metadata, documents, and embeddings are redacted.

)} From 77037ee7d54c78fba7477a2fff100e57589d3f3d Mon Sep 17 00:00:00 2001 From: stepandel Date: Sat, 30 May 2026 21:06:40 -0700 Subject: [PATCH 7/7] Keep Sentry DSN environment configured --- docs/TELEMETRY.md | 7 +++++++ src/error-monitoring.ts | 9 +++++++-- src/vite-env.d.ts | 2 ++ vite.config.js | 14 +++++++++++--- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/docs/TELEMETRY.md b/docs/TELEMETRY.md index 52e9223..8494cc7 100644 --- a/docs/TELEMETRY.md +++ b/docs/TELEMETRY.md @@ -50,6 +50,13 @@ passes those secrets into `pnpm build:release --publish always`. Configure the same repository secrets there, along with the existing Apple notarization secrets, before publishing production artifacts. +If you do not have source-map upload credentials yet, run Sentry's wizard and use +the auth token it configures: + +```bash +npx @sentry/wizard@latest -i sourcemaps --saas --org arsent --project electron +``` + ## Production Validation Before shipping a release: diff --git a/src/error-monitoring.ts b/src/error-monitoring.ts index 7985b36..28550d1 100644 --- a/src/error-monitoring.ts +++ b/src/error-monitoring.ts @@ -16,8 +16,13 @@ export async function initRendererErrorMonitoring(): Promise { } export function setRendererErrorMonitoringEnabled(enabled: boolean): void { - if (enabled && !initialized && !Sentry.isInitialized()) { - Sentry.init() + const dsn = import.meta.env.VITE_SENTRY_DSN + + if (enabled && dsn && !initialized && !Sentry.isInitialized()) { + Sentry.init({ + dsn, + release: import.meta.env.VITE_SENTRY_RELEASE, + }) initialized = true return } diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 2c6e9d8..e76b8df 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -2,6 +2,8 @@ interface ImportMetaEnv { readonly VITE_FORMINIT_FORM_ID?: string + readonly VITE_SENTRY_DSN?: string + readonly VITE_SENTRY_RELEASE?: string } interface ImportMeta { diff --git a/vite.config.js b/vite.config.js index 453758f..53a2521 100644 --- a/vite.config.js +++ b/vite.config.js @@ -8,6 +8,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)) // Load .env file for build-time environment variables const env = loadEnv('', process.cwd(), '') +const sentryDsn = env.SENTRY_DSN || env.VITE_SENTRY_DSN || '' const sentryRelease = env.SENTRY_RELEASE || `chroma-explorer@${process.env.npm_package_version || '0.0.0'}` const shouldBuildSourceMaps = Boolean(env.SENTRY_DSN || env.VITE_SENTRY_DSN) const shouldUploadSourceMaps = Boolean(env.SENTRY_AUTH_TOKEN && env.SENTRY_ORG && env.SENTRY_PROJECT) @@ -39,8 +40,8 @@ export default defineConfig({ vite: { define: { 'process.env.APTABASE_APP_KEY': JSON.stringify(env.APTABASE_APP_KEY || ''), - 'process.env.SENTRY_DSN': JSON.stringify(env.SENTRY_DSN || ''), - 'process.env.VITE_SENTRY_DSN': JSON.stringify(env.VITE_SENTRY_DSN || env.SENTRY_DSN || ''), + 'process.env.SENTRY_DSN': JSON.stringify(sentryDsn), + 'process.env.VITE_SENTRY_DSN': JSON.stringify(sentryDsn), 'process.env.SENTRY_RELEASE': JSON.stringify(sentryRelease), 'process.env.CHROMA_EXPLORER_RELEASE': JSON.stringify(env.CHROMA_EXPLORER_RELEASE || ''), }, @@ -59,7 +60,14 @@ export default defineConfig({ preload: { input: 'electron/preload.ts', }, - renderer: {}, + renderer: { + vite: { + define: { + 'import.meta.env.VITE_SENTRY_DSN': JSON.stringify(sentryDsn), + 'import.meta.env.VITE_SENTRY_RELEASE': JSON.stringify(sentryRelease), + }, + }, + }, }), shouldUploadSourceMaps && sentryVitePlugin({ authToken: env.SENTRY_AUTH_TOKEN,