diff --git a/changelog.md b/changelog.md index da42f92..16cf0eb 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,13 @@ # Changelog +## 2025-12-05 - 7.10.1 - fix(typedserver) +Use smartserve ControllerRegistry for custom routes and remove custom route parsing + +- addRoute now delegates to plugins.smartserve.ControllerRegistry instead of building its own regex-based matcher +- Backwards compatibility: incoming smartserve IRequestContext is converted to a Request and ctx.params is attached to request.params before invoking the handler +- Removed internal IRegisteredRoute, customRoutes storage, and parseRouteParams helper +- Request handling now uses ControllerRegistry.matchRoute and registered controllers are compiled via ControllerRegistry.compileRoutes() + ## 2025-12-05 - 7.10.0 - feat(website-server) Add configurable ads.txt support to website server diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 7afbf5a..70bfa26 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: '7.10.0', + version: '7.10.1', description: 'A TypeScript-based project for easy serving of static files with support for live reloading, compression, and typed requests.' } diff --git a/ts/classes.typedserver.ts b/ts/classes.typedserver.ts index 4512878..65085ad 100644 --- a/ts/classes.typedserver.ts +++ b/ts/classes.typedserver.ts @@ -145,14 +145,6 @@ export interface IRouteHandler { (request: Request): Promise; } -export interface IRegisteredRoute { - pattern: string; - regex: RegExp; - paramNames: string[]; - method: THttpMethod; - handler: IRouteHandler; -} - export class TypedServer { // instance public options: IServerOptions; @@ -175,9 +167,6 @@ export class TypedServer { // File server for static files private fileServer: plugins.smartserve.FileServer; - // Custom route handlers (for addRoute API) - private customRoutes: IRegisteredRoute[] = []; - public lastReload: number = Date.now(); public ended = false; @@ -210,49 +199,18 @@ export class TypedServer { * @param handler - Async function that receives Request and returns Response or null */ public addRoute(path: string, method: THttpMethod, handler: IRouteHandler): void { - // Convert Express-style path to regex - const paramNames: string[] = []; - let regexPattern = path - // Handle named parameters :param - .replace(/:([a-zA-Z_][a-zA-Z0-9_]*)/g, (_, paramName) => { - paramNames.push(paramName); - return '([^/]+)'; - }) - // Handle wildcard *splat (matches everything including slashes) - .replace(/\*([a-zA-Z_][a-zA-Z0-9_]*)/g, (_, paramName) => { - paramNames.push(paramName); - return '(.*)'; + // Delegate to smartserve's ControllerRegistry + plugins.smartserve.ControllerRegistry.addRoute(path, method, async (ctx: plugins.smartserve.IRequestContext) => { + // Convert context to Request for backwards compatibility + const request = new Request(ctx.url.toString(), { + method: ctx.method, + headers: ctx.headers, }); - - // Ensure exact match - regexPattern = `^${regexPattern}$`; - - this.customRoutes.push({ - pattern: path, - regex: new RegExp(regexPattern), - paramNames, - method, - handler, + (request as any).params = ctx.params; + return handler(request); }); } - /** - * Parse route parameters from a path using a registered route - */ - private parseRouteParams( - route: IRegisteredRoute, - pathname: string - ): Record | null { - const match = pathname.match(route.regex); - if (!match) return null; - - const params: Record = {}; - route.paramNames.forEach((name, index) => { - params[name] = match[index + 1]; - }); - return params; - } - /** * inits and starts the server */ @@ -650,18 +608,6 @@ export class TypedServer { } } - // Custom routes (registered via addRoute) - for (const route of this.customRoutes) { - if (route.method === 'ALL' || route.method === method) { - const params = this.parseRouteParams(route, path); - if (params !== null) { - (request as any).params = params; - const response = await route.handler(request); - if (response) return response; - } - } - } - // HTML injection for reload (if enabled) if (this.options.injectReload && this.options.serveDir) { const response = await this.handleHtmlWithInjection(request);