From 1af55f5e105a6a06265e2f160e42da15342fbdb0 Mon Sep 17 00:00:00 2001 From: Andrew Jon Przybilla Date: Mon, 4 May 2026 22:32:07 -0700 Subject: [PATCH 1/2] Now properly proxying channels reference in pnpm dev server setup Signed-off-by: Andrew Jon Przybilla --- apps/web/vite.config.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts index 49dd660..f491a5c 100644 --- a/apps/web/vite.config.ts +++ b/apps/web/vite.config.ts @@ -29,6 +29,11 @@ import { VitePWA } from 'vite-plugin-pwa'; // matches `DEFAULT_PORT` (8717) from the SDK and the server's CLI // default so `pnpm dev` at the root "just works" with no env vars. const PROXY_TARGET = 'http://127.0.0.1:8717'; +// Keep this in sync with PATHS in packages/sdk/src/protocol.ts. Each +// entry is a prefix — Vite forwards anything matching `/` (and +// its subpaths). Adding a new top-level API surface to the broker +// almost always means adding it here too, otherwise Vite serves the +// SPA fallback (or 404s) instead of proxying through to :8717. const PROXIED_PATHS = [ '/healthz', '/briefing', @@ -39,6 +44,10 @@ const PROXIED_PATHS = [ '/session', '/objectives', '/members', + '/channels', + '/team', + '/enroll', + '/presence', '/fs', ]; From e1c26a2e965c2f97d89077888d4361357dcee1a4 Mon Sep 17 00:00:00 2001 From: Andrew Jon Przybilla Date: Mon, 4 May 2026 22:41:33 -0700 Subject: [PATCH 2/2] Proxy now derived automagically. --- apps/web/vite.config.ts | 93 ++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 43 deletions(-) diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts index f491a5c..8125ee9 100644 --- a/apps/web/vite.config.ts +++ b/apps/web/vite.config.ts @@ -18,38 +18,61 @@ */ import { resolve } from 'node:path'; +import { PATHS } from '@agentc7/sdk/protocol'; import preact from '@preact/preset-vite'; import unocss from 'unocss/vite'; import { defineConfig, type PluginOption } from 'vite'; import { VitePWA } from 'vite-plugin-pwa'; -// ac7 API paths that dev mode must proxy through to the real -// server. Kept in sync with PATHS in packages/sdk/src/protocol.ts -// and the /session/* + /push/* routes added in later phases. Port -// matches `DEFAULT_PORT` (8717) from the SDK and the server's CLI -// default so `pnpm dev` at the root "just works" with no env vars. +// Dev-mode proxy target: the broker's default bind port. Matches +// `DEFAULT_PORT` (8717) from the SDK so `pnpm dev` at the repo root +// just works with no env vars. const PROXY_TARGET = 'http://127.0.0.1:8717'; -// Keep this in sync with PATHS in packages/sdk/src/protocol.ts. Each -// entry is a prefix — Vite forwards anything matching `/` (and -// its subpaths). Adding a new top-level API surface to the broker -// almost always means adding it here too, otherwise Vite serves the -// SPA fallback (or 404s) instead of proxying through to :8717. -const PROXIED_PATHS = [ - '/healthz', - '/briefing', - '/roster', - '/push', - '/subscribe', - '/history', - '/session', - '/objectives', - '/members', - '/channels', - '/team', - '/enroll', - '/presence', - '/fs', -]; + +/** + * Paths whose top-level segment is *also* a SPA route — proxying the + * top-level prefix would steal that page from Vite. We forward only + * subpaths via a regex below, leaving the bare path for the SPA. + * + * `/enroll` → SPA page (the verify-code form an operator hits + * from a CLI deep link); see apps/web/src/App.tsx. + * `/enroll/poll` etc → API endpoints (must reach the broker). + * + * Add to this set if you ever introduce another shared prefix. + */ +const SPA_SHARED_PREFIXES = new Set(['/enroll']); + +/** + * Derive the dev-proxy rule set from `PATHS` so adding a new API + * surface to the broker requires no change here. We map every value + * to its top-level segment (`/team/presets` → `/team`), de-dupe, and + * proxy each to the broker. Top-level segments that conflict with a + * SPA route fall back to a subpath-only regex (`^/enroll/`) so the + * bare path is still served by Vite as the SPA. + */ +function deriveProxyRules(): Record { + const topLevel = new Set(); + for (const value of Object.values(PATHS)) { + const seg = value.split('/')[1]; + if (seg) topLevel.add(`/${seg}`); + } + const rules: Record = {}; + for (const prefix of topLevel) { + const key = SPA_SHARED_PREFIXES.has(prefix) ? `^${prefix}/` : prefix; + rules[key] = { + target: PROXY_TARGET, + // Session cookies are SameSite=Strict, so we preserve the + // browser-visible host; `changeOrigin: false` ensures the + // Origin header reaches Hono unchanged. + changeOrigin: false, + // `/subscribe` and `/members/:name/activity/stream` upgrade to + // WebSocket; `ws: true` on every rule is harmless for HTTP-only + // paths and required for upgrades. + ws: true, + }; + } + return rules; +} // `vite-plugin-pwa` ships with its own nested copy of Vite's types, // so its `Plugin[]` return is a distinct-but-structurally-identical @@ -120,22 +143,6 @@ export default defineConfig({ }, server: { port: 5173, - // Proxy every known API path through to the Hono server. - // `/subscribe` and `/members/:name/activity/stream` upgrade to - // WebSocket, so `ws: true` is set on every proxied path — - // harmless for HTTP-only paths, required for upgrades. - proxy: Object.fromEntries( - PROXIED_PATHS.map((p) => [ - p, - { - target: PROXY_TARGET, - changeOrigin: false, - // Session cookies are set with SameSite=Strict, so we need - // to preserve the host; `changeOrigin: false` ensures the - // Origin header reaches Hono unchanged. - ws: true, - }, - ]), - ), + proxy: deriveProxyRules(), }, });