From 08af6f26b2949d19e830415f767ebadc8f0beb68 Mon Sep 17 00:00:00 2001 From: rgilks Date: Tue, 9 Jun 2026 20:39:00 +0100 Subject: [PATCH 1/2] Add Sentry instrumentation --- lobby_worker/index.html | 2 ++ lobby_worker/sentry-config.js | 6 +++++ lobby_worker/sentry.js | 37 ++++++++++++++++++++++++++++ package-lock.json | 42 ++++++++++++++++++++++++++++++++ package.json | 5 +++- scripts/write-sentry-config.mjs | 24 ++++++++++++++++++ worker/index.js | 43 +++++++++++++++++++++++++++++++-- wrangler.toml | 5 ++++ 8 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 lobby_worker/sentry-config.js create mode 100644 lobby_worker/sentry.js create mode 100644 scripts/write-sentry-config.mjs diff --git a/lobby_worker/index.html b/lobby_worker/index.html index d3011a7..65aba5a 100644 --- a/lobby_worker/index.html +++ b/lobby_worker/index.html @@ -26,6 +26,8 @@ + +

PONGO

diff --git a/lobby_worker/sentry-config.js b/lobby_worker/sentry-config.js new file mode 100644 index 0000000..b617b5f --- /dev/null +++ b/lobby_worker/sentry-config.js @@ -0,0 +1,6 @@ +window.TRE_STATIC_SENTRY_CONFIG = { + app: "pongo", + dsn: "", + environment: "production", + release: "", +}; diff --git a/lobby_worker/sentry.js b/lobby_worker/sentry.js new file mode 100644 index 0000000..1ce4305 --- /dev/null +++ b/lobby_worker/sentry.js @@ -0,0 +1,37 @@ +(() => { + const config = window.TRE_STATIC_SENTRY_CONFIG; + if (!config?.dsn) return; + + const script = document.createElement("script"); + script.src = "https://browser.sentry-cdn.com/10.57.0/bundle.min.js"; + script.crossOrigin = "anonymous"; + script.onload = () => { + if (!window.Sentry) return; + window.Sentry.init({ + dsn: config.dsn, + environment: config.environment || "production", + release: config.release, + sendDefaultPii: false, + tracesSampleRate: config.environment === "production" ? 0.01 : 0, + replaysSessionSampleRate: 0, + replaysOnErrorSampleRate: 0, + beforeSend(event) { + if (event.request) { + delete event.request.cookies; + delete event.request.data; + if (event.request.headers) { + for (const key of Object.keys(event.request.headers)) { + const lowerKey = key.toLowerCase(); + if (lowerKey.includes("authorization") || lowerKey.includes("cookie")) { + event.request.headers[key] = "[Filtered]"; + } + } + } + } + event.tags = { ...event.tags, app: config.app || "pongo" }; + return event; + }, + }); + }; + document.head.appendChild(script); +})(); diff --git a/package-lock.json b/package-lock.json index 3d9952d..b2b7685 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,9 @@ "": { "name": "pongo", "version": "0.1.0", + "dependencies": { + "@sentry/cloudflare": "^10.57.0" + }, "devDependencies": { "@playwright/test": "^1.50.0", "husky": "^9.1.7", @@ -17,6 +20,15 @@ "node": ">=20.0.0" } }, + "node_modules/@opentelemetry/api": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", + "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/@playwright/test": { "version": "1.60.0", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.60.0.tgz", @@ -33,6 +45,36 @@ "node": ">=18" } }, + "node_modules/@sentry/cloudflare": { + "version": "10.57.0", + "resolved": "https://registry.npmjs.org/@sentry/cloudflare/-/cloudflare-10.57.0.tgz", + "integrity": "sha512-LDKk177la/uG92ILNozcwQR7+4/pizPu01Y7M7l9J7o1uwAi9WjElafh/HU2Jqw+vST1BKknw/tQB1pnsnkDlA==", + "license": "MIT", + "dependencies": { + "@opentelemetry/api": "^1.9.1", + "@sentry/core": "10.57.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cloudflare/workers-types": "^4.x" + }, + "peerDependenciesMeta": { + "@cloudflare/workers-types": { + "optional": true + } + } + }, + "node_modules/@sentry/core": { + "version": "10.57.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.57.0.tgz", + "integrity": "sha512-kntItTA2kiT0YpL7encXaF6mkdZMB+y48lwj8w1wkfBpfJAC7sifdgrzLQZqmsqVNE3crg9VfufaAGA+78uFMg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/ansi-escapes": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz", diff --git a/package.json b/package.json index 5af0a0f..ec2a2e4 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "test:all": "prettier --check . && cargo fmt --check && cargo check --workspace && cargo clippy --workspace -- -D warnings && cargo test --workspace && npm run check:diagrams", "format": "prettier --write .", "build:client": "cd client_wasm && wasm-pack build --target web --out-dir ../worker/pkg/client_wasm", - "build:server": "cd lobby_worker && wasm-pack build --target web --out-dir ../worker/pkg && cp index.html style.css *.js manifest.webmanifest ../worker/pkg/ && cp -r icons ../worker/pkg/", + "build:server": "node scripts/write-sentry-config.mjs && cd lobby_worker && wasm-pack build --target web --out-dir ../worker/pkg && cp index.html style.css *.js manifest.webmanifest ../worker/pkg/ && cp -r icons ../worker/pkg/", "build": "npm run build:server && npm run build:client && node scripts/stamp-sw.mjs", "dev": "npx wrangler dev --assets worker/pkg", "deploy": "npx wrangler deploy", @@ -32,5 +32,8 @@ "lint-staged": { "*.rs": "rustfmt", "**/*": "prettier --write --ignore-unknown" + }, + "dependencies": { + "@sentry/cloudflare": "^10.57.0" } } diff --git a/scripts/write-sentry-config.mjs b/scripts/write-sentry-config.mjs new file mode 100644 index 0000000..f90d722 --- /dev/null +++ b/scripts/write-sentry-config.mjs @@ -0,0 +1,24 @@ +import { writeFileSync } from "node:fs"; +import { execSync } from "node:child_process"; + +function fallbackRelease() { + try { + return execSync("git rev-parse --short HEAD", { encoding: "utf8" }).trim(); + } catch { + return String(Date.now()); + } +} + +writeFileSync( + "lobby_worker/sentry-config.js", + `window.TRE_STATIC_SENTRY_CONFIG = ${JSON.stringify( + { + app: "pongo", + dsn: process.env.SENTRY_DSN || "", + environment: process.env.SENTRY_ENVIRONMENT || "production", + release: process.env.SENTRY_RELEASE || process.env.GITHUB_SHA || fallbackRelease(), + }, + null, + 2 + )};\n` +); diff --git a/worker/index.js b/worker/index.js index 74d3473..2f0a64d 100644 --- a/worker/index.js +++ b/worker/index.js @@ -1,3 +1,4 @@ +import * as Sentry from "@sentry/cloudflare"; import init, { fetch as wasmFetch, MatchDO as WasmMatchDO } from "./pkg/lobby_worker.js"; import wasmUrl from "./pkg/lobby_worker_bg.wasm"; @@ -7,7 +8,34 @@ async function ensureInit() { await initPromise; } -export default { +const sentryOptions = (env) => { + if (!env.SENTRY_DSN) return undefined; + return { + dsn: env.SENTRY_DSN, + environment: env.SENTRY_ENVIRONMENT || "production", + release: env.SENTRY_RELEASE, + sendDefaultPii: false, + tracesSampleRate: env.SENTRY_ENVIRONMENT === "production" ? 0.01 : 0, + enableRpcTracePropagation: true, + beforeSend(event) { + if (event.request) { + delete event.request.cookies; + delete event.request.data; + if (event.request.headers) { + for (const key of Object.keys(event.request.headers)) { + const lowerKey = key.toLowerCase(); + if (lowerKey.includes("authorization") || lowerKey.includes("cookie")) { + event.request.headers[key] = "[Filtered]"; + } + } + } + } + return event; + }, + }; +}; + +const handler = { async fetch(req, env, ctx) { try { await ensureInit(); @@ -23,6 +51,8 @@ export default { }, }; +export default Sentry.withSentry(sentryOptions, handler); + // The generated WasmMatchDO constructor is synchronous and needs the wasm // module ready. The DO runtime can construct it before the top-level init() // resolves, so defer construction behind ensureInit(). @@ -47,4 +77,13 @@ class MatchDOWrapper { } } -export { MatchDOWrapper as MatchDO }; +export const MatchDO = Sentry.instrumentDurableObjectWithSentry( + (env) => + sentryOptions(env) || { + environment: env.SENTRY_ENVIRONMENT || "production", + sendDefaultPii: false, + tracesSampleRate: 0, + enableRpcTracePropagation: true, + }, + MatchDOWrapper +); diff --git a/wrangler.toml b/wrangler.toml index cb6017f..9e3cca5 100644 --- a/wrangler.toml +++ b/wrangler.toml @@ -1,6 +1,11 @@ name = "pongo" main = "worker/index.js" compatibility_date = "2024-01-01" +compatibility_flags = ["nodejs_als"] + +[vars] +SENTRY_ENVIRONMENT = "production" +SENTRY_PROJECT = "pongo" [build] # Mirror `npm run build` so a standalone `wrangler deploy` produces a complete worker/pkg. From dbe6108704aa81487d1a37d6a7baa4864e90008b Mon Sep 17 00:00:00 2001 From: rgilks Date: Sun, 14 Jun 2026 09:02:31 +0100 Subject: [PATCH 2/2] chore: make asset 404 handling explicit --- wrangler.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/wrangler.toml b/wrangler.toml index 9e3cca5..be78741 100644 --- a/wrangler.toml +++ b/wrangler.toml @@ -15,6 +15,7 @@ command = "npm run build" directory = "./worker/pkg" binding = "ASSETS" html_handling = "auto-trailing-slash" +not_found_handling = "404-page" [durable_objects] bindings = [{ name = "MATCH", class_name = "MatchDO" }]