diff --git a/bun.lockb b/bun.lockb index 7ad9d07..11aa9b5 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index ab43b4d..e7df15a 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "files": [ "dist" ], - "sideEffects": false, + "sideEffects": true, "engines": { "node": ">=21.0.0", "npm": ">=10.0.0" @@ -67,6 +67,7 @@ "dependencies": { "@laterpay/auth": "^1.1.3", "@laterpay/tapper-sdk": "^37.0.0", + "@sentry/browser": "^8.24.0", "zod": "^3.22.3" }, "targets": { diff --git a/src/capture-errors.ts b/src/capture-errors.ts new file mode 100644 index 0000000..afab4c5 --- /dev/null +++ b/src/capture-errors.ts @@ -0,0 +1,16 @@ +import { SENTRY_DSN } from "./env"; + +export const sendErrorToSentry = async (error: Error) => { + if (SENTRY_DSN) { + const { captureException } = await import("./sentry"); + captureException(error); + } +}; + +window.addEventListener("error", (event) => { + sendErrorToSentry(event.error); +}); + +window.addEventListener("unhandledrejection", (event) => { + sendErrorToSentry(event.reason); +}); diff --git a/src/env.ts b/src/env.ts index e38f005..b65617a 100644 --- a/src/env.ts +++ b/src/env.ts @@ -6,6 +6,9 @@ const envSchema = z.object({ SSO_BASE_URL: z.string(), TAPI_BASE_URL: z.string(), CHECKOUT_BASE_URL: z.string(), + SENTRY_DSN: z.string().optional(), + PACKAGE_NAME: z.string().optional(), + PACKAGE_VERSION: z.string().optional(), }); export const { @@ -14,10 +17,16 @@ export const { SSO_BASE_URL, TAPI_BASE_URL, CHECKOUT_BASE_URL, + SENTRY_DSN, + PACKAGE_NAME, + PACKAGE_VERSION, } = envSchema.parse({ AUTH_URL: process.env.AUTH_URL, TOKEN_URL: process.env.TOKEN_URL, SSO_BASE_URL: process.env.SSO_BASE_URL, TAPI_BASE_URL: process.env.TAPI_BASE_URL, CHECKOUT_BASE_URL: process.env.CHECKOUT_BASE_URL, + SENTRY_DSN: process.env.SENTRY_DSN, + PACKAGE_NAME: process.env.PACKAGE_NAME, + PACKAGE_VERSION: process.env.PACKAGE_VERSION, }); diff --git a/src/index.ts b/src/index.ts index 9b5fb7b..5ae06f8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -26,6 +26,7 @@ import { authFlow, getAuthStatus, getAccessToken, AuthStatus } from "./auth"; import { DEFAULT_CURRENCY, formatPrice } from "./price"; import { Authenticable, FormattedTab, ScreenHint, SystemUrls } from "./types"; import { handleChildWindow, openBlankChildWindow } from "./window"; +import "./capture-errors"; function authenticated( target: Authenticable, diff --git a/src/sentry.ts b/src/sentry.ts new file mode 100644 index 0000000..52d25fa --- /dev/null +++ b/src/sentry.ts @@ -0,0 +1,33 @@ +import * as Sentry from "@sentry/browser"; +import { + PACKAGE_NAME, + PACKAGE_VERSION, + SENTRY_DSN, + TAPI_BASE_URL, +} from "./env"; + +Sentry.init({ + dsn: SENTRY_DSN, + release: `${PACKAGE_NAME}@${PACKAGE_VERSION}`, + environment: TAPI_BASE_URL.includes("sbx") + ? "sbx" + : TAPI_BASE_URL.includes("stg") + ? "stg" + : "prod", + integrations: [Sentry.browserTracingIntegration()], + beforeSend: (event: Sentry.ErrorEvent) => { + const found = event.exception?.values?.some( + (value) => + value.stacktrace?.frames?.some( + (frame) => frame.filename?.match(/dist\/(prod|sbx|stg)\/index\.js/), + ), + ); + + return found ? event : null; + }, + tracesSampleRate: 1.0, // Capture 100% of the transactions + // Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled +}); + +export const captureException = (error: Error) => + Sentry.captureException(error); diff --git a/tsup.prod.config.ts b/tsup.prod.config.ts index f77db4c..9ca67d5 100644 --- a/tsup.prod.config.ts +++ b/tsup.prod.config.ts @@ -1,4 +1,5 @@ import { defineConfig } from "tsup"; +import { name, version } from "./package.json"; export default defineConfig({ entry: ["index.ts"], @@ -16,6 +17,10 @@ export default defineConfig({ SSO_BASE_URL: "https://signon.supertab.co", TAPI_BASE_URL: "https://tapi.laterpay.net", CHECKOUT_BASE_URL: "https://checkout.supertab.co", + SENTRY_DSN: + "https://52977a2775f03e0a17133cee24848baa@o23455.ingest.us.sentry.io/4507741231448064", + PACKAGE_NAME: JSON.stringify(name), + PACKAGE_VERSION: JSON.stringify(version), }, - noExternal: ["zod", "@laterpay/tapper-sdk"], + noExternal: ["zod", "@laterpay/tapper-sdk", "@sentry/browser"], }); diff --git a/tsup.sbx.config.ts b/tsup.sbx.config.ts index e010837..13ccb88 100644 --- a/tsup.sbx.config.ts +++ b/tsup.sbx.config.ts @@ -1,4 +1,5 @@ import { defineConfig } from "tsup"; +import { name, version } from "./package.json"; export default defineConfig({ entry: ["index.ts"], @@ -16,6 +17,10 @@ export default defineConfig({ SSO_BASE_URL: "https://signon.sbx.supertab.co", TAPI_BASE_URL: "https://tapi.sbx.laterpay.net", CHECKOUT_BASE_URL: "https://checkout.sbx.supertab.co", + SENTRY_DSN: + "https://52977a2775f03e0a17133cee24848baa@o23455.ingest.us.sentry.io/4507741231448064", + PACKAGE_NAME: JSON.stringify(name), + PACKAGE_VERSION: JSON.stringify(version), }, - noExternal: ["zod", "@laterpay/tapper-sdk"], + noExternal: ["zod", "@laterpay/tapper-sdk", "@sentry/browser"], }); diff --git a/tsup.stg.config.ts b/tsup.stg.config.ts index f588429..d3f0c19 100644 --- a/tsup.stg.config.ts +++ b/tsup.stg.config.ts @@ -1,4 +1,5 @@ import { defineConfig } from "tsup"; +import { name, version } from "./package.json"; export default defineConfig({ entry: ["index.ts"], @@ -16,6 +17,10 @@ export default defineConfig({ SSO_BASE_URL: "https://signon.stg.supertab.co", TAPI_BASE_URL: "https://tapi.stg.supertab.co", CHECKOUT_BASE_URL: "https://checkout.stg.supertab.co", + SENTRY_DSN: + "https://52977a2775f03e0a17133cee24848baa@o23455.ingest.us.sentry.io/4507741231448064", + PACKAGE_NAME: JSON.stringify(name), + PACKAGE_VERSION: JSON.stringify(version), }, - noExternal: ["zod", "@laterpay/tapper-sdk"], + noExternal: ["zod", "@laterpay/tapper-sdk", "@sentry/browser"], });