From 66c556e7b0f0bb8826905340dd5a1d21b913d1df Mon Sep 17 00:00:00 2001 From: Kris Zyp Date: Fri, 17 Jul 2026 14:22:42 -0600 Subject: [PATCH 1/2] docs: document middleware host and path routing --- reference/components/plugin-api.md | 5 +++- reference/http/api.md | 47 ++++++++++++++++++++---------- reference/http/overview.md | 19 ++++++++++++ release-notes/v5-lincoln/5.2.md | 6 ++++ 4 files changed, 60 insertions(+), 17 deletions(-) diff --git a/reference/components/plugin-api.md b/reference/components/plugin-api.md index bf61d24d..ce801923 100644 --- a/reference/components/plugin-api.md +++ b/reference/components/plugin-api.md @@ -38,9 +38,12 @@ General plugin configuration options: - `files` — `string | string[] | FilesOptionObject` _(optional)_ — Glob pattern(s) for files and directories handled by the plugin's default `EntryHandler`. Pattern rules: - Cannot contain `..` or start with `/` - `.` or `./` is transformed to `**/*` automatically -- `urlPath` — `string` _(optional)_ — Base URL path prepended to resolved `files` entries. Cannot contain `..`. If starts with `./` or is `.`, the plugin name is automatically prepended +- `urlPath` — `string` _(optional)_ — Base URL path prepended to resolved `files` entries and used to route the plugin's HTTP, WebSocket, and upgrade handlers. Cannot contain `..`. If it starts with `./` or is `.`, the plugin name is automatically prepended. +- `host` — `string` _(optional)_ — Virtual hostname used to route the plugin's HTTP, WebSocket, and upgrade handlers - `timeout` — `number` _(optional)_ — Timeout in milliseconds for plugin operations. Takes precedence over the plugin's `defaultTimeout` and the system default (30 seconds) +`urlPath` and `host` are available in v5.2.0. Harper automatically passes them to handlers registered through the scoped `server` API. See [Middleware routing](../http/overview#middleware-routing) for an example and [`HttpOptions`](../http/api#httpoptions) for matching behavior. + ### File Entries ```yaml diff --git a/reference/http/api.md b/reference/http/api.md index 610c3f12..75c7136b 100644 --- a/reference/http/api.md +++ b/reference/http/api.md @@ -40,11 +40,31 @@ To continue the middleware chain, call `next(request)`. To short-circuit, return ### `HttpOptions` -| Property | Type | Default | Description | -| ------------ | ------- | ----------------- | --------------------------------------------- | -| `runFirst` | boolean | `false` | Insert this handler at the front of the chain | -| `port` | number | `http.port` | Target the HTTP server on this port | -| `securePort` | number | `http.securePort` | Target the HTTPS server on this port | + (`name`, `before`, `after`, `urlPath`, and `host`) + +| Property | Type | Default | Description | +| ------------ | ------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | +| `name` | string | Registering component's name | Name this middleware entry so other entries can position themselves relative to it | +| `before` | string | - | Run this entry before the named middleware entry | +| `after` | string | - | Run this entry after the named middleware entry | +| `urlPath` | string | - | Only handle requests whose pathname matches this prefix. Harper removes the prefix before passing the request to the handler. | +| `host` | string | - | Only handle requests whose `Host` header matches this virtual hostname | +| `runFirst` | boolean | `false` | Deprecated. Insert this handler at the front of the chain. Use `before` or `after` for explicit ordering. | +| `port` | number | `http.port` | Target the HTTP server on this port | +| `securePort` | number | `http.securePort` | Target the HTTPS server on this port | + +`host` and `urlPath` create a routed middleware chain. When both are present, both must match. Harper selects the most specific matching chain in this order: host and path, host only, then path only. Longer path prefixes take precedence. A request that matches no routed chain uses the default chain. + +```js +server.http(handleAdminRequest, { + name: 'admin', + host: 'admin.example.com', + urlPath: '/api', + after: 'authentication', +}); +``` + +For this example, a request to `https://admin.example.com/api/users` reaches `handleAdminRequest` with a pathname of `/users`. ### `HttpServer` @@ -162,12 +182,11 @@ type WsListener = (ws: WebSocket, request: Request, chainCompletion: Promise + +Harper can route middleware by URL prefix, virtual hostname, or both. Set `urlPath` or `host` in a component's `config.yaml` to create a routed middleware chain without writing dispatch code: + +```yaml +rest: + host: api.example.com + urlPath: /v1 +static: + files: 'web/**' + host: www.example.com +``` + +The `rest` handler receives requests under `api.example.com/v1`; Harper removes `/v1` from the pathname before invoking the chain. The `static` handler receives requests for `www.example.com`. Unmatched requests use the default middleware chain. + +Custom components can configure the same behavior programmatically with `server.http(listener, { host, urlPath })`. See [`HttpOptions`](./api#httpoptions) for matching priority and middleware ordering options. + ## Protocols Served The HTTP server handles multiple protocols on the same port: diff --git a/release-notes/v5-lincoln/5.2.md b/release-notes/v5-lincoln/5.2.md index 8cea990a..62373196 100644 --- a/release-notes/v5-lincoln/5.2.md +++ b/release-notes/v5-lincoln/5.2.md @@ -19,3 +19,9 @@ Vector searches combined with filters now evaluate the filter during HNSW graph ### Replicated `set_configuration` The `set_configuration` operation now accepts `"replicated": true` to apply a configuration change to all cluster nodes in a single Operations API call, with per-node outcomes reported in the response's `replicated` array. Only cluster-appropriate parameters should be replicated — see [Configuration Operations](/reference/v5/configuration/operations#set-configuration). + +## HTTP + +### Middleware routing and ordering + +Components can now declare `host` and `urlPath` in `config.yaml`, or pass them to `server.http()`, `server.ws()`, and `server.upgrade()`, to create middleware chains routed by virtual hostname, URL prefix, or both. The new `name`, `before`, and `after` options provide explicit middleware ordering. See [HTTP middleware routing](/reference/v5/http/overview#middleware-routing) and [`HttpOptions`](/reference/v5/http/api#httpoptions). From 382934e93c70a48296bd64014b69f3f0e87b486f Mon Sep 17 00:00:00 2001 From: Kris Zyp Date: Mon, 20 Jul 2026 20:09:51 -0600 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- reference/http/api.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reference/http/api.md b/reference/http/api.md index 75c7136b..2674f7ca 100644 --- a/reference/http/api.md +++ b/reference/http/api.md @@ -182,7 +182,7 @@ type WsListener = (ws: WebSocket, request: Request, chainCompletion: Promise