From a02d77a0d682924022010bb8c17407ed1f7832b5 Mon Sep 17 00:00:00 2001 From: Will Washburn Date: Wed, 15 Jul 2026 06:39:14 -0400 Subject: [PATCH 1/2] Add edge redirects for meeting links --- router/README.md | 1 + router/index.ts | 21 ++++++++++++++ router/test/vanity-redirects.test.ts | 43 ++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 router/test/vanity-redirects.test.ts diff --git a/router/README.md b/router/README.md index 37f9454d..028cfa4e 100644 --- a/router/README.md +++ b/router/README.md @@ -1,5 +1,6 @@ Route precedence: +- `/meet-with-will`, `/meet-with-khaliq`, and `/virtual-office` redirect to their external meeting destinations at the edge. - `/cloud*` routes to the Agent Relay Cloud Next.js app. - `/observer/file*` routes to the RelayFile observer app, expected to be built with `basePath: "/observer/file"`. - `/observer*` routes to the Relaycast observer app. diff --git a/router/index.ts b/router/index.ts index e6e85fda..7d7a1329 100644 --- a/router/index.ts +++ b/router/index.ts @@ -31,6 +31,11 @@ const FILE_OBSERVER_PATH_PREFIX = "/observer/file"; const OBSERVER_PATH_PREFIX = "/observer"; const CLOUD_PATH_PREFIX = "/cloud"; const WEBHOOK_ORIGIN_FLAG_KEY = "WEBHOOK_ORIGIN"; +const VANITY_REDIRECTS = new Map([ + ["/meet-with-will", "https://calendar.app.google/RqLuQyT3dYe5e2YdA"], + ["/meet-with-khaliq", "https://calendly.com/khaliq-agent-relay/30min"], + ["/virtual-office", "https://meet.google.com/ijx-gpfb-brt"], +]); // Header set by webhook-worker's queue consumer // (`packages/webhook-worker/src/queue-consumer.ts`'s `buildForwardHeaders`) on @@ -77,6 +82,17 @@ function isCloudPath(pathname: string): boolean { return isPathWithinPrefix(pathname, CLOUD_PATH_PREFIX); } +export function getVanityRedirect(hostname: string, pathname: string): string | undefined { + if (hostname !== PRIMARY_HOST) { + return undefined; + } + + const normalizedPathname = pathname.length > 1 + ? pathname.replace(/\/$/, "") + : pathname; + return VANITY_REDIRECTS.get(normalizedPathname); +} + // True only for the exact paths the webhook worker knows how to handle. Used // to gate worker forwarding so unrelated routes under /api/v1/webhooks/* (e.g. // the Composio OAuth callback) still reach the Lambda. @@ -309,6 +325,11 @@ export default { async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { const url = new URL(request.url); + const vanityRedirect = getVanityRedirect(url.hostname, url.pathname); + if (vanityRedirect) { + return Response.redirect(vanityRedirect, 302); + } + // Per-key rate limiting runs BEFORE any worker routing so a runaway // workspace gets bounded everywhere — including webhook ingress and // /cloud* traffic. The bypass list inside maybeRateLimit exempts diff --git a/router/test/vanity-redirects.test.ts b/router/test/vanity-redirects.test.ts new file mode 100644 index 00000000..7578c4b4 --- /dev/null +++ b/router/test/vanity-redirects.test.ts @@ -0,0 +1,43 @@ +import { describe, expect, it, vi } from "vitest"; + +import worker, { getVanityRedirect } from "../index.js"; + +const redirects = [ + ["/meet-with-will", "https://calendar.app.google/RqLuQyT3dYe5e2YdA"], + ["/meet-with-khaliq", "https://calendly.com/khaliq-agent-relay/30min"], + ["/virtual-office", "https://meet.google.com/ijx-gpfb-brt"], +] as const; + +function buildCtx(): ExecutionContext { + return { + waitUntil: () => undefined, + passThroughOnException: () => undefined, + } as unknown as ExecutionContext; +} + +describe("router vanity redirects", () => { + it.each(redirects)("redirects %s at the edge", async (path, destination) => { + const cloudWebWorker = { fetch: vi.fn() }; + const response = await worker.fetch( + new Request(`https://agentrelay.com${path}?utm_source=test`), + { + CLOUD_APP_ORIGIN: "https://origin.test.invalid", + CLOUD_WEB_WORKER: cloudWebWorker, + }, + buildCtx(), + ); + + expect(response.status).toBe(302); + expect(response.headers.get("location")).toBe(destination); + expect(cloudWebWorker.fetch).not.toHaveBeenCalled(); + }); + + it.each(redirects)("accepts a trailing slash for %s", (path, destination) => { + expect(getVanityRedirect("agentrelay.com", `${path}/`)).toBe(destination); + }); + + it("does not redirect another hostname or a nested path", () => { + expect(getVanityRedirect("origin-web.agentrelay.com", "/meet-with-will")).toBeUndefined(); + expect(getVanityRedirect("agentrelay.com", "/meet-with-will/details")).toBeUndefined(); + }); +}); From e88fb759430c1b61e233d289bda803b9014e1153 Mon Sep 17 00:00:00 2001 From: Will Washburn Date: Wed, 15 Jul 2026 06:44:19 -0400 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- router/index.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/router/index.ts b/router/index.ts index 7d7a1329..e8b63ddd 100644 --- a/router/index.ts +++ b/router/index.ts @@ -87,9 +87,9 @@ export function getVanityRedirect(hostname: string, pathname: string): string | return undefined; } - const normalizedPathname = pathname.length > 1 + const normalizedPathname = (pathname.length > 1 ? pathname.replace(/\/$/, "") - : pathname; + : pathname).toLowerCase(); return VANITY_REDIRECTS.get(normalizedPathname); } @@ -327,7 +327,11 @@ export default { const vanityRedirect = getVanityRedirect(url.hostname, url.pathname); if (vanityRedirect) { - return Response.redirect(vanityRedirect, 302); + const redirectUrl = new URL(vanityRedirect); + url.searchParams.forEach((value, key) => { + redirectUrl.searchParams.set(key, value); + }); + return Response.redirect(redirectUrl.toString(), 302); } // Per-key rate limiting runs BEFORE any worker routing so a runaway