diff --git a/.github/workflows/deploy-supabase.yml b/.github/workflows/deploy-supabase.yml index ca71c8c..dfa36fb 100644 --- a/.github/workflows/deploy-supabase.yml +++ b/.github/workflows/deploy-supabase.yml @@ -17,10 +17,22 @@ jobs: steps: - uses: actions/checkout@v6 + with: + fetch-depth: 0 - uses: supabase/setup-cli@v1 with: version: 2.24.3 + - name: "Sentry - Create release" + env: + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_ORG: ${{ vars.SENTRY_ORG }} + SENTRY_PROJECT: ${{ vars.SENTRY_PROJECT }} + run: | + npx @sentry/cli releases new ${{ github.sha }} + npx @sentry/cli releases set-commits ${{ github.sha }} --auto + npx @sentry/cli releases deploys ${{ github.sha }} new -e production + - name: "Supabase - Remote Connect" env: PROJECT_ID: ${{ secrets.SUPABASE_PROJECT_ID }} @@ -30,4 +42,12 @@ jobs: run: | supabase link --project-ref $PROJECT_ID supabase db push + supabase secrets set SENTRY_RELEASE=${{ github.sha }} supabase functions deploy --use-api + + - name: "Sentry - Finalize release" + env: + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_ORG: ${{ vars.SENTRY_ORG }} + SENTRY_PROJECT: ${{ vars.SENTRY_PROJECT }} + run: npx @sentry/cli releases finalize ${{ github.sha }} diff --git a/.github/workflows/deploy-web.yml b/.github/workflows/deploy-web.yml index f5e3961..7607b56 100644 --- a/.github/workflows/deploy-web.yml +++ b/.github/workflows/deploy-web.yml @@ -32,6 +32,11 @@ jobs: env: VITE_SUPABASE_URL: ${{ vars.VITE_SUPABASE_URL }} VITE_SUPABASE_ANON_KEY: ${{ vars.VITE_SUPABASE_ANON_KEY }} + VITE_SENTRY_DSN: ${{ vars.VITE_SENTRY_DSN }} + VITE_RELEASE: ${{ github.sha }} + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_ORG: ${{ vars.SENTRY_ORG }} + SENTRY_PROJECT: ${{ vars.SENTRY_PROJECT }} run: | cd src/web deno run compile diff --git a/CLAUDE.md b/CLAUDE.md index 8583670..54aa2c0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -134,4 +134,8 @@ Required in `.env` or Supabase secrets: - Deno formatting: 2-space indent, double quotes, semicolons - Run `deno task format` before committing -- Run `deno task lint` to check for issues \ No newline at end of file +- Run `deno task lint` to check for issues + +## Git + +When creating new files, always stage them with `git add ` after creating them. \ No newline at end of file diff --git a/src/web/deno.json b/src/web/deno.json index 2ccb33e..833b8ef 100644 --- a/src/web/deno.json +++ b/src/web/deno.json @@ -36,6 +36,8 @@ "react-loading-indicators": "npm:react-loading-indicators@^1.0.0", "use-sound": "npm:use-sound@^5.0.0", "usehooks-ts": "npm:usehooks-ts@^3.1.1", - "vite": "npm:vite@^7.3.1" + "vite": "npm:vite@^7.3.1", + "@sentry/react": "npm:@sentry/react@^10.43.0", + "@sentry/vite-plugin": "npm:@sentry/vite-plugin@^5.1.1" } } diff --git a/src/web/src/lib/sentry.ts b/src/web/src/lib/sentry.ts new file mode 100644 index 0000000..b7076f8 --- /dev/null +++ b/src/web/src/lib/sentry.ts @@ -0,0 +1,14 @@ +import * as Sentry from "@sentry/react"; + +export function initSentry() { + const dsn = import.meta.env.VITE_SENTRY_DSN; + if (!dsn) return; + + Sentry.init({ + dsn, + release: import.meta.env.VITE_RELEASE, + environment: import.meta.env.MODE, + integrations: [Sentry.browserTracingIntegration()], + tracesSampleRate: 1.0, + }); +} diff --git a/src/web/src/main.tsx b/src/web/src/main.tsx index 0af07fc..777dc65 100644 --- a/src/web/src/main.tsx +++ b/src/web/src/main.tsx @@ -3,6 +3,9 @@ import { StrictMode } from "react"; // @deno-types="@types/react-dom/client" import { createRoot } from "react-dom/client"; import App from "./app.tsx"; +import { initSentry } from "./lib/sentry.ts"; + +initSentry(); createRoot(document.getElementById("root") as HTMLElement).render( diff --git a/src/web/vite.config.ts b/src/web/vite.config.ts index 870cc22..739384b 100644 --- a/src/web/vite.config.ts +++ b/src/web/vite.config.ts @@ -1,7 +1,9 @@ +import process from "node:process"; import { defineConfig } from "vite"; import deno from "@deno/vite-plugin"; import react from "@vitejs/plugin-react"; import { lingui } from "@lingui/vite-plugin"; +import { sentryVitePlugin } from "@sentry/vite-plugin"; // https://vite.dev/config/ export default defineConfig({ @@ -13,7 +15,23 @@ export default defineConfig({ }, }), lingui(), + sentryVitePlugin({ + org: process.env.SENTRY_ORG, + project: process.env.SENTRY_PROJECT, + authToken: process.env.SENTRY_AUTH_TOKEN, + release: { + name: process.env.VITE_RELEASE, + setCommits: { auto: true }, + deploy: { env: process.env.NODE_ENV ?? "production" }, + }, + sourcemaps: { + filesToDeleteAfterUpload: ["dist/**/*.map"], + }, + }), ], + build: { + sourcemap: true, + }, optimizeDeps: { include: ["@tanstack/react-query"], }, diff --git a/supabase/functions/_shared/sentry.ts b/supabase/functions/_shared/sentry.ts index a469089..514f0e5 100644 --- a/supabase/functions/_shared/sentry.ts +++ b/supabase/functions/_shared/sentry.ts @@ -19,6 +19,8 @@ export class SentryErrorHandler { Sentry.init({ dsn: Deno.env.get("SENTRY_DSN")!, defaultIntegrations: false, + release: Deno.env.get("SENTRY_RELEASE"), + environment: "production", tracesSampleRate: 1.0, // deno-lint-ignore ban-ts-comment // @ts-ignore