W WRNexusJS
Runtime · Package reference

@wrnexus/ssr

Secure HTML document rendering and SEO metadata.

v0.8.7Private registryRuntime

Install the package

After WorkRoot approves private registry access, install the release-aligned package:

bun add @wrnexus/ssr@0.8.7

Request preview access. Never put registry tokens in source control.

Server-side rendering: wraps a page's HTML body in a complete HTML document with a metadata-driven <head>.

Part of the WRNexusJS framework — an SSR-first, Bun-native full-stack web framework.

Overview

Pages in WRNexusJS return an HTML string for the body. @wrnexus/ssr takes that body and produces a full HTML document — building the <head> from page metadata and global SEO defaults, resolving canonical/Open Graph/Twitter tags, and injecting module preloads and <script type="module"> tags. It is deliberately server-only: nothing in this package touches the DOM or ships to the browser, keeping server code genuinely server-only. Reach for it on the server when turning a rendered page body into a response document.

bun add @wrnexus/ssr
Private package — the machine must be authenticated to the wrnexus npm org
(a read token in ~/.npmrc). Requires Bun (Node is not supported).

API

The package has a single export.

renderDocument(opts: RenderOptions): string

Renders a complete HTML document as a string, beginning with <!doctype html>. All metadata is HTML-escaped (via escapeHtml from @wrnexus/core), so a malicious title or description cannot break out of its element or attribute. The body is placed inside <div id="app">.

RenderOptions

FieldTypeDescription
metaPageMetaPage metadata for the document head (required).
bodystringRendered HTML for the body, placed inside #app (required).
seoSeoConfigGlobal SEO defaults, typically from wrnexus.config.ts.
urlURLCurrent request URL, used to resolve canonical/Open Graph URLs.
scriptsstring[]URLs of <script type="module"> tags to load (e.g. per-island chunks or the reactive runtime). Each also gets a <link rel="modulepreload">.
defaultTitlestringDefault document title used when meta.title is absent.
extraHeadstringRaw HTML injected at the end of <head> (trusted, framework-controlled — not escaped).
extraBodystringRaw HTML injected at the end of <body> (trusted, framework-controlled — not escaped).
htmlAttrsstringAttributes for the <html> element, e.g. data-theme="dark" (trusted).

PageMeta and SeoConfig come from @wrnexus/core. PageMeta is an alias of SeoConfig, whose fields are all optional:

type SeoConfig = {
  title?: string;
  titleTemplate?: string; // e.g. "%s — My Site"; %s is replaced with the page title
  description?: string;
  canonical?: string;
  canonicalBase?: string; // origin used to absolutize canonical/image URLs
  robots?: string;
  keywords?: string | string[];
  image?: string;
  siteName?: string;
  type?: string; // Open Graph type; defaults to "website"
  locale?: string;
  twitterCard?: string; // defaults to "summary"
  twitterSite?: string;
  themeColor?: string;
};

Metadata resolution

renderDocument merges page metadata (meta) over global defaults (seo), field by field, so per-page values win. Notable behavior:

  • Title: uses meta.title, else seo.title, else defaultTitle, else "WRNexusJS". When the page sets its own title and seo.titleTemplate contains %s, the template is applied.
  • Canonical / image URLs: resolved against canonicalBase (or the request url's origin) into absolute URLs when possible.
  • Keywords: an array is joined with ", ".
  • Emitted tags: <title>, and as applicable description, robots, keywords, theme-color, and canonical link, plus Open Graph (og:title, og:description, og:type, og:url, og:site_name, og:locale, og:image) and Twitter (twitter:card, twitter:title, twitter:description, twitter:image, twitter:site) meta tags. The document always includes charset, viewport, and a /favicon.ico icon link.

Usage

Render an SEO-ready application page

import { renderDocument } from "@wrnexus/ssr";

const html = renderDocument({
  meta: {
    title: "About Us",
    description: "Learn more about our team.",
  },
  seo: {
    titleTemplate: "%s — Acme",
    siteName: "Acme",
    canonicalBase: "https://acme.example",
    twitterSite: "@acme",
  },
  url: new URL("https://acme.example/about"),
  body: "<h1>About Us</h1>",
  scripts: ["/_wire/runtime.js", "/_wire/islands/about.js"],
  htmlAttrs: ' data-theme="dark"',
});

return new Response(html, {
  headers: { "content-type": "text/html; charset=utf-8" },
});

The produced document has <title>About Us — Acme</title>, the SEO/Open Graph/Twitter tags derived from the merged metadata, a modulepreload link and module <script> for each entry in scripts, and the body wrapped in <div id="app">.

Add trusted framework assets and boot data

Use extraHead and extraBody only for HTML generated by your application or the framework. User-provided values belong in meta, where they are escaped.

const html = renderDocument({
  meta: { title: "Dashboard", robots: "noindex" },
  body: dashboardHtml,
  url: ctx.url,
  extraHead: '<link rel="stylesheet" href="/_wrnexus/admin.css">',
  extraBody: `<script type="application/json" id="boot">${JSON.stringify(bootData).replaceAll("<", "\\u003c")}</script>`,
});

return new Response(html, { headers: { "content-type": "text/html; charset=utf-8" } });

Requirements / Notes

  • Server-only. This module never imports or touches the DOM and is safe to keep out of client bundles.
  • Depends on [@wrnexus/core](../core) for escapeHtml and the PageMeta / SeoConfig types.
  • Bun-only — like the rest of WRNexusJS, this package targets the Bun runtime (Node is not supported).

Complete TypeScript API

Generated from the exact installed package declarations.

import { PageMeta, SeoConfig } from '@wrnexus/core';
export { RpcContext, RpcHandlerOptions, RpcManifestContract, RpcParameterContract, RpcRequestPayload, createRpcHandler } from './rpc.js';
export { disposeRequestStores, renderStoreHydration, requestStoreContainer } from './store-context.js';
import '@wrnexus/store';

/**
 * @wrnexus/ssr — server-side rendering.
 *
 * Pages return an HTML string for the body; this module wraps that body in a
 * full document with a `<head>` built from page metadata. It is intentionally
 * isolated from any client runtime: nothing here touches the DOM or ships to
 * the browser, which keeps "server-only code" genuinely server-only.
 */

interface ScriptAsset {
    src: string;
    /** Module scripts are the default for backward compatibility. */
    type?: "module" | "classic";
    async?: boolean;
    defer?: boolean;
    integrity?: string;
    crossOrigin?: "anonymous" | "use-credentials";
    nonce?: string;
    attributes?: Record<string, string | boolean>;
}
type RenderScript = string | ScriptAsset;
interface PartialPrerenderResult {
    shell: string;
    regions: Array<{
        id: string;
        html: string;
    }>;
}
/** Extract compiler-emitted dynamic regions into a cacheable static shell. */
declare function partialPrerender(html: string, startIndex?: number): PartialPrerenderResult;
/** Stream the static shell first, followed by inert region templates for client insertion. */
declare function streamPartialDocument(result: PartialPrerenderResult, nonce?: string): ReadableStream<Uint8Array>;
interface RenderOptions {
    /** Page metadata for the document head. */
    meta: PageMeta;
    /** Global SEO defaults from `wrnexus.config.ts`. */
    seo?: SeoConfig;
    /** Current request URL, used to resolve canonical/Open Graph URLs. */
    url?: URL;
    /** Rendered HTML for the body (placed inside `#app`). */
    body: string;
    /**
     * URLs of `<script type="module">` tags to load (e.g. per-island chunks or
     * the reactive runtime). Only the scripts a page actually needs are passed.
     */
    scripts?: RenderScript[];
    /** Optional default document title used when meta.title is absent. */
    defaultTitle?: string;
    /** Raw HTML injected at the end of `<head>` (trusted, framework-controlled). */
    extraHead?: string;
    /** CSP nonce applied to framework-promoted `.wrn` style blocks. */
    styleNonce?: string;
    /** Raw HTML injected at the end of `<body>` (trusted, framework-controlled). */
    extraBody?: string;
    /** Attributes for the `<html>` element, e.g. ` data-theme="dark"` (trusted). */
    htmlAttrs?: string;
    /**
     * Optional application-authored full document shell. It must contain
     * `<html>`, `<head>`, and `<body>`. Framework metadata, assets, and scripts
     * are merged into it instead of wrapping the rendered body again.
     */
    documentTemplate?: string;
}
/**
 * Render a complete HTML document.
 *
 * Metadata is HTML-escaped so a malicious title/description can never break
 * out of its element or attribute.
 */
declare function renderDocument(opts: RenderOptions): string;
interface ExtractedWrnexusStyles {
    html: string;
    styles: string;
}
/**
 * Promote compiler-emitted `.wrn` style blocks out of rendered markup and into
 * the document head. They are emitted after global stylesheets, deduplicated by
 * stable id, ordered layout -> page -> component, and nonce-tagged for CSP.
 */
declare function extractWrnexusStyles(html: string, nonce?: string): ExtractedWrnexusStyles;
interface StreamRenderOptions extends Omit<RenderOptions, "body"> {
    body: string | Promise<string> | AsyncIterable<string>;
}
/**
 * Stream a complete document while preserving the exact head/body contract of
 * `renderDocument`. Async iterables can flush a shell, primary content, and
 * slower fragments without buffering the entire route.
 */
declare function renderDocumentStream(opts: StreamRenderOptions): ReadableStream<Uint8Array>;
declare function streamDocumentResponse(opts: StreamRenderOptions, init?: ResponseInit): Response;

export { type PartialPrerenderResult, type RenderOptions, type RenderScript, type ScriptAsset, type StreamRenderOptions, extractWrnexusStyles, partialPrerender, renderDocument, renderDocumentStream, streamDocumentResponse, streamPartialDocument };

Examples

Copy-ready examples from the installed package documentation.

Render an SEO-ready application page

import { renderDocument } from "@wrnexus/ssr";

const html = renderDocument({
  meta: {
    title: "About Us",
    description: "Learn more about our team.",
  },
  seo: {
    titleTemplate: "%s — Acme",
    siteName: "Acme",
    canonicalBase: "https://acme.example",
    twitterSite: "@acme",
  },
  url: new URL("https://acme.example/about"),
  body: "<h1>About Us</h1>",
  scripts: ["/_wire/runtime.js", "/_wire/islands/about.js"],
  htmlAttrs: ' data-theme="dark"',
});

return new Response(html, {
  headers: { "content-type": "text/html; charset=utf-8" },
});

Add trusted framework assets and boot data

const html = renderDocument({
  meta: { title: "Dashboard", robots: "noindex" },
  body: dashboardHtml,
  url: ctx.url,
  extraHead: '<link rel="stylesheet" href="/_wrnexus/admin.css">',
  extraBody: `<script type="application/json" id="boot">${JSON.stringify(bootData).replaceAll("<", "\\u003c")}</script>`,
});

return new Response(html, { headers: { "content-type": "text/html; charset=utf-8" } });