diff --git a/apps/editor/proxy.test.ts b/apps/editor/proxy.test.ts index 1326543d23..5009e809b0 100644 --- a/apps/editor/proxy.test.ts +++ b/apps/editor/proxy.test.ts @@ -1,6 +1,7 @@ import { afterEach, expect, test } from 'bun:test' +import { unstable_doesMiddlewareMatch } from 'next/experimental/testing/server' import { issueSession, SESSION_COOKIE } from './lib/self-host-auth' -import { gateRequest } from './proxy' +import { config, gateRequest } from './proxy' const OLD_ENV = { ...process.env } @@ -66,6 +67,46 @@ test('login, setup, health and the scene API are never gated here', () => { } }) +test('the proxy runs on every page and API path, including dotted and locale-prefixed ones', () => { + process.env.PASCAL_ADMIN_PASSWORD = 'secret' + for (const path of [ + '/', + '/project/abc', + '/project/a.json', + '/project/abc.d.e', + '/api/x.json', + '/api/plugins/mint/session', + '/api/plugins/mint/api/x.json', + '/fr/admin', + '/en/api/x', + '/en/project/a.json', + '/fr/items/x.glb', + '/settings', + ]) { + expect([path, unstable_doesMiddlewareMatch({ config, url: path })]).toEqual([path, true]) + expect([path, gateRequest(request(path))?.status]).not.toEqual([path, undefined]) + } +}) + +test('Next and public/ static assets skip the proxy', () => { + for (const path of [ + '/_next/static/chunks/main.js', + '/_next/static/media/font.woff2', + '/_next/image?url=%2Fpascal.svg&w=64&q=75', + '/favicon.ico', + '/pascal-logo-shape.svg', + '/audios/sfx/snapshot_capture.mp3', + '/demos/demo_1.json', + '/fonts/PlusJakartaSans-SemiBold.ttf', + '/hdri/venice_sunset_1k.hdr', + '/icons/column.webp', + '/items/round-carpet/model.glb', + '/material/concrete/prepared_drywall/prepared_drywall_normal_512.ktx2', + ]) { + expect([path, unstable_doesMiddlewareMatch({ config, url: path })]).toEqual([path, false]) + } +}) + test('loopback and an upstream proxy are open', () => { delete process.env.PASCAL_ADMIN_PASSWORD const loopback = new Request('http://localhost:3002/', { diff --git a/apps/editor/proxy.ts b/apps/editor/proxy.ts index 9fe7227207..15676a8ecc 100644 --- a/apps/editor/proxy.ts +++ b/apps/editor/proxy.ts @@ -46,6 +46,11 @@ export function gateRequest(request: Request): NextResponse | null { } export const config = { - // Everything except Next's own assets and files served from `public/`. - matcher: ['/((?!_next/|.*\\.[a-zA-Z0-9]+$).*)'], + // Everything except Next's own assets and the files served from `public/` + // and `app/favicon.ico`, listed by location. Exclude assets by where they + // live, never by a file extension, since dynamic route segments accept dots. + // Keep this in sync with the folders in `public/`. + matcher: [ + '/((?!_next/|favicon\\.ico$|(?:audios|demos|fonts|hdri|icons|items|material)/|[^/]+\\.svg$).*)', + ], }