diff --git a/.dev.vars.example b/.dev.vars.example index 69f7999e1de..2377f6a996f 100644 --- a/.dev.vars.example +++ b/.dev.vars.example @@ -1,6 +1,8 @@ # env vars for local development of /functions/donation/donate.ts Cloudflare pages function # rename to .dev.vars and fill in the values from the homonymous "(dev)" keys in 1Password +ENV=development + # https://dashboard.stripe.com/test/apikeys # required by /donation/donate STRIPE_SECRET_KEY= @@ -14,3 +16,6 @@ RECAPTCHA_SECRET_KEY= STRIPE_WEBHOOK_SECRET= MAILGUN_DOMAIN= MAILGUN_SENDING_KEY= + +# optional +SENTRY_DSN= diff --git a/functions/donation/_middleware.ts b/functions/donation/_middleware.ts new file mode 100644 index 00000000000..9135a17cf45 --- /dev/null +++ b/functions/donation/_middleware.ts @@ -0,0 +1,31 @@ +import sentryPlugin from "@cloudflare/pages-plugin-sentry" +import { CaptureConsole } from "@sentry/integrations" + +interface SentryEnvVars { + SENTRY_DSN: string + ENV: "production" | "development" +} + +const hasSentryEnvVars = (env: any): env is SentryEnvVars => { + return ( + !!env.SENTRY_DSN && + !!env.ENV && + ["production", "development"].includes(env.ENV) + ) +} + +export const onRequest: PagesFunction = (context) => { + if (!hasSentryEnvVars(context.env)) { + console.error( + "Missing Sentry environment variables. Continuing without error logging..." + ) + // Gracefully continue if Sentry is not configured. + return context.next() + } + + return sentryPlugin({ + dsn: context.env.SENTRY_DSN, + integrations: [new CaptureConsole()], + environment: context.env.ENV, + })(context) +} diff --git a/functions/donation/donate.ts b/functions/donation/donate.ts index f889599f2aa..f3a308d3215 100644 --- a/functions/donation/donate.ts +++ b/functions/donation/donate.ts @@ -11,13 +11,12 @@ import { Value } from "@sinclair/typebox/value" import { DEFAULT_HEADERS, CORS_HEADERS } from "./_utils/constants.js" interface DonateEnvVars { - ASSETS: Fetcher STRIPE_SECRET_KEY: string RECAPTCHA_SECRET_KEY: string } const hasDonateEnvVars = (env: any): env is DonateEnvVars => { - return !!env.ASSETS && !!env.STRIPE_SECRET_KEY && !!env.RECAPTCHA_SECRET_KEY + return !!env.STRIPE_SECRET_KEY && !!env.RECAPTCHA_SECRET_KEY } // This function is called when the request is a preflight request ("OPTIONS"). @@ -79,6 +78,8 @@ export const onRequestPost: PagesFunction = async ({ status: 200, }) } catch (error) { + // Reporting to Sentry through the CaptureConsole integration in _middleware.ts + console.error("Error in donation/donate.ts", error) return new Response( JSON.stringify({ error: stringifyUnknownError(error) }), { diff --git a/functions/donation/thank-you.ts b/functions/donation/thank-you.ts index 5500c7844e5..5d12d09b461 100644 --- a/functions/donation/thank-you.ts +++ b/functions/donation/thank-you.ts @@ -13,7 +13,6 @@ interface MessageData { } type ThankYouEnvVars = { - ASSETS: Fetcher STRIPE_WEBHOOK_SECRET: string STRIPE_SECRET_KEY: string } & MailgunEnvVars @@ -21,10 +20,8 @@ type ThankYouEnvVars = { const hasThankYouEnvVars = (env: unknown): env is ThankYouEnvVars => { return ( typeof env === "object" && - "ASSETS" in env && "STRIPE_WEBHOOK_SECRET" in env && "STRIPE_SECRET_KEY" in env && - !!env.ASSETS && !!env.STRIPE_WEBHOOK_SECRET && !!env.STRIPE_SECRET_KEY ) @@ -132,7 +129,8 @@ export const onRequestPost: PagesFunction = async ({ status: 200, }) } catch (error) { - console.error(error) + // Reporting to Sentry through the CaptureConsole integration in _middleware.ts + console.error("Error in donation/thank-you.ts", error) return new Response( JSON.stringify({ error: stringifyUnknownError(error) }), { diff --git a/package.json b/package.json index 52d50fa2931..aef92231101 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "@bugsnag/js": "^7.20.0", "@bugsnag/plugin-express": "^7.19.0", "@bugsnag/plugin-react": "^7.19.0", + "@cloudflare/pages-plugin-sentry": "^1.1.1", "@fortawesome/fontawesome-svg-core": "^6.4.2", "@fortawesome/free-brands-svg-icons": "^6.4.2", "@fortawesome/free-solid-svg-icons": "^6.4.2", diff --git a/yarn.lock b/yarn.lock index aa28076acb2..e589da4ca8a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1958,6 +1958,15 @@ __metadata: languageName: node linkType: hard +"@cloudflare/pages-plugin-sentry@npm:^1.1.1": + version: 1.1.1 + resolution: "@cloudflare/pages-plugin-sentry@npm:1.1.1" + dependencies: + toucan-js: "npm:^3.0.0" + checksum: a9058ac31f662b6f6a2176f92e8befc07d82b28e72c73904600f173aa9ed782953cb0b3cdd82a23e84f6be7ea2c67ae81e377920206825083495c8b66075d582 + languageName: node + linkType: hard + "@cloudflare/workerd-darwin-64@npm:1.20231218.0": version: 1.20231218.0 resolution: "@cloudflare/workerd-darwin-64@npm:1.20231218.0" @@ -3814,6 +3823,44 @@ __metadata: languageName: node linkType: hard +"@sentry/core@npm:7.76.0": + version: 7.76.0 + resolution: "@sentry/core@npm:7.76.0" + dependencies: + "@sentry/types": "npm:7.76.0" + "@sentry/utils": "npm:7.76.0" + checksum: f6b524036a0bfe875868882d31a822ae71e598a33da1c6bb6ebf62da0520ac2b6dca5e28c70e8fb7570751ae1ebd590fc3c5b5fcc49f857753dcb739bfa7f06e + languageName: node + linkType: hard + +"@sentry/integrations@npm:7.76.0": + version: 7.76.0 + resolution: "@sentry/integrations@npm:7.76.0" + dependencies: + "@sentry/core": "npm:7.76.0" + "@sentry/types": "npm:7.76.0" + "@sentry/utils": "npm:7.76.0" + localforage: "npm:^1.8.1" + checksum: 8f307c81fd0eec8ee250061a311bc0b5d7f0839a069b6939d0576aee74f9d87cd332e6376d41b75dc4c789aaeedba11087f28e7950f1769884bbf05a3898a3d0 + languageName: node + linkType: hard + +"@sentry/types@npm:7.76.0": + version: 7.76.0 + resolution: "@sentry/types@npm:7.76.0" + checksum: 67a4cde848be8be534b42608f930da91fcb3e6e9f38843d9fc670d5bd531f7d13f826fb24f0ef6f88f1e3e603e8377ea1412b2fd8097ba641746ad4243b90936 + languageName: node + linkType: hard + +"@sentry/utils@npm:7.76.0": + version: 7.76.0 + resolution: "@sentry/utils@npm:7.76.0" + dependencies: + "@sentry/types": "npm:7.76.0" + checksum: 141e40b3ed4da50b2b6ceb11d58e557db34431d0ad8837af21636de5692275e1fddb0b920bb20c9ac2ead67c28a446fc76f451eefd10304a4aea85f9f2b32242 + languageName: node + linkType: hard + "@sigstore/bundle@npm:^1.1.0": version: 1.1.0 resolution: "@sigstore/bundle@npm:1.1.0" @@ -10752,6 +10799,7 @@ __metadata: "@bugsnag/js": "npm:^7.20.0" "@bugsnag/plugin-express": "npm:^7.19.0" "@bugsnag/plugin-react": "npm:^7.19.0" + "@cloudflare/pages-plugin-sentry": "npm:^1.1.1" "@cloudflare/workers-types": "npm:^4.20230821.0" "@fortawesome/fontawesome-svg-core": "npm:^6.4.2" "@fortawesome/free-brands-svg-icons": "npm:^6.4.2" @@ -11478,6 +11526,13 @@ __metadata: languageName: node linkType: hard +"immediate@npm:~3.0.5": + version: 3.0.6 + resolution: "immediate@npm:3.0.6" + checksum: f9b3486477555997657f70318cc8d3416159f208bec4cca3ff3442fd266bc23f50f0c9bd8547e1371a6b5e82b821ec9a7044a4f7b944798b25aa3cc6d5e63e62 + languageName: node + linkType: hard + "immutable@npm:^3.8.2": version: 3.8.2 resolution: "immutable@npm:3.8.2" @@ -13467,6 +13522,15 @@ __metadata: languageName: node linkType: hard +"lie@npm:3.1.1": + version: 3.1.1 + resolution: "lie@npm:3.1.1" + dependencies: + immediate: "npm:~3.0.5" + checksum: c2c7d9dcc3a9aae641f41cde4e2e2cd571e4426b1f5915862781d77776672dcbca43461e16f4d382c9a300825c15e1a4923f1def3a5568d97577e077a3cecb44 + languageName: node + linkType: hard + "liftoff@npm:3.1.0": version: 3.1.0 resolution: "liftoff@npm:3.1.0" @@ -13556,6 +13620,15 @@ __metadata: languageName: node linkType: hard +"localforage@npm:^1.8.1": + version: 1.10.0 + resolution: "localforage@npm:1.10.0" + dependencies: + lie: "npm:3.1.1" + checksum: d5c44be3a09169b013a3ebe252e678aaeb6938ffe72e9e12c199fd4307c1ec9d1a057ac2dfdfbb1379dfeec467a34ad0fc3ecd27489a2c43a154fb72b2822542 + languageName: node + linkType: hard + "locate-path@npm:^2.0.0": version: 2.0.0 resolution: "locate-path@npm:2.0.0" @@ -19446,6 +19519,18 @@ __metadata: languageName: node linkType: hard +"toucan-js@npm:^3.0.0": + version: 3.3.1 + resolution: "toucan-js@npm:3.3.1" + dependencies: + "@sentry/core": "npm:7.76.0" + "@sentry/integrations": "npm:7.76.0" + "@sentry/types": "npm:7.76.0" + "@sentry/utils": "npm:7.76.0" + checksum: 6985980551f68170bca01e932f32b06ec14698bcd661188084cfa741a98a789ac3f5195ec2da3b535b8a254fadc2c8a018f3a334b6788884178a624e337a5179 + languageName: node + linkType: hard + "tough-cookie@npm:^4.1.2": version: 4.1.3 resolution: "tough-cookie@npm:4.1.3"