From 73fff26b42a4772446c0a6dfc04ed4f43e0033ae Mon Sep 17 00:00:00 2001 From: meganemura <290611+meganemura@users.noreply.github.com> Date: Tue, 20 Oct 2026 11:23:28 +0000 Subject: [PATCH] fix(routes): discover routes under routes/.well-known The convention file glob skipped every dot path, so a route such as /.well-known/security.txt could not be a file. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01CZxFCFRcYc9ojkUsSvuz5j --- docs/guide/server-routing.md | 2 +- packages/void/src/shared/convention-files.ts | 6 +++--- packages/void/test/unit/scan.test.ts | 8 ++++++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/guide/server-routing.md b/docs/guide/server-routing.md index 16a3272e3..474682b4f 100644 --- a/docs/guide/server-routing.md +++ b/docs/guide/server-routing.md @@ -12,7 +12,7 @@ Create route handlers in `routes/**/*.ts`. Each file maps to a URL path based on -Dynamic segments use brackets: `[id]` becomes a route parameter and `[...slug]` becomes a catch-all. Files or directories starting with `_` are ignored. Directories wrapped in parentheses like `(admin)` are route groups. They help organize files without changing the URL. +Dynamic segments use brackets: `[id]` becomes a route parameter and `[...slug]` becomes a catch-all. Files or directories starting with `_` are ignored, and so are those starting with `.`, except `.well-known`. Directories wrapped in parentheses like `(admin)` are route groups. They help organize files without changing the URL. ### Environment-only routes diff --git a/packages/void/src/shared/convention-files.ts b/packages/void/src/shared/convention-files.ts index a31091856..843f826c8 100644 --- a/packages/void/src/shared/convention-files.ts +++ b/packages/void/src/shared/convention-files.ts @@ -2,7 +2,7 @@ import { globSync } from 'tinyglobby'; /** Handler files under `dir`, relative to it, skipping paths with a `_`-prefixed segment. */ export function listConventionFiles(dir: string): Array { - return globSync('**/*.{ts,mts,js,mjs}', { cwd: dir }).filter( - (filePath) => !filePath.split('/').some((segment) => segment.startsWith('_')), - ); + return globSync(['**/*.{ts,mts,js,mjs}', '.well-known/**/*.{ts,mts,js,mjs}'], { + cwd: dir, + }).filter((filePath) => !filePath.split('/').some((segment) => segment.startsWith('_'))); } diff --git a/packages/void/test/unit/scan.test.ts b/packages/void/test/unit/scan.test.ts index 4c5f861a2..0e8bc489e 100644 --- a/packages/void/test/unit/scan.test.ts +++ b/packages/void/test/unit/scan.test.ts @@ -73,6 +73,14 @@ describe('scanRoutes', () => { expect(result.routes[0].pattern).toBe('/api/hello'); }); + it('discovers routes under .well-known and ignores other dot paths', async () => { + createFile('routes/.well-known/security.txt.ts'); + createFile('routes/.cache/hello.ts'); + + const result = await scanRoutes(TMP); + expect(result.routes.map((route) => route.pattern)).toEqual(['/.well-known/security.txt']); + }); + it('discovers and sorts middleware by numeric prefix', async () => { createFile('middleware/02.auth.ts'); createFile('middleware/01.logger.ts');