import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { join, resolve } from "node:path";

const root = resolve(import.meta.dir, "..");
const projectPackage = JSON.parse(readFileSync(join(root, "package.json"), "utf8")) as {
  wrnexus?: { version?: string };
};
const frameworkVersion = projectPackage.wrnexus?.version;
if (!frameworkVersion) throw new Error("package.json is missing wrnexus.version");
const pages = join(root, "app", "pages");
const packagePages = join(pages, "packages");
mkdirSync(packagePages, { recursive: true });

const catalog = [
  ["ai", "AI", "Server-side Anthropic client with generation and streaming."],
  ["authz", "Security", "Role, permission, policy, and authorization guards."],
  ["cli", "Tooling", "Create, develop, build, generate, test, and maintain WrNexus apps."],
  ["compiler", "Core", "Parser and code generators for the .wrn language."],
  ["core", "Core", "Contexts, middleware, security, sessions, caching, JSX, and realtime."],
  ["csr", "Frontend", "Reactive, navigation, and realtime browser runtimes."],
  ["db", "Data", "Database adapters, typed queries, models, migrations, and sessions."],
  ["dev-server", "Runtime", "Development and production servers, HMR, assets, and gateways."],
  ["encryption", "Security", "Hashing, HMAC, authenticated encryption, and key derivation."],
  ["helpers", "Tooling", "Safe Context URL helpers and forward-auth login redirects."],
  ["i18n", "Frontend", "Translation loading, locale resolution, and Intl formatting."],
  ["jwt", "Security", "HS256 JWT signing, verification, and bearer authentication."],
  ["mobile", "Native", "SSR-safe compatibility access to Capacitor plugins."],
  ["native", "Native", "Cross-platform browser and Capacitor capability registry."],
  ["oauth", "Security", "OAuth 2.0, PKCE, provider presets, and profile mapping."],
  ["pubsub", "Realtime", "In-process and Redis-backed publish/subscribe."],
  ["queue", "Data", "Background jobs with delay, concurrency, retry, and repetition."],
  ["reactive", "Frontend", "Small type-safe reactive signal primitives."],
  ["router", "Core", "Filesystem discovery, route matching, and typed route generation."],
  ["ssr", "Runtime", "Secure HTML document rendering and SEO metadata."],
  ["styles", "Frontend", "CSS pipeline, themes, fonts, profiles, and application config."],
  ["test", "Tooling", "WrNexus-aware component, route, and browser testing utilities."],
  ["tracking", "Runtime", "Error/event capture, middleware, filtering, and sinks."],
  ["ui", "Frontend", "Themeable server-rendered UI components and CSS."],
  ["uploader", "Data", "Validated local/S3 uploads and secure file serving."],
  ["validation", "Security", "Typed schemas, coercion, validation, and browser descriptors."],
] as const;

const escape = (value: string) =>
  value
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/\{/g, "&#123;")
    .replace(/\}/g, "&#125;");

function inline(value: string): string {
  return escape(value)
    .replace(/`([^`]+)`/g, "<code>$1</code>")
    .replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>")
    .replace(/\[([^\]]+)\]\((https?:\/\/[^)]+)\)/g, '<a href="$2" rel="noreferrer">$1</a>');
}

interface DocHeading {
  id: string;
  title: string;
  level: number;
}

function markdown(source: string): { html: string; headings: DocHeading[] } {
  const lines = source.replace(/\r/g, "").split("\n");
  const out: string[] = [];
  const headings: DocHeading[] = [];
  const usedIds = new Map<string, number>();
  let code: string[] | null = null;
  let language = "";
  let list = false;
  let paragraph: string[] = [];
  let table: string[][] = [];
  const flushParagraph = () => {
    if (paragraph.length) out.push(`<p>${inline(paragraph.join(" "))}</p>`);
    paragraph = [];
  };
  const closeList = () => {
    if (list) out.push("</ul>");
    list = false;
  };
  const flushTable = () => {
    if (!table.length) return;
    const separator = table[1]?.every((cell) => /^:?-{3,}:?$/.test(cell.trim()));
    const header = separator ? table[0]! : undefined;
    const rows = separator ? table.slice(2) : table;
    out.push('<div class="table-wrap"><table>');
    if (header) {
      out.push(
        `<thead><tr>${header.map((cell) => `<th>${inline(cell.trim())}</th>`).join("")}</tr></thead>`,
      );
    }
    out.push(
      `<tbody>${rows.map((row) => `<tr>${row.map((cell) => `<td>${inline(cell.trim())}</td>`).join("")}</tr>`).join("")}</tbody></table></div>`,
    );
    table = [];
  };
  for (const line of lines) {
    if (/^\|.*\|\s*$/.test(line)) {
      flushParagraph();
      closeList();
      table.push(line.slice(1, line.lastIndexOf("|")).split("|"));
      continue;
    }
    flushTable();
    const fence = /^```(.*)$/.exec(line);
    if (fence) {
      flushParagraph();
      closeList();
      if (code) {
        out.push(
          `<pre data-language="${escape(language)}"><code>${escape(code.join("\n"))}</code></pre>`,
        );
        code = null;
      } else {
        code = [];
        language = fence[1]!.trim();
      }
      continue;
    }
    if (code) {
      code.push(line);
      continue;
    }
    const heading = /^(#{1,4})\s+(.+)$/.exec(line);
    if (heading) {
      flushParagraph();
      closeList();
      const level = Math.min(4, heading[1]!.length + 1);
      const title = heading[2]!.replace(/[`*_]/g, "").trim();
      const base =
        title
          .toLowerCase()
          .replace(/[^a-z0-9]+/g, "-")
          .replace(/^-|-$/g, "") || "section";
      const occurrence = usedIds.get(base) ?? 0;
      usedIds.set(base, occurrence + 1);
      const id = occurrence ? `${base}-${occurrence + 1}` : base;
      headings.push({ id, title, level });
      out.push(`<h${level} id="${id}">${inline(heading[2]!)}</h${level}>`);
      continue;
    }
    const item = /^[-*]\s+(.+)$/.exec(line);
    if (item) {
      flushParagraph();
      if (!list) out.push("<ul>");
      list = true;
      out.push(`<li>${inline(item[1]!)}</li>`);
      continue;
    }
    if (!line.trim()) {
      flushParagraph();
      closeList();
      continue;
    }
    if (/^>\s?/.test(line)) {
      flushParagraph();
      closeList();
      out.push(`<blockquote>${inline(line.replace(/^>\s?/, ""))}</blockquote>`);
      continue;
    }
    if (/^---+$/.test(line.trim())) continue;
    paragraph.push(line.trim());
  }
  flushParagraph();
  closeList();
  flushTable();
  if (code) out.push(`<pre><code>${escape(code.join("\n"))}</code></pre>`);
  return { html: out.join("\n"), headings };
}

function examplesFrom(readme: string, name: string): string {
  const usageHeading = /^## Usage[ \t]*\r?$/m.exec(readme);
  if (!usageHeading) throw new Error(`@wrnexus/${name} README must contain a Usage section`);
  const afterHeading = readme.slice(usageHeading.index + usageHeading[0].length);
  const nextSection = /^##[ \t]+/m.exec(afterHeading);
  const usage = afterHeading.slice(0, nextSection?.index ?? afterHeading.length);

  const examples: { title: string; language: string; code: string }[] = [];
  const lines = usage.replace(/\r/g, "").split("\n");
  let title = "Typical usage";
  let prose = "";
  for (let index = 0; index < lines.length; index++) {
    const line = lines[index]!;
    const heading = /^#{3,4}\s+(.+)$/.exec(line);
    if (heading) {
      title = heading[1]!.replace(/[`*_]/g, "").trim();
      prose = "";
      continue;
    }
    const fence = /^```(.*)$/.exec(line);
    if (fence) {
      const code: string[] = [];
      index++;
      while (index < lines.length && !/^```/.test(lines[index]!)) {
        code.push(lines[index]!);
        index++;
      }
      const value = code.join("\n").trim();
      const language = fence[1]!.trim();
      if (value && language !== "text" && !examples.some((example) => example.code === value)) {
        examples.push({
          title: title === "Typical usage" && prose ? prose : title,
          language,
          code: value,
        });
      }
      prose = "";
      continue;
    }
    if (line.trim() && !/^[-*>|]/.test(line.trim())) {
      prose = line
        .replace(/[`*_]/g, "")
        .replace(/\[([^\]]+)\]\([^)]+\)/g, "$1")
        .replace(/:\s*$/, "")
        .trim();
    }
  }
  if (examples.length < 2) {
    throw new Error(`@wrnexus/${name} README needs at least two Usage code examples`);
  }
  return examples
    .slice(0, 6)
    .map(
      (example) =>
        `<article class="example-card"><h3>${inline(example.title)}</h3><pre data-language="${escape(example.language || "text")}"><code>${escape(example.code)}</code></pre></article>`,
    )
    .join("");
}

function shell(title: string, description: string, content: string, state = ""): string {
  const document = `page ${title.replace(/[^A-Za-z0-9]/g, "")} {
  seo {
    title = "${title.replace(/"/g, "'")}"
    description = "${description.replace(/"/g, "'")}"
  }
${state}
  view {
    <div class="docs-shell">
      <a class="skip-link" href="#main">Skip to content</a>
      <header class="topbar">
        <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="/language">Language</a><a href="/architecture">Architecture</a></nav>
        <div class="topbar-actions"><a class="preview-pill" href="/access">Private preview · v${frameworkVersion}</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><a href="/getting-started">Get started</a><a href="/packages">Packages</a><a href="/language">Language</a><a href="/architecture">Architecture</a><a href="/tutorial">Tutorial</a><a href="/guides/project-structure">Guides</a><a href="/examples">Examples</a><a href="/search">Search</a></nav></details></div>
      ${content}
      <footer>WRNexusJS ${frameworkVersion} · Private Developer Preview · Bun-native · Documentation generated from installed package APIs.</footer>
    </div>
  }
}
`;
  return document.replace(/\bWrNexus\b/g, "WRNexusJS");
}

const cards = catalog
  .map(
    ([
      name,
      category,
      summary,
    ]) => `<a class="package-card" href="/packages/${name}" data-show="(category === 'All' ? true : category === '${category}') ? (query === '' ? true : '${name} ${category.toLowerCase()} ${summary.toLowerCase().replace(/'/g, "")} '.includes(query.toLowerCase())) : false">
          <span class="category">${category}</span><h2>@wrnexus/${name}</h2><p>${summary}</p><span class="card-link">Open documentation →</span>
        </a>`,
  )
  .join("\n");

const categories = ["All", ...new Set(catalog.map(([, category]) => category))];
const categoryButtons = categories
  .map((category) => {
    const count =
      category === "All"
        ? catalog.length
        : catalog.filter(([, value]) => value === category).length;
    return `<button type="button" @click="category = '${category}'">${category}<span>${count}</span></button>`;
  })
  .join("");

writeFileSync(
  join(pages, "packages.wrn"),
  shell(
    "Packages",
    "Explore every WrNexus package, API, function, and copy-ready usage example.",
    `<main class="page"><section class="hero compact"><span class="eyebrow">${catalog.length} focused packages</span><h1>Package reference</h1><p>Everything in the framework, organized by responsibility and documented from the published ${frameworkVersion} APIs.</p><input class="search" type="search" placeholder="Search packages, features, or categories…" @input="query = event.target.value" /></section><section class="category-filter" aria-label="Filter packages by category"><div class="category-row">${categoryButtons}</div><p>Showing <strong>{category}</strong> packages</p></section><section class="package-grid">${cards}</section></main>`,
    '  state query = ""\n  state category = "All"\n',
  ),
);

for (const [name, category, summary] of catalog) {
  const packageRoot = join(root, "node_modules", "@wrnexus", name);
  const readmePath = join(packageRoot, "README.md");
  const typesPath = join(packageRoot, "dist", "index.d.ts");
  if (!existsSync(readmePath) || !existsSync(typesPath))
    throw new Error(`Install @wrnexus/${name} before generating docs`);
  const readme = readFileSync(readmePath, "utf8")
    .replace(/^#\s+[^\n]+\n?/, "")
    .replace(/^## Installation\s*$[\s\S]*?(?=^##\s|\s*$)/m, "")
    .replace(/\bWrNexus\b/g, "WRNexusJS");
  const types = readFileSync(typesPath, "utf8");
  const guide = markdown(readme);
  const toc = [
    { id: "guide", title: "Guide", level: 2 },
    ...guide.headings,
    { id: "api", title: "Complete API", level: 2 },
    { id: "examples", title: "Examples", level: 2 },
  ]
    .map(
      (heading) =>
        `<a class="toc-level-${heading.level}" href="#${heading.id}">${escape(heading.title)}</a>`,
    )
    .join("");
  const content = `<main class="page package-page">
      <aside class="sidebar"><a href="/packages">← All packages</a><span class="category">${category}</span><h2>@wrnexus/${name}</h2><p>${summary}</p><span class="status status-beta">Private preview · ${frameworkVersion}</span><nav><a href="#access">Access</a><a href="#guide">Guide</a><a href="#api">Complete API</a></nav></aside>
      <article id="main" class="documentation"><section class="doc-intro"><span class="eyebrow">${category} · Preview</span><h1>@wrnexus/${name}</h1><p>${summary}</p><section id="access" class="access-callout"><h2>Private registry access required</h2><p>This package is not available from the public npm registry. After WorkRoot approves access and supplies private registry instructions, install the release-aligned package:</p><pre><code>bun add @wrnexus/${name}@${frameworkVersion}</code><button type="button" class="copy-button" aria-label="Copy installation command">Copy</button></pre><p><a href="/access">Request preview access</a>. Never put registry tokens in source control.</p></section></section><section id="guide" class="prose">${guide.html}</section><section id="api" class="prose api"><h2>Complete TypeScript API</h2><p>This declaration comes from the exact installed package and lists its exported functions, classes, interfaces, and types.</p><pre data-language="typescript"><code>${escape(types)}</code></pre></section><section id="examples" class="prose examples"><h2>Examples</h2><p>Examples are taken from this package's installed documentation and must be evaluated with its requirements and stability notes.</p><div class="example-grid">${examplesFrom(readme, name)}</div></section></article>
      <aside class="on-this-page"><h2>On this page</h2><nav>${toc}</nav></aside>
    </main>`;
  writeFileSync(join(packagePages, `${name}.wrn`), shell(`@wrnexus/${name}`, summary, content));
}

writeFileSync(
  join(pages, "index.wrn"),
  shell(
    "Home",
    "WrNexus documentation: build secure, server-rendered, reactive applications with Bun.",
    `<main class="page"><section class="hero"><span class="eyebrow">WrNexus ${frameworkVersion}</span><h1>Build from the server.<br><em>Ship only what matters.</em></h1><p>An SSR-first, Bun-native framework with reactive .wrn components, typed data, realtime rooms, mobile capabilities, and production security built in.</p><div class="actions"><a class="primary" href="/getting-started">Start building</a><a href="/packages">Explore ${catalog.length} packages</a></div><div class="code-window"><span>app/pages/counter.wrn</span><pre><code>page Counter {
  state count = 0
  view {
    &lt;button @click=&quot;count++&quot;&gt;
      Count {count}
    &lt;/button&gt;
  }
}</code></pre></div></section><section class="feature-grid"><article><h2>SSR by default</h2><p>Useful HTML reaches the browser immediately. Interactive pages hydrate only the runtime they use.</p></article><article><h2>Secure foundations</h2><p>CSP, Trusted Types, CSRF, sessions, validation, authorization, encryption, and safe rendering are integrated.</p></article><article><h2>Web to native</h2><p>Share markup through Capacitor or compile portable pages into Expo and React Native routes.</p></article></section></main>`,
  ),
);

const guides = {
  "getting-started": [
    "Getting started",
    "Getting started with WrNexus",
    `<main class="page"><article class="documentation prose standalone"><span class="eyebrow">Guide</span><h1>Getting started</h1><p>Create a production-ready WrNexus application with Bun.</p><h2>1. Create the project</h2><pre><code>bunx @wrnexus/cli create my-app
cd my-app
bun install
bun run dev</code></pre><h2>2. Add a page</h2><pre><code>page Dashboard {
  state count = 0
  view {
    &lt;main&gt;
      &lt;h1&gt;Dashboard&lt;/h1&gt;
      &lt;button @click=&quot;count++&quot;&gt;{count}&lt;/button&gt;
    &lt;/main&gt;
  }
}</code></pre><h2>3. Verify and build</h2><pre><code>wrnexus doctor
wrnexus test
wrnexus build</code></pre><h2>Where things live</h2><ul><li><code>app/pages</code> contains routes.</li><li><code>app/components</code> contains reusable .wrn components.</li><li><code>app/api</code> contains server API handlers.</li><li><code>app/layouts</code> contains shared shells.</li><li><code>app/middleware</code> contains request middleware.</li><li><code>wrnexus.config.ts</code> configures security, styles, data, mobile, and deployment.</li></ul></article></main>`,
  ],
  language: [
    "Language and directives",
    "Complete WrNexus language reference for events, directives, loops, conditionals, data, components, forms, realtime, and native behavior.",
    `<main class="page"><article class="documentation prose standalone language-reference"><span class="eyebrow">Complete reference</span><h1>Language and directives</h1><p>This page documents the .wrn language and declarative browser features that span multiple packages.</p>
    <h2 id="file-anatomy">File anatomy</h2><p>A file declares a <code>page</code> or <code>component</code> and can contain metadata, props, state, data, view, style, server functions, APIs, and realtime handlers.</p><pre><code>${escape(`page Dashboard {
  layout = "default"
  seo { title = "Dashboard" }
  state count = 0
  view { <button @click="count++">{count}</button> }
  style { button { padding: 12px; } }
}`)}</code></pre>
    <h2 id="state">State and interpolation</h2><p>State is scoped to the nearest generated <code>data-scope</code>. Text and ordinary attribute expressions update reactively after hydration while retaining useful initial SSR values.</p><pre><code>${escape(`state count = 0
state user = { name: "Ada" }
state showPassword = false

view {
  <p>Count: {count}</p>
  <p>{user.name}</p>
  <input type="{showPassword ? 'text' : 'password'}">
  <button @click="showPassword = !showPassword"
          aria-label="{showPassword ? 'Hide password' : 'Show password'}">
    Toggle password
  </button>
}`)}</code></pre>
    <h2 id="events">Events</h2><p>Any DOM event can use <code>@event="statement"</code>. The compiler emits <code>data-on-event</code>. The expression receives <code>event</code> and can mutate state.</p><div class="table-wrap"><table><thead><tr><th>Syntax</th><th>Purpose</th></tr></thead><tbody><tr><td><code>@click</code></td><td>Pointer or keyboard activation.</td></tr><tr><td><code>@input</code></td><td>Read live field values.</td></tr><tr><td><code>@change</code></td><td>React to committed field changes.</td></tr><tr><td><code>@submit</code></td><td>Handle form submission behavior.</td></tr><tr><td><code>@browser-click</code></td><td>Run only in a browser target.</td></tr><tr><td><code>@mobile-click</code></td><td>Run only in a native/mobile target.</td></tr></tbody></table></div><pre><code>${escape(`<input @input="name = event.target.value">
<button @click="count++">Add</button>
<form @submit="submitted = true">...</form>`)}</code></pre>
    <h2 id="directives">Reactive data attributes</h2><div class="table-wrap"><table><thead><tr><th>Directive</th><th>Behavior</th></tr></thead><tbody><tr><td><code>data-scope</code></td><td>Declares reactive state for a subtree.</td></tr><tr><td><code>data-text</code></td><td>Synchronizes textContent with an expression.</td></tr><tr><td><code>data-show</code></td><td>Shows or hides an element by truthiness.</td></tr><tr><td><code>data-for</code></td><td>Repeats an element for a client-side list.</td></tr><tr><td><code>data-on-&lt;event&gt;</code></td><td>Compiled form of an event binding.</td></tr><tr><td><code>data-component</code></td><td>Mounts a server-rendered component.</td></tr><tr><td><code>data-slot</code></td><td>Fills a named component or layout slot.</td></tr><tr><td><code>data-wrnexus-csr</code></td><td>Connects generated client data fetching.</td></tr></tbody></table></div>
    <h2 id="conditionals">Conditional rendering</h2><h3>Server conditionals</h3><p>Server blocks render only the selected branch into the response.</p><pre><code>${escape(`{#if user.isAdmin}
  <a href="/admin">Admin</a>
{:else if user}
  <p>Welcome {user.name}</p>
{:else}
  <a href="/login">Sign in</a>
{/if}`)}</code></pre><h3>Client visibility</h3><pre><code>${escape(`<section data-show="open">Visible while open is true</section>`)}</code></pre>
    <h2 id="loops">Loops and lists</h2><h3>Server each block</h3><pre><code>${escape(`{#each users as user, i}
  <p>{i + 1}. {user.name}</p>
{:empty}
  <p>No users</p>
{/each}`)}</code></pre><h3>Reactive client loop</h3><pre><code>${escape(`<li data-for="item, i in items">
  <span data-text="item.name"></span>
  <button data-on-click="items = items.filter(x => x !== item)">Remove</button>
</li>`)}</code></pre>
    <h2 id="components">Components, props, and slots</h2><pre><code>${escape(`component Card {
  props { title = "Card" }
  view {
    <article><h2>{title}</h2><slot></slot></article>
  }
}

<div data-component="card" title="Profile">
  <p>Card content</p>
</div>`)}</code></pre>
    <h2 id="data">Server and client data</h2><p>Use named data bindings for SSR data or client hydration. Secrets and database work stay on the server.</p><pre><code>${escape(`data users {
  ssr GET "/api/users"
}

view {
  {#each users as user}<p>{user.name}</p>{/each}
}`)}</code></pre>
    <h2 id="forms">Forms and validation</h2><p>Schema-backed forms validate in the browser and on the server with the same descriptor.</p><pre><code>${escape(`<form data-schema="login" method="post" action="/api/login" data-redirect="/dashboard">
  <input name="email" type="email">
  <span data-error="email"></span>
  <button>Sign in</button>
  <p data-success="Signed in" hidden></p>
</form>`)}</code></pre>
    <h2 id="i18n">Internationalization and themes</h2><pre><code>${escape(`<h1>{t:home.title}</h1>
<button data-wire-lang-set="fr">Français</button>
<button data-wire-theme-toggle>Toggle theme</button>
<button data-wire-theme-set="dark">Dark</button>`)}</code></pre>
    <h2 id="realtime">Realtime rooms</h2><pre><code>${escape(`<div data-room="chat" data-room-user="Ada">
  <span data-room-status></span>
  <div data-room-log></div>
  <template data-room-item="message"><p>%user%: %text%</p></template>
  <form data-room-send><input name="text" data-room-reset></form>
</div>`)}</code></pre>
    <h2 id="native">Browser and native directives</h2><pre><code>${escape(`<button data-native-browser="share" data-native-mobile="share"
        data-native-options='{"title":"WrNexus"}'>Share</button>
<nav data-native-only="mobile">Mobile navigation</nav>
<p data-native-only="browser">Browser instructions</p>
<button data-native-requires="haptics">Haptic action</button>`)}</code></pre>
    <h2 id="other">Other framework attributes</h2><div class="table-wrap"><table><thead><tr><th>Attribute</th><th>Purpose</th></tr></thead><tbody><tr><td><code>data-error</code></td><td>Field validation error destination.</td></tr><tr><td><code>data-success</code></td><td>Successful form message.</td></tr><tr><td><code>data-redirect</code></td><td>Navigation after form success.</td></tr><tr><td><code>data-room-*</code></td><td>Realtime status, templates, sending, and reset behavior.</td></tr><tr><td><code>data-uploader</code></td><td>Config-driven upload widget.</td></tr><tr><td><code>data-wire-theme-*</code></td><td>Theme selection and toggling.</td></tr><tr><td><code>data-wire-lang*</code></td><td>Language selection.</td></tr><tr><td><code>data-native-*</code></td><td>Cross-platform capability and visibility behavior.</td></tr></tbody></table></div></article></main>`,
  ],
  architecture: [
    "Architecture",
    "Understand the WrNexus SSR, compiler, runtime, and package architecture.",
    `<main class="page"><article class="documentation prose standalone"><span class="eyebrow">Concepts</span><h1>Architecture</h1><p>WrNexus separates server work, generated markup, and browser behavior so applications stay understandable and efficient.</p><h2>Request path</h2><pre><code>Request → Router → Middleware → Page/API → SSR document → Browser runtime</code></pre><h2>Compiler</h2><p>The compiler parses .wrn files and lowers state, events, interpolation, loops, conditionals, data bindings, components, and styles into server modules and small declarative browser directives.</p><h2>Runtime</h2><p>The server owns routing, data, secrets, sessions, validation, uploads, and rendering. The browser owns reactive scopes, navigation, forms, realtime clients, and native capability dispatch.</p><h2>Package boundaries</h2><p>Each package is independently installable. Start with the CLI and core, then add database, security, realtime, native, UI, and operational packages as required.</p><div class="actions"><a class="primary" href="/packages/core">Read core API</a><a href="/packages/compiler">Read compiler API</a></div></article></main>`,
  ],
} as const;
for (const [route, [title, description, content]] of Object.entries(guides)) {
  writeFileSync(join(pages, `${route}.wrn`), shell(title, description, content));
}

console.log(
  `Generated ${catalog.length} package pages and ${Object.keys(guides).length + 2} site pages.`,
);
