From ebdd42d18b39dc82e8747a45e85585cb2a2100b2 Mon Sep 17 00:00:00 2001 From: Fabian Rodriguez Date: Wed, 20 May 2026 09:51:35 +0200 Subject: [PATCH 1/3] feat: send logs to profound after we send the respond to the user as part of the edge function execution --- netlify/edge-functions/serve-markdown.ts | 57 +++++++++++++++++------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/netlify/edge-functions/serve-markdown.ts b/netlify/edge-functions/serve-markdown.ts index 29b10c2cf9..a5eafbeae7 100644 --- a/netlify/edge-functions/serve-markdown.ts +++ b/netlify/edge-functions/serve-markdown.ts @@ -1,26 +1,53 @@ -import type { Config } from "@netlify/edge-functions"; +import type { Config, Context } from "@netlify/edge-functions"; -export default async (request: Request) => { +export default async (request: Request, context: Context) => { const acceptHeader = request.headers.get("Accept") || ""; - - if (!acceptHeader.includes("text/markdown")) { - return; - } - const url = new URL(request.url); const { pathname } = url; - if (pathname.endsWith(".md")) { - return; + let response: URL | undefined; + + if (acceptHeader.includes("text/markdown") && !pathname.endsWith(".md")) { + if (pathname === "/") { + url.pathname = "/index.md"; + } else { + url.pathname = pathname.replace(/\/?$/, ".md").replace(/\.html\.md$/, ".md"); + } + response = url; } - if (pathname === "/") { - url.pathname = "/index.md"; - } else { - url.pathname = pathname.replace(/\/?$/, ".md").replace(/\.html\.md$/, ".md"); + const apiKey = Netlify.env.get("PROFOUND_API_KEY"); + const loggingEnabled = Netlify.env.get("LOG_TO_PROFOUND") === "true"; + + if (apiKey && loggingEnabled) { + const params: Record = {}; + url.searchParams.forEach((value, key) => { + params[key] = value; + }); + + context.waitUntil( + fetch("https://artemis.api.tryprofound.com/v1/logs/custom", { + method: "POST", + headers: { + 'x-api-key': apiKey, + 'Content-Type': 'application/json', + }, + body: JSON.stringify([{ + timestamp: new Date().toISOString(), + method: request.method, + host: request.headers.get("host"), + path: pathname, + status_code: 200, // hardcoded, we don't want to add extra overhead + ip: context.ip, + user_agent: request.headers.get("user-agent"), + query_params: params, + referer: request.headers.get("referer"), + }]), + }) + ); } - return url; + return response; }; export const config: Config = { @@ -29,7 +56,7 @@ export const config: Config = { "/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg", "/**/*.gif", "/**/*.svg", "/**/*.ico", "/**/*.webp", "/**/*.woff", "/**/*.woff2", "/**/*.ttf", "/**/*.eot", - "/**/*.json", "/**/*.xml", "/**/*.map", + "/**/*.json", "/**/*.xml", "/**/*.map" ], onError: "bypass", }; From 05f5fd9f37ee22d5f334af1e50c64a57389fd52d Mon Sep 17 00:00:00 2001 From: Fabian Rodriguez Date: Wed, 20 May 2026 09:58:36 +0200 Subject: [PATCH 2/3] fix: exclude /assets/ and /vite/assets/ from serve-markdown Avoids unnecessary overhead and should catch assets with extensions that aren't listed in the config --- netlify/edge-functions/serve-markdown.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/netlify/edge-functions/serve-markdown.ts b/netlify/edge-functions/serve-markdown.ts index a5eafbeae7..d1173e5f92 100644 --- a/netlify/edge-functions/serve-markdown.ts +++ b/netlify/edge-functions/serve-markdown.ts @@ -53,6 +53,8 @@ export default async (request: Request, context: Context) => { export const config: Config = { path: "/*", excludedPath: [ + "/assets/*", + "/vite/assets/*", "/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg", "/**/*.gif", "/**/*.svg", "/**/*.ico", "/**/*.webp", "/**/*.woff", "/**/*.woff2", "/**/*.ttf", "/**/*.eot", From e32b9104d4fd91fd428d4dc6c9f2e3670750b60d Mon Sep 17 00:00:00 2001 From: Fabian Rodriguez Date: Thu, 21 May 2026 16:37:59 +0200 Subject: [PATCH 3/3] feat: Uses context.next() instead of a URL rewrite so the edge function runs once, and logs the real status code --- netlify/edge-functions/serve-markdown.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/netlify/edge-functions/serve-markdown.ts b/netlify/edge-functions/serve-markdown.ts index d1173e5f92..2fdbb1e6d7 100644 --- a/netlify/edge-functions/serve-markdown.ts +++ b/netlify/edge-functions/serve-markdown.ts @@ -5,17 +5,17 @@ export default async (request: Request, context: Context) => { const url = new URL(request.url); const { pathname } = url; - let response: URL | undefined; - + let nextRequest: Request = request; if (acceptHeader.includes("text/markdown") && !pathname.endsWith(".md")) { - if (pathname === "/") { - url.pathname = "/index.md"; - } else { - url.pathname = pathname.replace(/\/?$/, ".md").replace(/\.html\.md$/, ".md"); - } - response = url; + url.pathname = + pathname === "/" + ? "/index.md" + : pathname.replace(/\/?$/, ".md").replace(/\.html\.md$/, ".md"); + nextRequest = new Request(url, request); } + const response = await context.next(nextRequest); + const apiKey = Netlify.env.get("PROFOUND_API_KEY"); const loggingEnabled = Netlify.env.get("LOG_TO_PROFOUND") === "true"; @@ -37,7 +37,7 @@ export default async (request: Request, context: Context) => { method: request.method, host: request.headers.get("host"), path: pathname, - status_code: 200, // hardcoded, we don't want to add extra overhead + status_code: response.status, ip: context.ip, user_agent: request.headers.get("user-agent"), query_params: params,