diff --git a/.serena/.gitignore b/.serena/.gitignore new file mode 100644 index 0000000..14d86ad --- /dev/null +++ b/.serena/.gitignore @@ -0,0 +1 @@ +/cache diff --git a/changelog.md b/changelog.md index d761459..5ae7d76 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,13 @@ # Changelog +## 2025-09-03 - 3.0.78 - fix(servertools) +Fix wildcard path extraction for static/proxy handlers, correct serviceworker route, add local settings and test typo fix + +- Make HandlerProxy and HandlerStatic robust to Express 5 wildcard param shapes (handle req.params.splat, numeric params, req.baseUrl and root routes) to correctly compute relative paths +- Change serviceworker route registration to use '/serviceworker/*splat' (instead of previous pattern) for consistent wildcard handling +- Fix test wording typo in test/test.server.ts ('exposer' -> 'expose') +- Add .claude/settings.local.json with local tool permissions and add .serena/.gitignore to ignore /cache + ## 2025-08-17 - 3.0.77 - fix(servertools) Adjust route wildcard patterns and CORS handling; update serviceworker and SSL redirect patterns; bump express dependency; add local Claude settings diff --git a/test/test.server.ts b/test/test.server.ts index cd3f3db..c34b0d2 100644 --- a/test/test.server.ts +++ b/test/test.server.ts @@ -122,7 +122,7 @@ tap.test('should answer a preflight request', async () => { console.log(response.headers); }); -tap.test('should exposer a sitemap', async () => { +tap.test('should expose a sitemap', async () => { const response = await fetch('http://127.0.0.1:3000/sitemap'); console.log(await response.text()); }); diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 6b38220..32d3695 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@api.global/typedserver', - version: '3.0.77', + version: '3.0.78', description: 'A TypeScript-based project for easy serving of static files with support for live reloading, compression, and typed requests.' } diff --git a/ts/servertools/classes.handlerproxy.ts b/ts/servertools/classes.handlerproxy.ts index 774c342..8de0103 100644 --- a/ts/servertools/classes.handlerproxy.ts +++ b/ts/servertools/classes.handlerproxy.ts @@ -16,7 +16,31 @@ export class HandlerProxy extends Handler { } ) { super('ALL', async (req, res) => { - const relativeRequestPath = req.path.slice(req.route.path.length - 1); + // Extract the path using Express 5's params or fallback methods + let relativeRequestPath: string; + if (req.params && req.params.splat !== undefined) { + // Express 5 wildcard route (/*splat) + // Handle array values - join them if array, otherwise use as-is + relativeRequestPath = Array.isArray(req.params.splat) ? req.params.splat.join('/') : String(req.params.splat || ''); + } else if (req.params && req.params[0] !== undefined) { + // Numbered parameter fallback + relativeRequestPath = Array.isArray(req.params[0]) ? req.params[0].join('/') : String(req.params[0] || ''); + } else if (req.baseUrl) { + // If there's a baseUrl, remove it from the path + relativeRequestPath = req.path.slice(req.baseUrl.length); + } else if (req.route && req.route.path === '/') { + // Root route - use full path minus leading slash + relativeRequestPath = req.path.slice(1); + } else { + // Fallback to the original slicing logic for compatibility + relativeRequestPath = req.path.slice(req.route.path.length - 1); + } + + // Ensure relativeRequestPath is a string and has no leading slash + relativeRequestPath = String(relativeRequestPath || ''); + if (relativeRequestPath.startsWith('/')) { + relativeRequestPath = relativeRequestPath.slice(1); + } const proxyRequestUrl = remoteMountPointArg + relativeRequestPath; console.log(`proxy ${req.path} to ${proxyRequestUrl}`); let proxiedResponse: plugins.smartrequest.ICoreResponse; diff --git a/ts/servertools/classes.handlerstatic.ts b/ts/servertools/classes.handlerstatic.ts index 78eea52..cef9d3c 100644 --- a/ts/servertools/classes.handlerstatic.ts +++ b/ts/servertools/classes.handlerstatic.ts @@ -36,7 +36,31 @@ export class HandlerStatic extends Handler { } // lets compute some paths - let filePath: string = requestPath.slice(req.route.path.length - 1); // lets slice of the root + // Extract the path using Express 5's params or fallback methods + let filePath: string; + if (req.params && req.params.splat !== undefined) { + // Express 5 wildcard route (/*splat) + // Handle array values - join them if array, otherwise use as-is + filePath = Array.isArray(req.params.splat) ? req.params.splat.join('/') : String(req.params.splat || ''); + } else if (req.params && req.params[0] !== undefined) { + // Numbered parameter fallback + filePath = Array.isArray(req.params[0]) ? req.params[0].join('/') : String(req.params[0] || ''); + } else if (req.baseUrl) { + // If there's a baseUrl, remove it from the path + filePath = requestPath.slice(req.baseUrl.length); + } else if (req.route && req.route.path === '/') { + // Root route - use full path minus leading slash + filePath = requestPath.slice(1); + } else { + // Fallback to the original slicing logic for compatibility + filePath = requestPath.slice(req.route.path.length - 1); + } + + // Ensure filePath is a string and has no leading slash + filePath = String(filePath || ''); + if (filePath.startsWith('/')) { + filePath = filePath.slice(1); + } if (requestPath === '') { console.log('replaced root with index.html'); filePath = 'index.html'; diff --git a/ts/servertools/tools.serviceworker.ts b/ts/servertools/tools.serviceworker.ts index b5ecc5b..6ac1df9 100644 --- a/ts/servertools/tools.serviceworker.ts +++ b/ts/servertools/tools.serviceworker.ts @@ -38,7 +38,7 @@ export const addServiceWorkerRoute = ( swVersionInfo = swDataFunc(); // the basic stuff - typedserverInstance.server.addRoute('/serviceworker{.*}', serviceworkerHandler); + typedserverInstance.server.addRoute('/serviceworker/*splat', serviceworkerHandler); // the typed stuff const typedrouter = new plugins.typedrequest.TypedRouter();