From 48b91d681d94cda96e5620618915f2b9339938cc Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 17 May 2026 14:15:00 +0000 Subject: [PATCH 1/2] Handle noisy scanner posts before workshop router Co-authored-by: Kent C. Dodds --- epicshop/package.json | 4 ++ epicshop/patch-workshop-app.js | 91 +++++++++++++++++++++++++++++ epicshop/patch-workshop-app.test.js | 45 ++++++++++++++ 3 files changed, 140 insertions(+) create mode 100644 epicshop/patch-workshop-app.js create mode 100644 epicshop/patch-workshop-app.test.js diff --git a/epicshop/package.json b/epicshop/package.json index 1509e35..3e1fa55 100644 --- a/epicshop/package.json +++ b/epicshop/package.json @@ -1,5 +1,9 @@ { "type": "module", + "scripts": { + "postinstall": "node ./patch-workshop-app.js", + "test:patch-workshop-app": "node --test ./patch-workshop-app.test.js" + }, "dependencies": { "@epic-web/workshop-app": "^6.90.3", "@epic-web/workshop-utils": "^6.90.3", diff --git a/epicshop/patch-workshop-app.js b/epicshop/patch-workshop-app.js new file mode 100644 index 0000000..1acc055 --- /dev/null +++ b/epicshop/patch-workshop-app.js @@ -0,0 +1,91 @@ +import fs from 'node:fs/promises' +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +const currentFilePath = fileURLToPath(import.meta.url) +const currentDir = path.dirname(currentFilePath) + +const serverPatchMarker = 'programming-foundations:sentry-noisy-catch-all-posts' + +const serverPatchSearch = `app.options("*splat", (_req, res) => { + res.set("Allow", "GET, HEAD, POST, OPTIONS"); + res.sendStatus(204); +}); +function getNumberOrNull(value) {` + +const serverPatchReplacement = `app.options("*splat", (_req, res) => { + res.set("Allow", "GET, HEAD, POST, OPTIONS"); + res.sendStatus(204); +}); +const noisyCatchAllMutationPrefixes = [ + "/__rsc", + "/_next", + "/_rsc", + "/__nextjs_action", + "/_middleware", + "/RSC/" +]; +const noisyCatchAllMutationPaths = /* @__PURE__ */ new Set([ + "/", + "/.action" +]); +function isNoisyCatchAllMutationPath(pathname) { + return noisyCatchAllMutationPaths.has(pathname) || noisyCatchAllMutationPrefixes.some( + (prefix) => pathname === prefix || pathname.startsWith(prefix.endsWith("/") ? prefix : \`\${prefix}/\`) + ); +} +app.all("*splat", (req, res, next) => { + if (req.method === "GET" || req.method === "HEAD" || req.method === "OPTIONS") { + return next(); + } + if (!isNoisyCatchAllMutationPath(req.path)) return next(); + + res.status(404).type("text/plain").send("Not found"); +}); +// ${serverPatchMarker} +function getNumberOrNull(value) {` + +function getWorkshopAppServerPath(epicshopDir = currentDir) { + return path.join( + epicshopDir, + 'node_modules', + '@epic-web', + 'workshop-app', + 'dist', + 'server', + 'index.js', + ) +} + +export function patchWorkshopAppServer(source) { + if (source.includes(serverPatchMarker)) return source + + if (!source.includes(serverPatchSearch)) { + throw new Error( + 'Could not find the workshop app server insertion point. The upstream server may have changed.', + ) + } + + return source.replace(serverPatchSearch, serverPatchReplacement) +} + +export async function patchWorkshopApp(epicshopDir = currentDir) { + const serverPath = getWorkshopAppServerPath(epicshopDir) + const source = await fs.readFile(serverPath, 'utf8') + const patchedSource = patchWorkshopAppServer(source) + + if (patchedSource === source) { + console.log('workshop-app server patch already applied') + return + } + + await fs.writeFile(serverPath, patchedSource) + console.log('patched workshop-app server noisy catch-all mutation handling') +} + +if (process.argv[1] === currentFilePath) { + patchWorkshopApp().catch((error) => { + console.error(error) + process.exit(1) + }) +} diff --git a/epicshop/patch-workshop-app.test.js b/epicshop/patch-workshop-app.test.js new file mode 100644 index 0000000..eaa789b --- /dev/null +++ b/epicshop/patch-workshop-app.test.js @@ -0,0 +1,45 @@ +import assert from 'node:assert/strict' +import { describe, it } from 'node:test' + +import { patchWorkshopAppServer } from './patch-workshop-app.js' + +const serverSource = `app.options("*splat", (_req, res) => { + res.set("Allow", "GET, HEAD, POST, OPTIONS"); + res.sendStatus(204); +}); +function getNumberOrNull(value) { + if (value == null) return null; +}` + +describe('patchWorkshopAppServer', () => { + it('adds a narrow normal 404 handler for known scanner mutation paths', () => { + const patchedSource = patchWorkshopAppServer(serverSource) + + assert.match(patchedSource, /programming-foundations:sentry-noisy-catch-all-posts/) + assert.match(patchedSource, /app\.all\("\*splat"/) + assert.match(patchedSource, /req\.method === "GET"/) + assert.match(patchedSource, /req\.method === "HEAD"/) + assert.match(patchedSource, /req\.method === "OPTIONS"/) + assert.match(patchedSource, /"\/__rsc"/) + assert.match(patchedSource, /"\/_next"/) + assert.match(patchedSource, /"\/_rsc"/) + assert.match(patchedSource, /"\/__nextjs_action"/) + assert.match(patchedSource, /"\/_middleware"/) + assert.match(patchedSource, /"\/RSC\/"/) + assert.match(patchedSource, /"\/\.action"/) + assert.match(patchedSource, /res\.status\(404\)/) + }) + + it('does not apply the server patch more than once', () => { + const patchedSource = patchWorkshopAppServer(serverSource) + + assert.equal(patchWorkshopAppServer(patchedSource), patchedSource) + }) + + it('fails loudly if the upstream server shape changes', () => { + assert.throws( + () => patchWorkshopAppServer('app.all("*splat", handler)'), + /Could not find the workshop app server insertion point/, + ) + }) +}) From 760c0fa028702d5b1f2a84a27cff68048f1234be Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 17 May 2026 14:17:29 +0000 Subject: [PATCH 2/2] Record workshop app postinstall patch Co-authored-by: Kent C. Dodds --- epicshop/package-lock.json | 1 + 1 file changed, 1 insertion(+) diff --git a/epicshop/package-lock.json b/epicshop/package-lock.json index 750e76c..3bf6517 100644 --- a/epicshop/package-lock.json +++ b/epicshop/package-lock.json @@ -4,6 +4,7 @@ "requires": true, "packages": { "": { + "hasInstallScript": true, "dependencies": { "@epic-web/workshop-app": "^6.90.3", "@epic-web/workshop-utils": "^6.90.3",