Files
deepseek-harness/packages/host/frontend-static

description, kind
description kind
SPA dist server for the Web shell: claims the webserver fallback seat and serves the built frontend with traversal rejection and SPA index fallback. package-reference

@deepseek-ai/dsh-host-frontend-static

English | 中文

Summary

Browsers get the built Web shell from dsh-host-frontend-static: it claims the webserver fallback seat and serves the built frontend directory with locked semantics — only the dist root and the configured index path render index.html (HTTP 200), other existing files are served directly, an absent or non-file target inside the dist root — including a missing configured index — returns an empty 404, traversal outside the dist root is 403, unknown extensions ship as application/octet-stream, and non-GET/HEAD without a matching named route is 405. Every successful index response is rendered through the webserver's renderIndex, which is how the boot manifest reaches the page. The fallback seat is single-owner: a second claim throws, and unloading the plugin releases the seat.

Table of Contents


Use this package

Compose this plugin in a browser-facing host that serves the built Web shell: it claims the webserver's fallback seat and answers every request no named route matches. It needs one config value — where the built frontend's index.html lives.

Minimal configuration

- name: '@deepseek-ai/dsh-host-frontend-static'
  config:
    distIndex: /absolute/path/to/dist/index.html

distIndex is an assembly fact of the composing application: dsh-web-app resolves it through the frontend package's exports and mounts this plugin; a deployment never hardcodes it.

What the server enforces

Requests are served from the dist root (the directory containing distIndex). The dist root and the configured index path render index.html with HTTP 200; any other existing file is served directly with its MIME type, and unknown extensions ship as application/octet-stream. A path that resolves outside the root is rejected with 403, so a crafted path cannot read files above the dist. An absent or non-file target inside the dist root — a missing file, a directory, or a missing configured index — returns an empty 404. Non-GET/HEAD requests without a matching named route are answered 405. Every successful index response is rendered through the webserver's renderIndex, so the boot manifest reaches the page on / and on the configured index path.

Root and configured-index responses call ctx.connection.authorizeIndex before reading HTML. A valid process token receives a 303 redirect plus the persistent browser cookie; an existing valid cookie serves the index; every other index request receives the Connection-owned 401 response. Non-index files remain public static assets. Connection owns the token, cookie, expiry, and signing-record semantics.

Observable failures

Traversal returns 403 rather than an error page. An absent or non-file target inside the dist root returns an empty 404, so a stale link or a mistyped pathname is an explicit failure rather than a silent SPA fallback. Claiming the seat twice throws, and while the seat is unclaimed the webserver answers 404 — which is what a browser sees if this plugin's fiber is disposed.


Understand the implementation

Implementation internals — click to expand

Design concept

The package is one function plugin around serveStatic: apply resolves the dist root from distIndex, builds a renderIndex closure that runs ctx.webServer.renderIndex over the raw index.html, and registers the fallback handler under an effect scope. The seat is single-owner by the webserver's contract — a second registration throws — and effect-scoped, so disposing the fiber releases the seat.

The traversal fence

serveStatic normalizes the requested pathname and joins it to the dist root, then requires the target to be the root itself or stay under it. The check uses sep rather than / because resolve() emits backslash paths on Windows, where a / suffix would reject every legitimate subpath as traversal.

Source map

File Role
src/index.ts serveStatic and apply: fallback claim, traversal rejection, index rendering, MIME table

Further Exploration

Read these when the serving contract is not enough: the seat owner's contract, then the composition that resolves the dist and the subsystem reference.


Model Experience

None, as the SPA dist server answers browser asset requests and registers nothing model-facing.

KV Cache effect

None; this package neither assembles nor sends a provider request.

Known Limitations and Deferred Work

These limits define when a served asset class is not yet covered. They are current package constraints, not a task backlog.

  • The starter MIME table is minimal — it covers the Vite-emitted asset set plus the shipped PWA manifest; other extensions fall back to application/octet-stream until an asset class ships.
  • Pathname routing is explicit — the current client enters through the root or configured index path and has no History API pathname routes. Adding one requires an explicit server rule and real-composition coverage rather than a broad fallback for every miss.

Dev Note

Working context for maintainers — click to expand

None.