1160 lines
77 KiB
TypeScript
1160 lines
77 KiB
TypeScript
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
||
import { execFileSync } from "node:child_process";
|
||
import { join, resolve } from "node:path";
|
||
import { format } from "prettier";
|
||
|
||
const root = resolve(import.meta.dir, "..");
|
||
const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
||
const version = pkg.wrnexus.version as string;
|
||
const pages = join(root, "app", "pages");
|
||
const docs = join(root, "docs");
|
||
const pub = join(root, "public");
|
||
mkdirSync(docs, { recursive: true });
|
||
const packageNames = [...Object.keys(pkg.dependencies), ...Object.keys(pkg.devDependencies)]
|
||
.filter((name) => name.startsWith("@wrnexus/"))
|
||
.map((name) => name.split("/")[1]!)
|
||
.filter((name, index, all) => all.indexOf(name) === index)
|
||
.sort();
|
||
const packageCount = packageNames.length;
|
||
const cliEntry = join(root, "node_modules", "@wrnexus", "cli", "dist", "index.js");
|
||
const cliHelp = execFileSync(process.execPath, [cliEntry, "--help"], {
|
||
cwd: root,
|
||
encoding: "utf8",
|
||
env: { ...process.env, WRNEXUS_DISABLE_UPDATE_CHECK: "1" },
|
||
}).trim();
|
||
const cliReference = `# Complete CLI command reference
|
||
|
||
This section is generated from the installed \`@wrnexus/cli@${version}\` executable. It is the canonical command inventory for this release.
|
||
|
||
\`\`\`text
|
||
${cliHelp}
|
||
\`\`\`
|
||
|
||
## CLI workflows with expected output
|
||
|
||
Commands below are copy-ready. Paths, ports, counts, and timings vary by project; the shown output identifies the success condition to check.
|
||
|
||
### Create, check, build, and preview an application
|
||
|
||
\`\`\`bash
|
||
bunx @wrnexus/cli@${version} create my-app
|
||
cd my-app
|
||
bun install
|
||
bunx wrnexus typecheck .
|
||
bunx wrnexus build .
|
||
bunx wrnexus preview . --port=3000
|
||
\`\`\`
|
||
|
||
Expected output:
|
||
|
||
\`\`\`text
|
||
✓ Application types are valid
|
||
✓ Runtime: .../dist/reactive.js
|
||
✓ Styles: .../dist/styles.css
|
||
✓ Server: .../dist/server.js
|
||
Run it: bun .../dist/server.js
|
||
\`\`\`
|
||
|
||
### Generate framework files and committed application types
|
||
|
||
\`\`\`bash
|
||
bunx wrnexus generate page Dashboard
|
||
bunx wrnexus generate component status-card
|
||
bunx wrnexus generate api health
|
||
bunx wrnexus generate schema account
|
||
bunx wrnexus generate routes
|
||
bunx wrnexus generate types .
|
||
\`\`\`
|
||
|
||
Expected output includes created source paths followed by:
|
||
|
||
\`\`\`text
|
||
✓ Generated app/routes.gen.ts (... routes)
|
||
✓ Generated .../app/types/wrnexus.generated.d.ts (... routes, ... components)
|
||
\`\`\`
|
||
|
||
### Run development and production-runtime modes
|
||
|
||
\`\`\`bash
|
||
bunx wrnexus dev . --port=3000
|
||
bunx wrnexus dev . --services --services-port=3099
|
||
bunx wrnexus dev . --production-runtime --port=3000
|
||
\`\`\`
|
||
|
||
Expected output reports the active profile, discovered plugins/routes, generated cache path, and listening URL. Production-runtime mode rebuilds and reloads the exact production artifact.
|
||
|
||
### Database lifecycle
|
||
|
||
\`\`\`bash
|
||
bunx wrnexus db status
|
||
bunx wrnexus db new create_accounts --from-models
|
||
bunx wrnexus db migrate
|
||
bunx wrnexus db generate
|
||
bunx wrnexus db seed
|
||
\`\`\`
|
||
|
||
Expected output identifies the selected profile/dialect, migration state, applied migration names, and generated typed query files. Run \`db rollback\` only when intentionally reverting the latest migration.
|
||
|
||
### Diagnose, inspect, and enforce contracts
|
||
|
||
\`\`\`bash
|
||
bunx wrnexus doctor .
|
||
bunx wrnexus typecheck .
|
||
bunx wrnexus compatibility check .
|
||
bunx wrnexus contracts check .
|
||
bunx wrnexus security audit .
|
||
bunx wrnexus inspect packages .
|
||
bunx wrnexus inspect routes .
|
||
bunx wrnexus inspect component Navbar .
|
||
bunx wrnexus analyze .
|
||
\`\`\`
|
||
|
||
Successful checks exit with status 0. Inspect commands print the resolved package, route, component, asset, runtime, style, migration, or bundle contract without changing the application.
|
||
|
||
### Tests, API artifacts, SDKs, and deployment manifests
|
||
|
||
\`\`\`bash
|
||
bunx wrnexus test unit .
|
||
bunx wrnexus test component .
|
||
bunx wrnexus test api .
|
||
bunx wrnexus test browser .
|
||
bunx wrnexus api generate .
|
||
bunx wrnexus api docs .
|
||
bunx wrnexus sdk generate typescript .
|
||
bunx wrnexus deploy docker .
|
||
\`\`\`
|
||
|
||
Test commands return the underlying suite summary and a nonzero status on failure. API/SDK/deploy commands report each generated artifact; review and commit generated files after validation.
|
||
|
||
### Workspaces and environments
|
||
|
||
\`\`\`bash
|
||
bunx wrnexus workspace company-platform
|
||
cd company-platform
|
||
bunx wrnexus workspace add reports --domain=reports.localhost
|
||
bunx wrnexus gateway --port=3000
|
||
bunx wrnexus production . --prepare-only
|
||
bunx wrnexus staging .
|
||
\`\`\`
|
||
|
||
Expected output lists created apps, domain mappings, selected environment/profile, build and migration decisions, and the gateway address.
|
||
|
||
### Internationalization, native targets, MCP, and support bundles
|
||
|
||
\`\`\`bash
|
||
bunx wrnexus i18n extract .
|
||
bunx wrnexus i18n validate .
|
||
bunx wrnexus generate mobile
|
||
bunx wrnexus mobile compile
|
||
bunx wrnexus native list
|
||
bunx wrnexus mcp .
|
||
bunx wrnexus report . --file=app/pages/index.wrn
|
||
\`\`\`
|
||
|
||
Expected output identifies extracted/validated translation keys, generated native routes, available capabilities, MCP stdio startup, or the sanitized reproduction archive. MCP uses stdio, so protocol messages—not a web URL—are its normal runtime output.
|
||
|
||
### Safe upgrades
|
||
|
||
\`\`\`bash
|
||
bunx wrnexus update . --latest --dry-run
|
||
bunx wrnexus update . --latest
|
||
\`\`\`
|
||
|
||
The dry run previews dependency and migration changes. A real update prints the source and target versions, backup directory, each migration action, installation result, and verification result. Commit or back up the application before upgrading.`;
|
||
const uiReferencePath = join(root, "node_modules", "@wrnexus", "ui", "component-reference.json");
|
||
const uiReference = existsSync(uiReferencePath)
|
||
? (JSON.parse(readFileSync(uiReferencePath, "utf8")) as {
|
||
count: number;
|
||
components: Array<{
|
||
name: string;
|
||
mount: string;
|
||
category: string;
|
||
purpose: string;
|
||
source: string;
|
||
props: Array<{ name: string; type: string; required: boolean; default: string | null }>;
|
||
slots: string[];
|
||
events: string[];
|
||
}>;
|
||
})
|
||
: undefined;
|
||
const uiReferenceText = uiReference
|
||
? uiReference.components
|
||
.map(
|
||
(component) =>
|
||
`### ${component.name}\nShowcase: https://component.wrnexusjs.dev/\nMount: <${component.mount} /> (legacy: data-component="${component.mount}")\nCategory: ${component.category}\nPurpose: ${component.purpose}\nProps: ${component.props.length ? component.props.map((prop) => `${prop.name}: ${prop.type}${prop.required ? " (required)" : ` = ${prop.default}`}`).join(", ") : "none"}\nSlots: ${component.slots.join(", ") || "none"}\nEvents: ${component.events.join(", ") || "none"}`,
|
||
)
|
||
.join("\n\n")
|
||
: "UI component reference unavailable; install the release-aligned @wrnexus/ui package.";
|
||
|
||
async function writeFormatted(path: string, source: string) {
|
||
writeFileSync(path, await format(source, { filepath: path }));
|
||
}
|
||
|
||
const esc = (s: string) => s.replaceAll("{", "{").replaceAll("}", "}");
|
||
const code = (s: string) =>
|
||
`<pre><code>${esc(s).replaceAll("<", "<").replaceAll(">", ">")}</code></pre>`;
|
||
|
||
const navigation = [
|
||
["/getting-started", "Get started"],
|
||
["/packages", "Packages"],
|
||
["https://component.wrnexusjs.dev/", "Components"],
|
||
["/language", "Language"],
|
||
["/architecture", "Architecture"],
|
||
] as const;
|
||
|
||
const documentationNavigation = [
|
||
...navigation,
|
||
["/tutorial", "Tutorial"],
|
||
["/guides/project-structure", "Guides"],
|
||
["/examples", "Examples"],
|
||
["/search", "Search"],
|
||
] as const;
|
||
|
||
const packageNavigation = packageNames
|
||
.map((name) => `<a href="/packages/${name}">@wrnexus/${name}</a>`)
|
||
.join("");
|
||
const sectionNavigation = `<aside class="docs-section-menu" aria-label="Documentation sections">
|
||
<nav>
|
||
<section><strong>Get started</strong><a href="/getting-started">Quick start</a><a href="/tutorial">Tutorial</a><a href="/guides/full-stack-auth-demo">Auth dashboard demo</a><a href="/guides/project-structure">Project structure</a><a href="/guides/configuration-and-profiles">Configuration</a></section>
|
||
<section><strong>Build</strong><a href="/guides/pages-and-components">Pages and components</a><a href="/guides/routing">Routing</a><a href="/guides/server-data">Server data</a><a href="/guides/forms-and-validation">Forms and validation</a><a href="/guides/database">Database</a></section>
|
||
<section><strong>Auth and security</strong><a href="/guides/authentication">Authentication</a><a href="/guides/authorization">Authorization</a><a href="/guides/security">Application security</a><a href="/security">Security policy</a></section>
|
||
<section><strong>Reference</strong><a href="/packages">Packages overview</a><a href="/packages/cli">CLI</a><a href="/language">.wrn language</a><a href="https://component.wrnexusjs.dev/">Components</a><a href="/examples">Examples</a></section>
|
||
<section class="package-menu"><strong>Packages</strong>${packageNavigation}</section>
|
||
</nav>
|
||
</aside>`;
|
||
|
||
function documentationFrame(body: string): { body: string; toc: string } {
|
||
const headings: Array<{ id: string; title: string; level: number }> = [];
|
||
const used = new Set<string>();
|
||
const framed = body.replace(
|
||
/<h([23])(\s+id="([^"]+)")?>([\s\S]*?)<\/h\1>/g,
|
||
(_match, levelText, idAttribute, existingId, rawTitle) => {
|
||
const title = rawTitle
|
||
.replace(/<[^>]+>/g, "")
|
||
.replace(/&[^;]+;/g, " ")
|
||
.trim();
|
||
let id =
|
||
existingId ||
|
||
title
|
||
.toLowerCase()
|
||
.replace(/[^a-z0-9]+/g, "-")
|
||
.replace(/^-|-$/g, "") ||
|
||
"section";
|
||
const base = id;
|
||
let suffix = 2;
|
||
while (used.has(id)) id = `${base}-${suffix++}`;
|
||
used.add(id);
|
||
headings.push({ id, title, level: Number(levelText) });
|
||
return `<h${levelText} id="${id}">${rawTitle}</h${levelText}>`;
|
||
},
|
||
);
|
||
const toc = headings
|
||
.map(({ id, title, level }) => `<a class="toc-level-${level}" href="#${id}">${title}</a>`)
|
||
.join("");
|
||
return { body: framed, toc };
|
||
}
|
||
|
||
function shell(title: string, description: string, body: string, section = "Documentation") {
|
||
const nav = navigation.map(([href, label]) => `<a href="${href}">${label}</a>`).join("");
|
||
const mobileNav = documentationNavigation
|
||
.map(([href, label]) => `<a href="${href}">${label}</a>`)
|
||
.join("");
|
||
const breadcrumbs =
|
||
title === "Home"
|
||
? ""
|
||
: `<nav class="breadcrumbs" aria-label="Breadcrumb"><a href="/">Home</a><span aria-hidden="true">/</span><span>${section}</span><span aria-hidden="true">/</span><span aria-current="page">${title}</span></nav>`;
|
||
const framed = documentationFrame(body);
|
||
return `page ${title.replace(/[^A-Za-z0-9]/g, "") || "Guide"} {
|
||
seo {
|
||
title = "${title.replaceAll('"', "'")}"
|
||
description = "${description.replaceAll('"', "'")}"
|
||
canonical = "https://wrnexusjs.dev${routeFor(title)}"
|
||
}
|
||
view {
|
||
<a href="#main" class="skip-link">Skip to content</a>
|
||
<div class="docs-shell">
|
||
<header class="topbar"><a class="brand" href="/"><span>W</span> WRNexusJS</a><nav aria-label="Primary">${nav}</nav><div class="topbar-actions"><a class="preview-pill" href="/access">Preview · v${version}</a><button data-wire-theme-toggle class="theme-button" aria-label="Toggle color theme" title="Toggle color theme">◐</button></div></header>
|
||
<div class="mobile-doc-nav"><details><summary>Browse documentation</summary><nav>${mobileNav}</nav></details></div>
|
||
<main id="main" class="portal-main docs-layout docs-layout--navigation">${sectionNavigation}<div class="docs-reading-column">${breadcrumbs}${framed.body}</div><aside class="on-this-page"><h2>On this page</h2><nav>${framed.toc || '<a href="#main">Overview</a>'}</nav></aside></main>
|
||
<footer><div class="footer-brand"><span class="footer-mark" aria-hidden="true">W</span><p><strong>WRNexusJS ${version}</strong><span>Server-first documentation for the Bun-native framework.</span></p></div><nav aria-label="Footer"><a href="/access">Request access</a><a href="/license">License</a><a href="/security">Security</a><a href="/support">Support</a><a href="/llms.txt">AI guide</a></nav><p class="footer-meta">Created by <a href="https://workroot.in/">WorkRoot</a> · Private Developer Preview</p></footer>
|
||
</div>
|
||
}
|
||
}`;
|
||
}
|
||
|
||
function marketingShell(description: string, body: string) {
|
||
const codeCard = `<div class="code-window"><span>app/pages/dashboard.wrn</span><pre><code>page Dashboard {
|
||
ssr { api tasks GET /api/tasks { return tasks } }
|
||
view {
|
||
<main>
|
||
<h1>Tasks</h1>
|
||
{#each tasks as task}
|
||
<article>{task.title}</article>
|
||
{:empty}
|
||
<p>Nothing waiting.</p>
|
||
{/each}
|
||
</main>
|
||
}
|
||
}</code></pre></div>`;
|
||
const marketingBody = body
|
||
.replace("hero portal-hero", "hero marketing-hero")
|
||
.replace(
|
||
"Packages require approved private-registry access. No public installation command is currently available.",
|
||
"Private developer preview. Request access to the package registry.",
|
||
)
|
||
.replace("</section>", `${codeCard}</section>`);
|
||
return `page Home {
|
||
seo {
|
||
title = "WRNexusJS — Bun-native server-first framework"
|
||
description = "${description.replaceAll('"', "'")}"
|
||
canonical = "https://wrnexusjs.dev/"
|
||
}
|
||
view {
|
||
<a href="#main" class="skip-link">Skip to content</a>
|
||
<div class="docs-shell marketing-shell">
|
||
<header class="topbar marketing-header"><a class="brand" href="/"><span>W</span> WRNexusJS</a><nav aria-label="Primary"><a href="/getting-started">Get started</a><a href="/packages">Packages</a><a href="https://component.wrnexusjs.dev/">Components</a><a href="/language">Language</a><a href="/architecture">Architecture</a></nav><div class="topbar-actions"><a class="preview-pill" href="/access">Private preview · v${version}</a><button data-wire-theme-toggle class="theme-button" aria-label="Toggle color theme">◐</button></div></header>
|
||
<div class="marketing-mobile-nav"><details><summary>Menu</summary><nav><a href="/getting-started">Get started</a><a href="/packages">Packages</a><a href="https://component.wrnexusjs.dev/">Components</a><a href="/language">Language</a><a href="/architecture">Architecture</a><a href="/tutorial">Tutorial</a><a href="/examples">Examples</a></nav></details></div>
|
||
<main id="main" class="marketing-main">${marketingBody}</main>
|
||
<footer><div class="footer-brand"><span class="footer-mark" aria-hidden="true">W</span><p><strong>WRNexusJS ${version}</strong><span>Build from the server. Ship only what matters.</span></p></div><nav aria-label="Footer"><a href="/getting-started">Documentation</a><a href="/roadmap">Roadmap</a><a href="/security">Security</a><a href="/support">Support</a><a href="/llms.txt">AI guide</a></nav><p class="footer-meta">Bun-native · Created by <a href="https://workroot.in/">WorkRoot</a></p></footer>
|
||
</div>
|
||
}
|
||
}`;
|
||
}
|
||
|
||
const slugs: Record<string, string> = {
|
||
Home: "",
|
||
Packages: "/packages",
|
||
"Getting started": "/getting-started",
|
||
Tutorial: "/tutorial",
|
||
Architecture: "/architecture",
|
||
"The .wrn language": "/language",
|
||
};
|
||
function routeFor(title: string) {
|
||
return (
|
||
slugs[title] ??
|
||
`/${title
|
||
.toLowerCase()
|
||
.replace(/[^a-z0-9]+/g, "-")
|
||
.replace(/^-|-$/g, "")}`
|
||
);
|
||
}
|
||
function page(route: string, title: string, description: string, body: string, section?: string) {
|
||
const path = route === "/" ? join(pages, "index.wrn") : join(pages, `${route.slice(1)}.wrn`);
|
||
mkdirSync(resolve(path, ".."), { recursive: true });
|
||
slugs[title] = route;
|
||
writeFileSync(path, shell(title, description, body, section));
|
||
}
|
||
|
||
const status = `<Badge class="status status-beta" label="Private Developer Preview" variant="info" />`;
|
||
writeFileSync(
|
||
join(pages, "index.wrn"),
|
||
marketingShell(
|
||
"WRNexusJS is a Bun-native, SSR-first full-stack framework using the .wrn component language.",
|
||
`<section class="hero portal-hero">${status}<p class="eyebrow">WRNexusJS v${version}</p><h1>Build from the server.<br><em>Ship only what matters.</em></h1><p>WRNexusJS is an SSR-first, Bun-native full-stack framework. Build typed pages, APIs, validated forms, realtime rooms, secure sessions, workspaces, and optional mobile experiences with the <code>.wrn</code> component language.</p><div class="actions"><a class="primary" href="/access">Request preview access</a><a href="/getting-started">Read the preview docs</a></div><p class="access-note">Packages require approved private-registry access. No public installation command is currently available.</p></section>
|
||
<section><h2>Why WRNexusJS</h2><div class="feature-grid"><article><h3>Server-first rendering</h3><p>Useful HTML is rendered first; reactive scopes hydrate only where declared.</p></article><article><h3><code>.wrn</code> components</h3><p>Pages, layouts, props, state, events, server loops, and directives live in a focused language.</p></article><article><h3>Bun-native runtime</h3><p>The runtime is Bun. Node compatibility is not claimed.</p></article><article><h3>Typed data and validation</h3><p>Database queries and shared validation connect server routes to forms.</p></article><article><h3>Integrated security</h3><p>CSP, CSRF, sessions, authorization, encryption, and safe output are framework primitives.</p></article><article><h3>Realtime and workspaces</h3><p>Rooms, Redis pub/sub, and multi-app gateways support live and isolated applications.</p></article></div></section>
|
||
<section><h2>A small full-stack flow</h2>${code(`// app/schemas/contact.ts\nimport { v } from "@wrnexus/validation";\nexport default v.object({ email: v.string().email(), message: v.string().min(10) });\n\n// app/api/contacts.ts\nimport schema from "../schemas/contact";\nimport { parseBody } from "@wrnexus/validation";\nexport const POST = async (ctx) => {\n const result = await parseBody(schema, ctx.req);\n return result.ok ? Response.json({ ok: true }, { status: 201 }) : result.response;\n};`)}</section>
|
||
<section><h2>Request lifecycle</h2><ol class="lifecycle"><li><strong>Request</strong><span>Security headers and request limits</span></li><li><strong>Middleware</strong><span>Authentication, policy, and context</span></li><li><strong>File route</strong><span>Page or API handler</span></li><li><strong>Compiler + SSR</strong><span>Safe HTML and scoped runtime</span></li><li><strong>Response</strong><span>HTML, JSON, stream, or realtime upgrade</span></li></ol></section>
|
||
<section><h2>Production proof</h2><div class="feature-grid"><article><h3><a href="https://workroot.in/">WorkRoot</a></h3><p>Public creator/company site and approved WRNexusJS production showcase.</p></article><article><h3><a href="https://wrnexusjs.dev/">wrnexusjs.dev</a></h3><p>This documentation application runs WRNexusJS ${version}.</p></article></div><p><a href="/showcase">View deployment notes and showcase status →</a></p></section>
|
||
<section><h2>Capability status</h2><div class="table-wrap"><table><thead><tr><th>Capability</th><th>Status</th><th>Details</th></tr></thead><tbody><tr><td>SSR, routing, compiler, APIs</td><td>Preview</td><td>Installed in ${version}; public support policy pending.</td></tr><tr><td>Mobile/native</td><td>Experimental</td><td>Capacitor compatibility and native generation have platform limitations.</td></tr><tr><td>Durable queues</td><td>Experimental</td><td>Production durability requires an appropriate driver strategy.</td></tr></tbody></table></div></section>
|
||
<section><h2>Continue exploring</h2><div class="actions"><a href="/packages">Explore ${packageCount} packages</a><a href="/changelog">Release notes</a><a href="/roadmap">Roadmap</a><a href="/support">Support and access</a></div></section>`,
|
||
),
|
||
);
|
||
|
||
page(
|
||
"/access",
|
||
"Access",
|
||
"Request access to the WRNexusJS private developer preview.",
|
||
`<article class="documentation prose standalone">${status}<h1>Request preview access</h1><p>WRNexusJS ${version} packages are not available from the public npm registry. Installation requires approval and private registry credentials supplied by WorkRoot. Never paste registry tokens into source control, issue reports, or support messages.</p><h2>Request process</h2><ol><li>Contact WorkRoot through the public contact path at <a href="https://workroot.in/">workroot.in</a>.</li><li>Describe the application, team, expected deployment, and Bun environment.</li><li>After approval, follow the registry instructions supplied privately.</li><li>Use the canonical scaffold command below only after authentication.</li></ol>${code(`bunx @wrnexus/cli@${version} create my-app`)}<p>Access approval, response time, licensing terms, and support level remain owner-controlled. This site does not collect access requests directly.</p></article>`,
|
||
"Status",
|
||
);
|
||
|
||
page(
|
||
"/getting-started",
|
||
"Getting started",
|
||
"Build and run a first WRNexusJS application after receiving private preview access.",
|
||
`<article class="documentation prose standalone"><span class="status status-beta">Preview guide · v${version}</span><h1>Build a contact inbox</h1><p>This path creates a server-rendered page, validated API route, middleware, and realtime next step. It requires approved registry access and Bun 1.3.x; this site was verified with Bun 1.3.14.</p><h2 id="create">1. Create the project</h2>${code(`bunx @wrnexus/cli@${version} create my-app\ncd my-app\nbun install\nbun run dev`)}<h2 id="structure">2. Know the structure</h2>${code(`app/pages/ # file-based .wrn routes\napp/components/ # reusable .wrn components\napp/api/ # TypeScript request handlers\napp/middleware/ # ordered request middleware\napp/schemas/ # shared validation\napp/realtime/ # realtime rooms\nwrnexus.config.ts`)}<h2 id="page">3. Add a page</h2>${code(`page Contacts {\n view {\n <main><h1>Contact inbox</h1>\n <form data-schema="contact" action="/api/contacts" method="post">\n <input name="email" type="email" /><span data-error="email"></span>\n <textarea name="message"></textarea><span data-error="message"></span>\n <button type="submit">Send</button>\n </form>\n </main>\n }\n}`)}<h2 id="api">4. Validate an API route</h2>${code(`import schema from "../schemas/contact";\nimport { parseBody } from "@wrnexus/validation";\nexport const POST = async (ctx) => {\n const result = await parseBody(schema, ctx.req);\n return result.ok ? Response.json({ ok: true }, { status: 201 }) : result.response;\n};`)}<h2 id="server-data">5. Load server data</h2><p>Use an <code>ssr</code> API binding and a server <code>{#each}</code> block. See <a href="/guides/server-data">Server data</a> for the complete verified pattern.</p><h2 id="middleware">6. Add middleware</h2>${code(`export default async function logger(ctx, next) {\n console.log(ctx.req.method, ctx.url.pathname);\n return next();\n}`)}<h2 id="test-build">7. Test and ship</h2>${code(`bun run test\nbun run build\nbun dist/server.js`)}<p>Next: <a href="/guides/deployment">deployment</a>, <a href="/guides/database">database</a>, <a href="/guides/authentication">authentication</a>, and <a href="/guides/workspaces-and-gateway">workspaces</a>.</p></article>`,
|
||
);
|
||
|
||
page(
|
||
"/tutorial",
|
||
"Tutorial",
|
||
"Build a secure task application with WRNexusJS preview APIs.",
|
||
`<article class="documentation prose standalone"><span class="status status-beta">Preview · runnable-project extraction pending</span><h1>Secure task board</h1><p>This tutorial connects the installed ${version} APIs into one design. Snippets are limited to declarations and README patterns verified in the installed packages; a CI-compiled standalone fixture remains on the roadmap.</p><h2>Application shape</h2><p>A <code>.wrn</code> page renders tasks from an SSR API binding. A shared validation schema protects mutations. Session middleware identifies users, authorization policies gate updates, and a realtime room broadcasts changes.</p><h2>Schema and create route</h2>${code(`import { v, parseBody } from "@wrnexus/validation";\nconst task = v.object({ title: v.string().trim().min(3).max(120) });\nexport const POST = async (ctx) => {\n const parsed = await parseBody(task, ctx.req);\n if (!parsed.ok) return parsed.response;\n return Response.json({ ok: true, task: parsed.value }, { status: 201 });\n};`)}<h2>Server-rendered list</h2>${code(`page Tasks {\n ssr { api tasks GET /api/tasks { return tasks } }\n view {\n <main><h1>Tasks</h1><ul>\n {#each tasks as task}<li>{task.title}</li>{:empty}<li>No tasks yet.</li>{/each}\n </ul></main>\n }\n}`)}<h2>Production checklist</h2><ul><li>Choose SQLite for local development or configure the supported PostgreSQL driver.</li><li>Run migrations before accepting traffic.</li><li>Enable session authentication and enforce authorization on every mutation.</li><li>Validate upload types and sizes; keep private objects behind authenticated routes.</li><li>Use Redis pub/sub when realtime rooms span processes.</li><li>Treat the default queue as non-durable until a production driver is selected.</li></ul><p>Follow the focused <a href="/guides/database">database</a>, <a href="/guides/authentication">authentication</a>, <a href="/guides/authorization">authorization</a>, <a href="/guides/realtime">realtime</a>, and <a href="/guides/uploads">upload</a> guides.</p></article>`,
|
||
);
|
||
|
||
page(
|
||
"/architecture",
|
||
"Architecture",
|
||
"WRNexusJS request lifecycle, compiler, runtime, security, data, realtime, workspace, deployment, and mobile architecture.",
|
||
`<article class="documentation prose standalone"><span class="status status-beta">Framework architecture · ${version}</span><h1>Architecture</h1><p>WRNexusJS is Bun-native and SSR-first. File discovery maps pages and API handlers; middleware enriches or short-circuits a request; the compiler turns <code>.wrn</code> declarations into server render functions and small feature runtimes.</p><h2>Request and build lifecycle</h2><ol class="lifecycle"><li><strong>Discover</strong><span>Pages, APIs, middleware, components, layouts, schemas, rooms</span></li><li><strong>Compile</strong><span>Parse .wrn, validate grammar, generate server code</span></li><li><strong>Request</strong><span>Limits, security, locale, session, middleware</span></li><li><strong>Match</strong><span>Static and dynamic file route</span></li><li><strong>Render</strong><span>SSR data, escaped interpolation, components, metadata</span></li><li><strong>Enhance</strong><span>Only required reactive/directive runtimes</span></li></ol><h2>Package boundaries</h2><p><code>core</code> owns contexts, middleware, sessions and rooms; <code>router</code> discovers routes; <code>compiler</code> parses <code>.wrn</code>; <code>ssr</code> renders documents; <code>csr</code> supplies browser runtimes; <code>dev-server</code> and <code>cli</code> orchestrate development and builds.</p><h2>Security and data flow</h2><p>Validation happens at trust boundaries. Session authentication establishes identity; authorization makes resource decisions. CSP, Trusted Types, CSRF, upload checks, WebSocket origins, request limits, and output escaping are layered controls—not substitutes for application policy.</p><h2>Realtime and scale</h2><p>Rooms are process-local unless connected through pub/sub. Redis-backed pub/sub distributes events. Queue durability depends on the selected driver and must be evaluated explicitly.</p><h2>Workspaces and gateways</h2><p>The gateway can dispatch multiple applications while preserving route, component, asset, config, and session boundaries. Validate host routing and isolation before production.</p><h2>Build and deployment</h2><p><code>wrnexus build .</code> produces <code>dist/server.js</code> and hashed/static assets. Run the server with Bun, apply migrations before traffic, terminate TLS at a trusted edge, and forward only expected proxy headers.</p><h2>Mobile</h2><p>Mobile compatibility bridges SSR-safe Capacitor capabilities; native route generation is experimental and is not general web portability. Test each target platform.</p><h2>Generated files and limits</h2><p><code>app/routes.gen.ts</code>, <code>.wrnexus/</code>, and <code>dist/</code> are generated. The runtime is Bun-only. Preview packages are private. Historical compatibility and long-term support policy are not yet published.</p></article>`,
|
||
);
|
||
|
||
page(
|
||
"/language",
|
||
"The .wrn language",
|
||
"Reference for WRNexusJS .wrn pages, components, layouts, props, state, directives, forms, security, and errors.",
|
||
`<article class="documentation prose standalone"><span class="status status-beta">Language reference · ${version}</span><h1>The <code>.wrn</code> language</h1><nav class="local-toc" aria-label="On this page"><a href="#anatomy">Anatomy</a><a href="#state">Props and state</a><a href="#server">Server control flow</a><a href="#directives">Directives</a><a href="#security">Security</a><a href="#errors">Errors</a></nav><h2 id="anatomy">File anatomy</h2>${code(`page Account {\n layout = "public"\n seo { title = "Account" description = "Manage your account." }\n state count = 0\n view { <button @click="count++">Count {count}</button> }\n}`)}<h2 id="state">Pages, components, layouts, props, and state</h2><p>Pages are routes. Components declare default-valued props and may hold state. Layouts provide shared slots. Mount components with <code>data-component</code>; fill default or named slots with <code>data-slot</code>.</p><h2 id="server">Interpolation, conditionals, and loops</h2><p>Interpolation is HTML-escaped. Use server <code>{#if}</code> and <code>{#each}</code> for SSR data. Use <code>data-show</code> for reactive client visibility.</p><h2 id="directives">Events and directives</h2><p><code>@click</code> and other events execute in the reactive scope. Data attributes opt into forms, i18n, themes, realtime, uploader, browser, and mobile behavior. Consult the exact package page because availability varies.</p><h2 id="forms">Forms, i18n, themes, and realtime</h2><p><code>form[data-schema]</code> connects descriptors to client and server validation. Translation keys use <code>{t:key}</code>. Theme toggles use <code>data-wire-theme-toggle</code>. Realtime pages opt into a named room.</p><h2 id="security">Escaping and security</h2><p>Text interpolation is escaped by default. Do not construct trusted HTML from user input. Server-only refinements must be repeated at the authoritative mutation boundary.</p><h2 id="errors">Common compiler errors</h2><ul><li>Use balanced braces; a literal brace must be escaped.</li><li>Declare UI in <code>view</code>, not JSX or hooks.</li><li>Use a valid page, component, or layout declaration matching the file role.</li><li>Keep server loops tied to available SSR bindings.</li><li>Check <a href="/guides/troubleshooting">troubleshooting</a> and <a href="/packages/compiler">compiler API</a> for this release.</li></ul></article>`,
|
||
);
|
||
|
||
const guides: Record<string, [string, string, string]> = {
|
||
"project-structure": [
|
||
"Project structure",
|
||
"How source, public, generated, and build files are organized.",
|
||
"Pages, components, layouts, APIs, middleware, schemas, database files, locales, realtime rooms, and styles live under app. Never edit app/routes.gen.ts, .wrnexus, or dist by hand.",
|
||
],
|
||
routing: [
|
||
"Routing",
|
||
"File-based page and API routing.",
|
||
"A page filename defines its URL; index maps to the directory root and bracket segments are dynamic parameters. API files under app/api expose HTTP method functions and receive a Context.",
|
||
],
|
||
"pages-and-components": [
|
||
"Pages and components",
|
||
"Compose .wrn pages, layouts, props, state, and slots.",
|
||
"Pages are routable, components are reusable, and layouts provide shared slots. Mount a component with data-component and keep browser state scoped and minimal.",
|
||
],
|
||
"server-data": [
|
||
"Server data",
|
||
"Render API-backed data with SSR bindings.",
|
||
"Use an ssr API binding, return the desired response field, and render it with a server #each block. Values are escaped. Avoid fetching private data through a route that lacks authorization.",
|
||
],
|
||
"api-routes": [
|
||
"API routes",
|
||
"Build typed Bun-native HTTP handlers.",
|
||
"Export GET, POST, PUT, PATCH, or DELETE from app/api files. Validate request bodies, enforce authentication and authorization, cap request sizes, and return Web Responses.",
|
||
],
|
||
middleware: [
|
||
"Middleware",
|
||
"Order and short-circuit request middleware.",
|
||
"Middleware receives context and next. Return next() to continue or return a Response to stop. Put request limits and trust-boundary controls before business logic.",
|
||
],
|
||
"forms-and-validation": [
|
||
"Forms and validation",
|
||
"Share validation between forms and API routes.",
|
||
"Define a v.object schema, use data-schema on the form, show field errors with data-error, and always call parseBody on the server. refine is server-only.",
|
||
],
|
||
authentication: [
|
||
"Authentication",
|
||
"Session and identity boundaries.",
|
||
"Configure session authentication, log users in through supported auth helpers, and read identity from context. Cookie flags, rotation, expiry, and secret storage remain deployment responsibilities.",
|
||
],
|
||
authorization: [
|
||
"Authorization",
|
||
"Roles, permissions, policies, and resource checks.",
|
||
"Authentication identifies; authorization decides. Enforce permissions in server routes and policies, including object ownership. UI hiding is never an authorization boundary.",
|
||
],
|
||
security: [
|
||
"Application security",
|
||
"Configure layered WRNexusJS security controls.",
|
||
"Use CSP, CSRF, Trusted Types, session hardening, validation, origin checks, upload restrictions, encryption, request limits, and explicit CORS. See the security policy for reporting.",
|
||
],
|
||
database: [
|
||
"Database",
|
||
"Drivers, models, typed SQL, migrations, and deployment.",
|
||
"Configure SQLite or the installed supported driver, keep queries in named SQL blocks, generate typed functions, and apply migrations before traffic. Back up data and test rollback independently.",
|
||
],
|
||
uploads: [
|
||
"Uploads",
|
||
"Validated local and S3-compatible file handling.",
|
||
"Configure named stores, accepted MIME/extensions, and maxBytes. Random keys avoid path traversal. Private files require an authenticated serving route; v1 buffers each file in memory.",
|
||
],
|
||
realtime: [
|
||
"Realtime",
|
||
"Define rooms and secure WebSocket traffic.",
|
||
"defineRoom handles connection and messages. Validate message shapes, authorize subscriptions, restrict origins, bound payloads, and use pub/sub to scale across processes.",
|
||
],
|
||
pubsub: [
|
||
"Pub/sub",
|
||
"Scale events with in-process or Redis-backed pub/sub.",
|
||
"The in-process driver cannot cross processes. Use Redis where instances must share events, define channel ownership, and design for reconnects and duplicate delivery.",
|
||
],
|
||
queues: [
|
||
"Queues",
|
||
"Run delayed, retried, and repeated jobs.",
|
||
"Queue behavior is preview-level. Treat in-process work as non-durable, make handlers idempotent, cap retries, record failures, and choose a production persistence strategy.",
|
||
],
|
||
testing: [
|
||
"Testing",
|
||
"Test compiled components, routes, and browser behavior.",
|
||
"Use Bun tests and @wrnexus/test helpers. Cover server HTML, API status and validation, authorization failures, reactive behavior, and a production startup smoke test.",
|
||
],
|
||
"workspaces-and-gateway": [
|
||
"Workspaces and gateway",
|
||
"Add applications, route domains, and implement safe SSO forward authentication.",
|
||
`<p>A workspace runs isolated applications behind one domain-routing gateway. Add an application from the workspace root; the CLI scaffolds <code>apps/reports</code> and registers it in <code>wrnexus.workspace.ts</code>:</p>${code(`wrnexus workspace add reports --domain=reports.localhost
|
||
bun install
|
||
bun run dev`)}<h2>Forward authentication</h2><p>Point protected applications at a dedicated verifier endpoint. The verifier must return 2xx for an authenticated session, 401/403 to deny access, or an HTTP redirect to begin browser login.</p>${code(`// wrnexus.workspace.ts
|
||
{
|
||
name: "admin",
|
||
dir: "apps/admin",
|
||
domains: ["admin.localhost"],
|
||
auth: { forward: { url: "http://sso.localhost:3000/api/verify" } },
|
||
}`)}<p>The gateway forwards cookies, authorization, original host, protocol, method, path, and query. Inside the verifier, <code>ctx.url</code> identifies the SSO verifier request—not the original admin URL. Use <code>@wrnexus/helpers</code> to reconstruct and validate the original destination:</p>${code(`import type { Context } from "@wrnexus/core";
|
||
import { redirectToLogin } from "@wrnexus/helpers";
|
||
|
||
export const GET = async (ctx: Context) => {
|
||
if (await hasValidSession(ctx)) {
|
||
return new Response(null, { status: 204 });
|
||
}
|
||
|
||
return redirectToLogin(ctx, "/login", {
|
||
allowedHosts: ["admin.localhost:3000", "reports.localhost:3000"],
|
||
});
|
||
};`)}<p>Always allowlist redirect hosts. After login, validate or sign the <code>returnTo</code> value before redirecting. Keep internal app ports private and open applications through the gateway port.</p>`,
|
||
],
|
||
deployment: [
|
||
"Deployment",
|
||
"Build and run WRNexusJS with Bun.",
|
||
"Run bun run build, apply migrations, and start dist/server.js with Bun. Configure TLS, proxy trust, environment validation, health checks, graceful restarts, logs, backups, and restrictive security headers.",
|
||
],
|
||
"configuration-and-profiles": [
|
||
"Configuration and profiles",
|
||
"Use typed config and environment-specific profiles.",
|
||
"wrnexus.config.ts owns styles, SEO, security, data, mobile, fonts, and profiles. Keep secrets in validated environment variables and review merged production configuration.",
|
||
],
|
||
"i18n-and-themes": [
|
||
"Internationalization and themes",
|
||
"Load translations and token-based themes.",
|
||
"Store locale JSON under app/locales and use translation directives. Themes resolve CSS tokens; ensure contrast, system preference behavior, persistence, and non-color cues.",
|
||
],
|
||
mobile: [
|
||
"Mobile",
|
||
"Understand experimental webview and native modes.",
|
||
"Mobile capabilities are experimental in this preview. Test Capacitor permissions and lifecycle on each platform; do not assume every .wrn or browser API converts to native.",
|
||
],
|
||
observability: [
|
||
"Observability",
|
||
"Capture errors and events without leaking private data.",
|
||
"Use tracking middleware and sinks with redaction, sampling, stable request identifiers, alert ownership, and retention limits. Never capture registry tokens or session secrets.",
|
||
],
|
||
upgrading: [
|
||
"Upgrading",
|
||
"Upgrade aligned WRNexusJS packages safely.",
|
||
`Back up and commit first, then use wrnexus update --latest as documented by the installed CLI. Review migrations and keep every @wrnexus package aligned. Current release: ${version}.`,
|
||
],
|
||
troubleshooting: [
|
||
"Troubleshooting",
|
||
"Diagnose compiler, routing, build, and runtime failures.",
|
||
"Confirm Bun and package versions, regenerate docs/routes through supported commands, read the first compiler diagnostic, check file naming, validate config, and reproduce under a production build.",
|
||
],
|
||
"full-stack-auth-demo": [
|
||
"Auth and permissions dashboard demo",
|
||
"Create a complete demonstration site with public pages, authentication, configuration profiles, a protected dashboard, roles, permissions, database migrations, tests, and a production build.",
|
||
`<p>This walkthrough builds a small team portal. Public visitors can read the home and pricing pages, users can sign in, and the dashboard separates ordinary members from administrators. Every authorization decision remains on the server.</p>
|
||
<h2>1. Create the application</h2>${code(`bunx @wrnexus/cli@${version} create team-portal
|
||
cd team-portal
|
||
bun install
|
||
bun add @wrnexus/auth @wrnexus/authz @wrnexus/db @wrnexus/validation @wrnexus/ui
|
||
bunx wrnexus generate page pricing
|
||
bunx wrnexus generate page login
|
||
bunx wrnexus generate page dashboard
|
||
bunx wrnexus generate api session/login
|
||
bunx wrnexus generate api session/logout
|
||
bunx wrnexus generate schema login
|
||
bunx wrnexus authz init --dialect=sqlite
|
||
bunx wrnexus db new initial_auth --from-models
|
||
bunx wrnexus db migrate
|
||
bunx wrnexus generate types .`)}<p>Expected success output includes created file paths, an initialized authorization catalog, the applied migration name, and the generated application declaration path.</p>
|
||
<h2>2. Configure profiles and security</h2>${code(`// wrnexus.config.ts
|
||
import type { AppConfig } from "@wrnexus/styles";
|
||
|
||
const config: AppConfig = {
|
||
seo: { title: "Team Portal", titleTemplate: "%s | Team Portal" },
|
||
theme: { default: "system", palette: "violet" },
|
||
security: {
|
||
contentSecurityPolicy: true,
|
||
csrf: true,
|
||
frameOptions: "deny",
|
||
},
|
||
profiles: {
|
||
development: { envFiles: [".env", ".env.development"] },
|
||
production: { envFiles: [".env", ".env.production"] },
|
||
},
|
||
};
|
||
|
||
export default config;`)}${code(`# .env.example — commit names, never real secrets
|
||
DATABASE_URL=sqlite:./data/team-portal.db
|
||
SESSION_SECRET=replace-with-at-least-32-random-bytes
|
||
APP_ORIGIN=http://localhost:3000`)}<p>Run <code>wrnexus config . --explain --profile=production</code> before deployment and confirm no development fallback or secret value is printed.</p>
|
||
<h2>3. Create public pages and layout</h2>${code(`// app/layouts/public.wrn
|
||
layout Public {
|
||
view {
|
||
<Navbar brand="Team Portal" />
|
||
<main><slot /></main>
|
||
<Footer copyright="Team Portal" />
|
||
}
|
||
}
|
||
|
||
// app/pages/index.wrn
|
||
page Home {
|
||
layout = "public"
|
||
seo { title = "Home" description = "A secure portal for modern teams." }
|
||
view {
|
||
<Hero eyebrow="Team operations" title="One secure place for every team." />
|
||
<FeatureGrid columns="3"><slot /></FeatureGrid>
|
||
}
|
||
}`)}<p>Create <code>pricing.wrn</code>, <code>privacy.wrn</code>, and <code>terms.wrn</code> with the same public layout. Public routes must not load private account data.</p>
|
||
<h2>4. Define login validation and handlers</h2>${code(`// app/schemas/login.ts
|
||
import { v } from "@wrnexus/validation";
|
||
export default v.object({
|
||
email: v.string().trim().email(),
|
||
password: v.string().min(12).max(128),
|
||
});
|
||
|
||
// app/api/session/login.ts
|
||
import schema from "../../schemas/login";
|
||
import { parseBody } from "@wrnexus/validation";
|
||
|
||
export const POST = async (ctx) => {
|
||
const parsed = await parseBody(schema, ctx.req);
|
||
if (!parsed.ok) return parsed.response;
|
||
// Look up the account, verify its password, rotate the session,
|
||
// and return the same failure shape for unknown users and bad passwords.
|
||
return Response.json({ ok: true, redirect: "/dashboard" });
|
||
};`)}<p>Use the exact installed <a href="/packages/auth">authentication package</a> API for account lookup, password verification, session rotation, rate limiting, and audit events. Do not copy placeholder authentication logic into production.</p>
|
||
<h2>5. Declare roles and permissions</h2>${code(`// app/authz/main.ts
|
||
export const permissions = [
|
||
"dashboard:read",
|
||
"member:read",
|
||
"member:invite",
|
||
"member:manage",
|
||
] as const;
|
||
|
||
export const roles = {
|
||
member: ["dashboard:read", "member:read"],
|
||
manager: ["dashboard:read", "member:read", "member:invite"],
|
||
admin: ["dashboard:read", "member:read", "member:invite", "member:manage"],
|
||
} as const;`)}${code(`bunx wrnexus authz generate
|
||
bunx wrnexus authz list
|
||
bunx wrnexus contracts snapshot .`)}<p>Expected output lists the four permission identifiers and generated authorization artifacts. Commit the contract snapshot so later permission drift is reviewable.</p>
|
||
<h2>6. Protect the dashboard on the server</h2>${code(`// app/middleware/auth.ts
|
||
export default async function requireUser(ctx, next) {
|
||
const user = await readAuthenticatedUser(ctx);
|
||
if (!user) return Response.redirect(new URL("/login", ctx.url), 303);
|
||
ctx.state.user = user;
|
||
return next();
|
||
}
|
||
|
||
// app/api/members.ts
|
||
export const GET = async (ctx) => {
|
||
await requirePermission(ctx, "member:read");
|
||
return Response.json({ members: await listMembers(ctx.state.user.tenantId) });
|
||
};
|
||
|
||
export const POST = async (ctx) => {
|
||
await requirePermission(ctx, "member:invite");
|
||
// Validate input and keep the tenant identifier server-owned.
|
||
return Response.json({ ok: true }, { status: 201 });
|
||
};`)}<p>Route middleware establishes identity; each API mutation still checks its exact permission and resource boundary. Hiding an Invite button is useful UX but never authorization.</p>
|
||
<h2>7. Render the dashboard</h2>${code(`page Dashboard {
|
||
layout = "dashboard"
|
||
ssr {
|
||
api summary GET /api/dashboard { return summary }
|
||
api members GET /api/members { return members }
|
||
}
|
||
view {
|
||
<PageHeader eyebrow="Workspace" title="Dashboard" />
|
||
<MetricGrid columns="3">
|
||
<MetricCard label="Members" value={summary.memberCount} />
|
||
<MetricCard label="Invitations" value={summary.invitationCount} />
|
||
<MetricCard label="Active today" value={summary.activeToday} />
|
||
</MetricGrid>
|
||
<DataTable rows={members} />
|
||
}
|
||
}`)}<p>Keep dashboard data tenant-scoped in the API. Server rendering prevents an empty shell, while the client receives only the modules required for interactive controls.</p>
|
||
<h2>8. Test denial paths and production</h2>${code(`bunx wrnexus typecheck .
|
||
bunx wrnexus test unit .
|
||
bunx wrnexus test api .
|
||
bunx wrnexus test browser .
|
||
bunx wrnexus security audit .
|
||
bunx wrnexus contracts check .
|
||
bunx wrnexus build .
|
||
bunx wrnexus preview . --port=3000`)}<p>Tests should prove anonymous dashboard access redirects, members cannot invite, managers can invite but cannot manage roles, administrators can manage roles, cross-tenant identifiers are rejected, login failures are rate-limited, CSRF failures return 403, and the production server starts from <code>dist/server.js</code>.</p>
|
||
<h2>9. Demo checklist</h2><ul><li>Public home, pricing, privacy, and terms pages render without authentication.</li><li>Login creates and rotates a secure session.</li><li>Dashboard navigation changes by permission, while APIs enforce every permission independently.</li><li>Member lists and mutations are tenant-scoped on the server.</li><li>Development and production profiles resolve explicitly.</li><li>Typecheck, API tests, browser tests, security audit, contract check, build, and preview all pass.</li></ul>`,
|
||
],
|
||
};
|
||
const guideExamples: Record<string, [string, string]> = {
|
||
"project-structure": [
|
||
"Generate files through the CLI so routes and application types stay synchronized.",
|
||
`bunx wrnexus generate page account/settings
|
||
bunx wrnexus generate component account-card
|
||
bunx wrnexus generate api account/profile
|
||
bunx wrnexus generate routes
|
||
bunx wrnexus generate types .`,
|
||
],
|
||
routing: [
|
||
"This creates a dynamic, server-rendered account route and verifies that the router discovered it.",
|
||
`// app/pages/accounts/[id].wrn
|
||
page Account { view { <main><h1>Account {params.id}</h1></main> } }
|
||
|
||
bunx wrnexus inspect routes .`,
|
||
],
|
||
"pages-and-components": [
|
||
"Declare the reusable contract in a component, then pass data from the owning page.",
|
||
`component StatusCard {
|
||
prop title = "Status"
|
||
prop value = "Unknown"
|
||
view { <article><h2>{title}</h2><p>{value}</p><slot /></article> }
|
||
}
|
||
|
||
page Dashboard { view { <StatusCard title="API" value="Healthy" /> } }`,
|
||
],
|
||
"server-data": [
|
||
"Fetch on the server and render useful HTML before browser JavaScript loads.",
|
||
`page Accounts {
|
||
ssr { api result GET /api/accounts { return result.accounts } }
|
||
view { <ul>{#each result as account}<li>{account.name}</li>{:empty}<li>No accounts</li>{/each}</ul> }
|
||
}`,
|
||
],
|
||
"api-routes": [
|
||
"Validate a mutation and return an explicit HTTP result.",
|
||
`import { v, parseBody } from "@wrnexus/validation";
|
||
const input = v.object({ name: v.string().trim().min(2).max(80) });
|
||
export const POST = async (ctx) => {
|
||
const parsed = await parseBody(input, ctx.req);
|
||
return parsed.ok ? Response.json(parsed.value, { status: 201 }) : parsed.response;
|
||
};`,
|
||
],
|
||
middleware: [
|
||
"Add a request identifier and reject unsupported methods before application handlers run.",
|
||
`export default async function requestContext(ctx, next) {
|
||
ctx.state.requestId = crypto.randomUUID();
|
||
if (!["GET", "HEAD", "POST"].includes(ctx.req.method))
|
||
return new Response("Method not allowed", { status: 405 });
|
||
return next();
|
||
}`,
|
||
],
|
||
"forms-and-validation": [
|
||
"Use the same named schema in the browser form and authoritative API handler.",
|
||
`page Signup { view {
|
||
<form data-schema="signup" action="/api/signup" method="post">
|
||
<input name="email" type="email" /><span data-error="email"></span>
|
||
<button type="submit">Create account</button>
|
||
</form>
|
||
} }`,
|
||
],
|
||
authentication: [
|
||
"Require an authenticated session in middleware and redirect browser requests to login.",
|
||
`export default async function requireSession(ctx, next) {
|
||
const user = await readAuthenticatedUser(ctx);
|
||
if (!user) return Response.redirect(new URL("/login", ctx.url), 303);
|
||
ctx.state.user = user;
|
||
return next();
|
||
}`,
|
||
],
|
||
authorization: [
|
||
"Check the exact permission at the mutation boundary; hiding UI is only a convenience.",
|
||
`export const DELETE = async (ctx) => {
|
||
await requirePermission(ctx, "member:delete");
|
||
await deleteMember(ctx.params.id, ctx.state.user.tenantId);
|
||
return new Response(null, { status: 204 });
|
||
};`,
|
||
],
|
||
security: [
|
||
"Enable the main browser and request protections in application configuration, then audit the resolved production profile.",
|
||
`// wrnexus.config.ts
|
||
export default {
|
||
security: {
|
||
contentSecurityPolicy: true,
|
||
csrf: true,
|
||
trustedTypes: true,
|
||
frameOptions: "deny",
|
||
referrerPolicy: "strict-origin-when-cross-origin",
|
||
requestLimit: { maxBytes: 1_048_576 },
|
||
cors: { origins: ["https://app.example.com"] },
|
||
},
|
||
};
|
||
|
||
bunx wrnexus config . --explain --profile=production
|
||
bunx wrnexus security audit .`,
|
||
],
|
||
database: [
|
||
"Create a migration from models, apply it, and regenerate typed database functions.",
|
||
`bunx wrnexus db status
|
||
bunx wrnexus db new create_accounts --from-models
|
||
bunx wrnexus db migrate
|
||
bunx wrnexus db generate`,
|
||
],
|
||
uploads: [
|
||
"Keep size and type policy server-owned and serve private objects through an authorized route.",
|
||
`export default {
|
||
uploads: { stores: { avatars: {
|
||
driver: "local", directory: "./data/avatars",
|
||
maxBytes: 2_000_000, accept: ["image/png", "image/jpeg"],
|
||
} } },
|
||
};`,
|
||
],
|
||
realtime: [
|
||
"Authorize room membership and validate every incoming message before broadcasting.",
|
||
`export default defineRoom("team", {
|
||
async connect(client, ctx) { await requireTeamMember(ctx, ctx.params.teamId); },
|
||
async message(client, raw) {
|
||
const message = chatMessage.parse(JSON.parse(raw));
|
||
client.room.broadcast(JSON.stringify(message));
|
||
},
|
||
});`,
|
||
],
|
||
pubsub: [
|
||
"Use Redis when events must cross processes; use a namespaced channel contract.",
|
||
`const bus = createRedisPubSub({ url: env.REDIS_URL });
|
||
await bus.subscribe("team:42:events", (event) => handleTeamEvent(event));
|
||
await bus.publish("team:42:events", JSON.stringify({ type: "member.invited" }));`,
|
||
],
|
||
queues: [
|
||
"Make jobs idempotent and bound retry behavior before processing external effects.",
|
||
`const emails = queue("emails", { concurrency: 4, retries: 3 });
|
||
emails.process(async (job) => sendInviteOnce(job.data.invitationId));
|
||
await emails.add({ invitationId }, { delay: 1_000 });`,
|
||
],
|
||
testing: [
|
||
"Cover successful output and the denial path, then run the built server smoke check.",
|
||
`import { describe, expect, test } from "bun:test";
|
||
describe("members API", () => {
|
||
test("denies anonymous requests", async () => {
|
||
const response = await request("/api/members");
|
||
expect(response.status).toBe(401);
|
||
});
|
||
});`,
|
||
],
|
||
"workspaces-and-gateway": [
|
||
"Register applications explicitly and verify host routing through the gateway port.",
|
||
`bunx wrnexus workspace company-platform
|
||
cd company-platform
|
||
bunx wrnexus workspace add admin --domain=admin.localhost
|
||
bunx wrnexus gateway --port=3000`,
|
||
],
|
||
deployment: [
|
||
"Build once, apply migrations before traffic, and run the immutable Bun server artifact.",
|
||
`bun install --frozen-lockfile
|
||
bunx wrnexus typecheck .
|
||
bunx wrnexus db migrate
|
||
bunx wrnexus build .
|
||
bun dist/server.js`,
|
||
],
|
||
"configuration-and-profiles": [
|
||
"Keep shared defaults at the root and make production differences explicit.",
|
||
`export default {
|
||
server: { port: 3000 },
|
||
profiles: {
|
||
development: { envFiles: [".env", ".env.development"] },
|
||
production: { envFiles: [".env", ".env.production"] },
|
||
},
|
||
};
|
||
|
||
bunx wrnexus config . --explain --profile=production`,
|
||
],
|
||
"i18n-and-themes": [
|
||
"Configure one default locale and theme, then reference translation keys in server-rendered markup.",
|
||
`export default {
|
||
i18n: { defaultLocale: "en", locales: ["en", "fr"] },
|
||
theme: { default: "system", palette: "violet" },
|
||
};
|
||
|
||
page Home { view { <h1>{t:home.title}</h1><button data-wire-theme-toggle>Theme</button> } }`,
|
||
],
|
||
mobile: [
|
||
"Generate the mobile surface, compile it, and inspect supported native capabilities before relying on one.",
|
||
`bunx wrnexus generate mobile
|
||
bunx wrnexus mobile compile
|
||
bunx wrnexus native list`,
|
||
],
|
||
observability: [
|
||
"Redact credentials at the sink boundary and attach a stable request identifier.",
|
||
`const tracking = createTracking({
|
||
redact: ["authorization", "cookie", "password", "token"],
|
||
sampleRate: 0.1,
|
||
});
|
||
export default tracking.middleware();`,
|
||
],
|
||
upgrading: [
|
||
"Preview migrations first, review the report, then update the aligned package set.",
|
||
`git status --short
|
||
bunx wrnexus update . --latest --dry-run
|
||
bunx wrnexus update . --latest
|
||
bunx wrnexus typecheck .
|
||
bunx wrnexus build .`,
|
||
],
|
||
troubleshooting: [
|
||
"Collect deterministic diagnostics without exposing application secrets.",
|
||
`bun --version
|
||
bunx wrnexus doctor .
|
||
bunx wrnexus config . --explain
|
||
bunx wrnexus inspect routes .
|
||
bunx wrnexus report . --file=app/pages/index.wrn`,
|
||
],
|
||
};
|
||
for (const [slug, [title, desc, text]] of Object.entries(guides))
|
||
page(
|
||
`/guides/${slug}`,
|
||
title,
|
||
desc,
|
||
`<article class="documentation prose standalone"><span class="status status-beta">Preview guide · ${version}</span><h1>${title}</h1>${text.startsWith("<") ? text : `<p>${text}</p>`}${guideExamples[slug] ? `<h2>Practical example</h2><p>${guideExamples[slug][0]}</p>${code(guideExamples[slug][1])}<h3>What to verify</h3><p>Run this against the selected profile, inspect the generated or returned result, and add a test for both the successful path and its most important failure path.</p>` : ""}<h2>Configuration</h2><p>Keep configuration in <code>wrnexus.config.ts</code>, select an explicit profile, and store secrets only in validated environment variables. Use <code>wrnexus config . --explain</code> to review the resolved non-secret configuration.</p><h2>Implementation workflow</h2>${code(`bunx wrnexus doctor .
|
||
bunx wrnexus typecheck .
|
||
bunx wrnexus inspect routes .
|
||
bunx wrnexus build .`)}<p>Start from the exact installed package page, implement the smallest server-owned contract, and add browser behavior only where interaction requires it. Run the production build because development-only success does not prove deployability.</p><h2>Verification checklist</h2><ul><li>Inputs are validated at the authoritative server boundary.</li><li>Authentication and resource authorization are tested independently.</li><li>Generated routes and application types are current.</li><li>Error, empty, loading, denied, and success states are documented.</li><li>The production artifact starts and serves the expected route.</li></ul><h2>Release scope</h2><p>This guide describes installed ${version} capabilities. Follow linked package declarations for exact signatures; undocumented behavior is not guaranteed.</p><p><a href="/packages">Browse package APIs</a> · <a href="/packages/cli">CLI reference</a> · <a href="/guides/troubleshooting">Troubleshooting</a> · <a href="/support">Support</a></p></article>`,
|
||
"Guides",
|
||
);
|
||
|
||
const examples = [
|
||
"Minimal .wrn page",
|
||
"Database CRUD",
|
||
"Authentication and protected route",
|
||
"Permissions",
|
||
"Forms and validation",
|
||
"Realtime dashboard",
|
||
"File upload",
|
||
"Background queue",
|
||
"Redis pub/sub",
|
||
"Workspace gateway",
|
||
"Deployment",
|
||
"Experimental mobile mode",
|
||
];
|
||
page(
|
||
"/examples",
|
||
"Examples",
|
||
"WRNexusJS examples and their verification status.",
|
||
`<article class="documentation prose standalone"><h1>Examples</h1><p>Examples are tied to installed ${version} package documentation. The focused snippets in guides are source-verified; standalone runnable projects and CI compilation are tracked as remaining work.</p><div class="coverage-list">${examples.map((x, i) => `<article><h2>${x}</h2><span class="status ${i === 0 || i === 4 ? "status-beta" : "status-planned"}">${i === 0 || i === 4 ? "Documented" : "Planned fixture"}</span></article>`).join("")}</div></article>`,
|
||
"Learn",
|
||
);
|
||
page(
|
||
"/showcase",
|
||
"Showcase",
|
||
"Approved public WRNexusJS deployments.",
|
||
`<article class="documentation prose standalone"><h1>Showcase</h1><p>Only confirmed public properties are listed; no customer or traffic claims are made.</p><div class="feature-grid"><article><h2><a href="https://workroot.in/">WorkRoot</a></h2><p>Creator/company site demonstrating a public WRNexusJS deployment. Exact deployed version and infrastructure notes await owner confirmation.</p></article><article><h2><a href="https://wrnexusjs.dev/">WRNexusJS docs</a></h2><p>This documentation portal, built and verified against WRNexusJS ${version} on Bun.</p></article></div><p>Screenshots are intentionally deferred until approved assets and alt text are available.</p></article>`,
|
||
"Project",
|
||
);
|
||
page(
|
||
"/benchmarks",
|
||
"Benchmarks",
|
||
"Reproducible WRNexusJS performance evidence and methodology status.",
|
||
`<article class="documentation prose standalone"><h1>Benchmarks</h1><span class="status status-planned">No publishable benchmark dataset yet</span><p>No comparative speed claims are published. A valid baseline must record scripts, commit, Bun/framework versions, hardware, OS, warmup, samples, workload, raw results, median, percentiles, memory, HTML size, browser JavaScript size, and run date.</p><p>The roadmap starts with WRNexusJS-only measurements before any maintained equivalent-workload comparison.</p></article>`,
|
||
"Project",
|
||
);
|
||
page(
|
||
"/roadmap",
|
||
"Roadmap",
|
||
"Current WRNexusJS documentation and framework priorities without promised dates.",
|
||
`<article class="documentation prose standalone"><h1>Roadmap</h1><p>Roadmap items are direction, not delivery commitments. Dates require explicit owner approval.</p><h2>Now</h2><ul><li>Private preview onboarding and accurate package references</li><li>Runnable documentation fixtures and link/accessibility checks</li><li>License, support, and disclosure owner decisions</li></ul><h2>Next</h2><ul><li>Durable queue driver guidance</li><li>Expanded database/auth/realtime examples</li><li>Versioned release notes and migration fixtures</li></ul><h2>Later / exploration</h2><ul><li>Historical documentation selector</li><li>Maintained reproducible benchmarks</li><li>Broader mobile/native coverage</li></ul></article>`,
|
||
"Project",
|
||
);
|
||
page(
|
||
"/changelog",
|
||
"Changelog",
|
||
"WRNexusJS documentation release history and migration notes.",
|
||
`<article class="documentation prose standalone"><h1>Changelog</h1><h2>${version} <small>2026-07-13</small></h2><p>Documentation is aligned to all ${packageCount} installed packages. This release adds <code>@wrnexus/helpers</code>, original-request URL helpers, safe login redirects, working <code>wrnexus workspace add</code>, and forward-auth redirect propagation.</p><h3>Migration notes</h3><p>Run <code>wrnexus update --latest</code> and keep every <code>@wrnexus/*</code> package on ${version}. Existing applications must explicitly add <code>@wrnexus/helpers</code> before importing it; newly scaffolded applications include it automatically.</p><h2>Versioning and support</h2><p>The packages use semantic-looking versions, but a formal compatibility and old-release support policy has not been approved. Preview consumers should treat minor releases as potentially requiring migration review.</p></article>`,
|
||
"Project",
|
||
);
|
||
page(
|
||
`/releases/${version}`,
|
||
`Release ${version}`,
|
||
`WRNexusJS ${version} release notes.`,
|
||
`<article class="documentation prose standalone"><h1>WRNexusJS ${version}</h1><p>Released 2026-07-13. All ${packageCount} installed packages are aligned to this version. Highlights include the new helpers package, reliable workspace app addition, and browser SSO redirects through forward authentication. See the <a href="/changelog">changelog</a>, <a href="/guides/upgrading">upgrade guide</a>, and package references.</p></article>`,
|
||
"Releases",
|
||
);
|
||
page(
|
||
"/security",
|
||
"Security",
|
||
"WRNexusJS security defaults, limits, supported release status, and reporting process.",
|
||
`<article class="documentation prose standalone"><h1>Security</h1><p>WRNexusJS provides primitives for CSP, CSRF, Trusted Types, sessions, validation, authorization, encryption, upload restrictions, request limits, and WebSocket-origin checks. Applications remain responsible for correct configuration, business authorization, secrets, dependencies, data protection, and operations.</p><h2>Start with a production policy</h2><p>The following baseline blocks framing, restricts referrers and cross-origin access, enables CSRF and Trusted Types, and caps request bodies. Replace the example origin with the exact browser origin that calls your application.</p>${code(`// wrnexus.config.ts
|
||
export default {
|
||
security: {
|
||
contentSecurityPolicy: true,
|
||
csrf: true,
|
||
trustedTypes: true,
|
||
frameOptions: "deny",
|
||
referrerPolicy: "strict-origin-when-cross-origin",
|
||
cors: { origins: ["https://app.example.com"], credentials: true },
|
||
requestLimit: { maxBytes: 1_048_576 },
|
||
},
|
||
};`)}<h3>What you can change</h3><ul><li>Add only required API origins to CORS; never use a wildcard with credentialed requests.</li><li>Lower request limits for JSON APIs and define separate upload limits for accepted file types.</li><li>Extend CSP only for origins your application actually loads; avoid unsafe inline script exceptions.</li><li>Enable HSTS only after HTTPS works on every production hostname and subdomain you include.</li><li>Set session expiry, rotation, secure, HTTP-only, and SameSite behavior for your authentication flow.</li></ul><h2>Verify the resolved controls</h2>${code(`bunx wrnexus config . --explain --profile=production
|
||
bunx wrnexus security audit .
|
||
bunx wrnexus typecheck .
|
||
bunx wrnexus build .`)}<p>Review the resolved production configuration, then test a valid request, an invalid CSRF token, an oversized body, an unapproved origin, an anonymous protected request, and a permission-denied request. Security configuration is complete only when denial behavior is tested.</p><h2>Supported releases</h2><p>Only the current private-preview release ${version} is documented here. A formal old-release support window is not yet published.</p><h2>Report a vulnerability</h2><p>Use WorkRoot’s approved private contact path at <a href="https://workroot.in/">workroot.in</a>. Do not publish exploit details or secrets. Include affected version, impact, reproduction, and a safe contact method. Response targets, encryption key, bounty, audit, and certification are not currently claimed.</p><h2>Deployment controls</h2><p>Terminate TLS at a trusted edge, forward only expected proxy headers, store secrets outside source control, apply database migrations before traffic, and monitor rejected requests without logging credentials. Continue with the complete <a href="/guides/security">application security guide</a>.</p></article>`,
|
||
"Trust",
|
||
);
|
||
page(
|
||
"/support",
|
||
"Support",
|
||
"Actual WRNexusJS private preview support and contact routes.",
|
||
`<article class="documentation prose standalone"><h1>Support</h1><p>WRNexusJS has no public Discord, public issue tracker, or guaranteed community support channel listed by this repository. Preview access and support begin through <a href="https://workroot.in/">WorkRoot’s public contact path</a>.</p><p>Include WRNexusJS version, Bun version, OS, a minimal reproduction, expected and actual behavior, and sanitized logs. Never include registry tokens, credentials, session cookies, or private data.</p><p>Support scope, service levels, and commercial terms require owner confirmation.</p></article>`,
|
||
"Trust",
|
||
);
|
||
page(
|
||
"/license",
|
||
"License",
|
||
"Current WRNexusJS licensing status and private-preview terms boundary.",
|
||
`<article class="documentation prose standalone"><h1>License</h1><span class="status status-planned">Owner decision required</span><p>This documentation repository contains no public license file, and the packages are unavailable from the public npm registry. No open-source license or redistribution right should be inferred.</p><p>Approved preview users must follow the private/commercial terms supplied by WorkRoot. Contact <a href="https://workroot.in/">WorkRoot</a> before copying, redistributing, or using WRNexusJS in production.</p></article>`,
|
||
"Trust",
|
||
);
|
||
|
||
page(
|
||
"/search",
|
||
"Search",
|
||
"Search the local WRNexusJS documentation index without third-party tracking.",
|
||
`<article class="documentation prose standalone"><h1>Search documentation</h1><p>This build-time index is local and sends no query to a third party. Use your browser’s find command to filter this compact index.</p><h2>Core documentation</h2><p>${navigation.map(([href, label]) => `<a href="${href}">${label}</a>`).join(" · ")}</p><h2>Guides</h2><p>${Object.entries(
|
||
guides,
|
||
)
|
||
.map(([slug, [title]]) => `<a href="/guides/${slug}">${title}</a>`)
|
||
.join(" · ")}</p><h2>Package APIs</h2><p>${Object.keys(pkg.dependencies)
|
||
.concat(Object.keys(pkg.devDependencies))
|
||
.filter((name) => name.startsWith("@wrnexus/"))
|
||
.map((name) => `<a href="/packages/${name.split("/")[1]}">${name}</a>`)
|
||
.join(" · ")}</p></article>`,
|
||
"Discovery",
|
||
);
|
||
|
||
page(
|
||
"/404",
|
||
"Page not found",
|
||
"Find the requested WRNexusJS documentation through search or the documentation index.",
|
||
`<article class="documentation prose standalone"><span class="eyebrow">404</span><h1>Page not found</h1><p>The address may be outdated or misspelled. No private or duplicate route is exposed here.</p><div class="actions"><a class="primary" href="/search">Search documentation</a><a href="/getting-started">Getting started</a><a href="/packages">Package reference</a></div></article>`,
|
||
"Error",
|
||
);
|
||
|
||
const routes = [
|
||
"/",
|
||
"/access",
|
||
"/getting-started",
|
||
"/tutorial",
|
||
"/architecture",
|
||
"/language",
|
||
"/packages",
|
||
...Object.keys(guides).map((x) => `/guides/${x}`),
|
||
"/examples",
|
||
"/showcase",
|
||
"/benchmarks",
|
||
"/roadmap",
|
||
"/changelog",
|
||
`/releases/${version}`,
|
||
"/security",
|
||
"/support",
|
||
"/license",
|
||
"/search",
|
||
"/404",
|
||
].filter(Boolean);
|
||
const urls = [...new Set([...routes, ...packageNames.map((x) => `/packages/${x}`)])];
|
||
writeFileSync(
|
||
join(pub, "robots.txt"),
|
||
`User-agent: *\nAllow: /\nSitemap: https://wrnexusjs.dev/sitemap.xml\n`,
|
||
);
|
||
writeFileSync(
|
||
join(pub, "sitemap.xml"),
|
||
`<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">${urls.map((x) => `<url><loc>https://wrnexusjs.dev${x}</loc></url>`).join("")}</urlset>\n`,
|
||
);
|
||
await writeFormatted(
|
||
join(pub, "docs-index.json"),
|
||
JSON.stringify(
|
||
{
|
||
version,
|
||
status: "private-developer-preview",
|
||
generatedAt: "2026-07-13",
|
||
documents: urls.map((url) => ({
|
||
url,
|
||
title: url === "/" ? "WRNexusJS" : url.split("/").pop()!.replaceAll("-", " "),
|
||
section: url.startsWith("/guides")
|
||
? "guide"
|
||
: url.startsWith("/packages")
|
||
? "package"
|
||
: "portal",
|
||
version,
|
||
stability: url.includes("mobile") || url.includes("queues") ? "experimental" : "preview",
|
||
})),
|
||
},
|
||
null,
|
||
2,
|
||
),
|
||
);
|
||
const packageMarker = "# Installed package documentation";
|
||
const existingGuide = readFileSync(join(pub, "llms.txt"), "utf8");
|
||
let frameworkGuide = existingGuide
|
||
.split(
|
||
/\n# (?:Canonical documentation locations|Installed package index|UI component catalog|Installed package documentation)/,
|
||
)[0]!
|
||
.trim();
|
||
if (frameworkGuide.startsWith("# WRNexusJS documentation ")) {
|
||
frameworkGuide = frameworkGuide.replace(
|
||
/^# WRNexusJS documentation [^\n]+/,
|
||
`# WRNexusJS documentation ${version}`,
|
||
);
|
||
frameworkGuide = frameworkGuide.replace(
|
||
/^Status: Private Developer Preview\. This site documents \d+ release-aligned packages\.$/m,
|
||
`Status: Private Developer Preview. This site documents ${packageCount} release-aligned packages.`,
|
||
);
|
||
} else {
|
||
frameworkGuide = `# WRNexusJS documentation ${version}\n\nStatus: Private Developer Preview. This site documents ${packageCount} release-aligned packages.\n\n${frameworkGuide}`;
|
||
}
|
||
frameworkGuide = frameworkGuide.replace(
|
||
/\n## CLI\n[\s\S]*?\n## When asked to "create a page\/component\/feature"/,
|
||
`\n## CLI\n\nSee the generated **Complete CLI command reference** below. It is sourced from the installed ${version} executable so command names and options cannot drift.\n\n## When asked to "create a page/component/feature"`,
|
||
);
|
||
const installedPackageDocs = packageNames
|
||
.map((name) => {
|
||
const packageRoot = join(root, "node_modules", "@wrnexus", name);
|
||
const readme = readFileSync(join(packageRoot, "README.md"), "utf8").trim();
|
||
const declarations = readFileSync(join(packageRoot, "dist", "index.d.ts"), "utf8").trim();
|
||
return `## @wrnexus/${name}\n\nDocumentation URL: https://wrnexusjs.dev/packages/${name}\n\n${readme}\n\n### Exported TypeScript declarations\n\n\`\`\`ts\n${declarations}\n\`\`\``;
|
||
})
|
||
.join("\n\n---\n\n");
|
||
const packageIndex = packageNames
|
||
.map(
|
||
(name) =>
|
||
`## @wrnexus/${name}\n\n- @wrnexus/${name} ${version}\n- Documentation: https://wrnexusjs.dev/packages/${name}\n- README and complete exported TypeScript API: https://wrnexusjs.dev/llms-full.txt`,
|
||
)
|
||
.join("\n\n");
|
||
const componentSources =
|
||
uiReference?.components
|
||
.map((component) => {
|
||
const sourcePath = join(root, "node_modules", "@wrnexus", "ui", component.source);
|
||
const source = existsSync(sourcePath)
|
||
? readFileSync(sourcePath, "utf8").trim()
|
||
: "Source unavailable in the installed package.";
|
||
return `## ${component.name}\n\n${uiReferenceText
|
||
.split(`### ${component.name}\n`)[1]
|
||
?.split("\n\n### ")[0]
|
||
?.trim()}\n\n### Complete .wrn source contract\n\n\`\`\`wrn\n${source}\n\`\`\``;
|
||
})
|
||
.join("\n\n---\n\n") ?? "";
|
||
writeFileSync(
|
||
join(pub, "llms.txt"),
|
||
`${frameworkGuide}\n\n${cliReference}\n\n# Canonical documentation locations\n\n- Framework and package documentation: https://wrnexusjs.dev/\n- Interactive UI component showcase and examples: https://component.wrnexusjs.dev/\n- Comprehensive AI reference: https://wrnexusjs.dev/llms-full.txt\n\n# Installed package index\n\n${packageIndex}\n\n# UI component catalog\n\nThe installed @wrnexus/ui ${version} release contains ${uiReference?.count ?? 0} documented components. The contracts below include every mount name, purpose, prop type, required/default status, slot, and event. Interactive examples live only on the dedicated component showcase.\n\n${uiReferenceText}\n`,
|
||
);
|
||
writeFileSync(
|
||
join(pub, "llms-full.txt"),
|
||
`${frameworkGuide}\n\nRelease: WRNexusJS ${version}\n\n${cliReference}\n\n# Canonical documentation locations\n\n- Framework and package documentation: https://wrnexusjs.dev/\n- Interactive UI component showcase and examples: https://component.wrnexusjs.dev/\n\n${packageMarker}\n\nThe following README files and declarations come from the installed private ${version} release.\n\n${installedPackageDocs}\n\n# Complete @wrnexus/ui component reference and source contracts\n\n${componentSources}\n`,
|
||
);
|
||
|
||
const auditDocs: Record<string, string> = {
|
||
"site-audit.md": `# WRNexusJS site audit\n\nDate: 2026-07-13. Baseline: Bun 1.3.14, framework ${version}.\n\n## Baseline results\n\n- authenticated private-registry installation: pass.\n- docs generation: pass (${packageCount} package pages plus portal and guide pages).\n- tests, lint, formatting, and production build are required by the release check.\n- package access remains restricted/private.\n- repository: private WorkRoot Git remote; no public license file exists.\n\n## Findings\n\nPackage documentation, discovery assets, and AI-readable references are generated from the installed release. The ${version} portal includes the helpers package, workspace app addition, and safe forward-auth login redirect guidance.\n\n## Audit limitations\n\nBrowser tooling, Lighthouse, axe, screenshots, and authenticated production deployment checks are separate post-deploy work. Scores are not fabricated; reports belong under docs/audits/.\n`,
|
||
"documentation-information-architecture.md": `# Documentation information architecture\n\nGlobal navigation groups Learn, Reference, Guides, Project, and Trust. Canonical discovery begins at the homepage, then /getting-started and /tutorial. Exact APIs live under /packages. Conceptual tasks live under /guides. Status and trust live at /roadmap, /changelog, /security, /support, /license, and /access. Machine discovery uses robots.txt, sitemap.xml, llms.txt, llms-full.txt, and docs-index.json.\n`,
|
||
"release-access-status.md": `# Release and access status\n\n## Decision: Mode B — Private Developer Preview\n\nActive version: ${version}, derived from package.json#wrnexus.version. All ${packageCount} installed @wrnexus packages resolve to ${version} and npm reports restricted access. The repository remote is a private WorkRoot Git service and no public license file exists.\n\nExternal users cannot execute an installation without approved private registry credentials. The truthful CTA is Request preview access. After approval, the canonical command is bunx @wrnexus/cli@${version} create my-app. Tokens must never appear in documentation or source.\n`,
|
||
"documentation-coverage-matrix.md": `# Documentation coverage matrix\n\n| Area | Package reference | Concept guide | Runnable fixture | Tests | Stability | Limitation |\n|---|---|---|---|---|---|---|\n${packageNames.map((x) => `| @wrnexus/${x} | /packages/${x} | ${["validation", "authz", "db", "uploader", "pubsub", "queue", "mobile"].includes(x) ? `/guides/${x === "authz" ? "authorization" : x === "validation" ? "forms-and-validation" : x === "uploader" ? "uploads" : x === "queue" ? "queues" : x}` : "Architecture/package guide"} | Planned | Generator coverage | ${["mobile", "native", "queue"].includes(x) ? "Experimental" : "Preview"} | No standalone CI fixture |`).join("\n")}\n`,
|
||
"seo-metadata-matrix.md": `# SEO metadata matrix\n\nEvery canonical portal page defines a unique descriptive title, description, and absolute canonical. Package metadata is generated from installed package metadata. Sitemap and robots cover portal, guides, release, and package routes. Structured-data support is not exposed by the installed .wrn SEO grammar and remains a framework/generator gap. Preview routes remain indexable because the documentation is public; private package/source locations are not linked.\n`,
|
||
"redirect-map.md": `# Redirect map\n\nNo legacy redirects are currently required: existing /, /getting-started, /architecture, /language, /packages, and /packages/:name remain canonical. If versioned archives are introduced, current unversioned docs should canonicalize to the active release and archived URLs must remain immutable.\n`,
|
||
"release-checklist.md": `# Release checklist\n\n- [ ] Confirm all @wrnexus versions align with package.json#wrnexus.version.\n- [ ] Run bun install, docs:generate twice, test, check, build, and production smoke.\n- [ ] Verify clean-registry access status and CTA.\n- [ ] Crawl routes, links, anchors, canonical metadata, sitemap, robots, and AI files.\n- [ ] Run mobile/desktop accessibility and Lighthouse audits.\n- [ ] Confirm license, disclosure contact, support policy, changelog, and showcase approvals.\n- [ ] Verify no tokens, private paths, fake community links, or unsupported claims.\n`,
|
||
"post-deploy-checklist.md": `# Post-deploy checklist\n\n1. Fetch representative HTML, robots.txt, sitemap.xml, llms.txt, llms-full.txt, and docs-index.json.\n2. Run Lighthouse mobile under controlled conditions; target performance/accessibility/SEO/best-practices >=95 with no critical accessibility issue.\n3. Run keyboard, screen reader, zoom, reduced-motion, link, anchor, and responsive overflow checks.\n4. Submit sitemap in Google Search Console and Bing Webmaster Tools after domain ownership is verified.\n5. Inspect canonical selection, rich-result eligibility, crawl errors, CSP reports, server logs, and 404s.\n6. Save dated reports under docs/audits/.\n`,
|
||
};
|
||
for (const [name, body] of Object.entries(auditDocs)) {
|
||
await writeFormatted(join(docs, name), body);
|
||
}
|
||
mkdirSync(join(docs, "audits"), { recursive: true });
|
||
writeFileSync(
|
||
join(docs, "audits", "2026-07-12-baseline.md"),
|
||
`# Baseline audit\n\nAutomated Bun install/docs/test/check/build passed before implementation. Lighthouse, browser accessibility, and screenshots were unavailable; no scores are claimed.\n`,
|
||
);
|
||
|
||
// Historical release notes are intentionally immutable content, but they share
|
||
// the current accessible shell controls and interaction behavior.
|
||
const releasesDirectory = join(pages, "releases");
|
||
for (const file of readdirSync(releasesDirectory).filter((name) => name.endsWith(".wrn"))) {
|
||
const releasePath = join(releasesDirectory, file);
|
||
let source = readFileSync(releasePath, "utf8");
|
||
source = source.replace(
|
||
'<SkipLink label="Skip to content" href="#main" class="docs-skip-link" />',
|
||
'<a href="#main" class="skip-link">Skip to content</a>',
|
||
);
|
||
source = source.replace(/\s*<BackToTop(?: threshold=\{480\})? \/>/g, "");
|
||
writeFileSync(releasePath, source);
|
||
}
|
||
console.log(
|
||
`Generated portal pages, ${urls.length} discovery URLs, and audit deliverables for WRNexusJS ${version}.`,
|
||
);
|