@pagenary/publisher 2026.6.4 → 2026.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -31,7 +31,7 @@ npx pagenary serve # serve on http://localhost:5173
31
31
 
32
32
  ## What It Is
33
33
 
34
- The publisher takes a catalog of shared section templates plus per-tenant content and configuration and produces a self-contained documentation bundle for each tenant. Each bundle is a static single-page app — hash-based routing (`#/page-id`), no server-side rendering, no runtime dependencies — that you build once and host anywhere that serves files. Tenants share the template catalog but keep isolated content, branding, navigation, and domains, so one repository can publish a dozen distinct sites.
34
+ The publisher takes a catalog of shared section templates plus per-tenant content and configuration and produces a self-contained documentation bundle for each tenant. Each bundle is a static single-page app — hash-based routing (`#/page-id`), no server-side rendering, no runtime dependencies — that you build once and host anywhere that serves files. A per-tenant `<base>` resolves asset and module URLs to the tenant root, so the same bundle serves correctly at a domain root *or* under a subpath mount. Tenants share the template catalog but keep isolated content, branding, navigation, and domains — each with ranked client-side search and SEO-ready output — so one repository can publish a dozen distinct sites.
35
35
 
36
36
  ---
37
37
 
@@ -99,10 +99,12 @@ inspect, build, or run the AIWG project from `~/dev/aiwg`.
99
99
  - **Typography** — IBM Plex Sans/Mono defaults, customizable
100
100
 
101
101
  ### SEO (built in)
102
+ - **Metadata-driven titles** — the shell `<title>` derives from the default page's metadata title (`"<page title> · <brand>"`), and each section sets its own title/description at runtime; the generic brand is only a fallback
102
103
  - **Absolute URLs** — declare a `domain` (or `seo.siteUrl`) and the sitemap, canonical, `og:url`, and `robots` URLs become fully-qualified
103
104
  - **Static snapshots** — crawler-friendly `/pages/<id>.html` for every section, self-canonical (the SPA hash route isn't crawlable)
104
105
  - **`sitemap.xml`, `robots.txt`, `llms.txt`** — generated automatically
105
106
  - **JSON-LD + Open Graph** — `TechArticle`/`BreadcrumbList` per page, optional Organization data, and `og:image`/`twitter:image` via `seo.ogImage`
107
+ - **Subpath-safe assets** — a per-tenant `<base>` keeps stylesheet/script/snapshot URLs valid whether served at a domain root or a subpath
106
108
 
107
109
  ### Export & Sharing
108
110
  - **Export Options** — Current Page or Entire Site
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pagenary/publisher",
3
- "version": "2026.6.4",
3
+ "version": "2026.6.5",
4
4
  "type": "module",
5
5
  "description": "Multi-tenant static publishing component for Pagenary platform.",
6
6
  "license": "AGPL-3.0-or-later",
package/site/index.html CHANGED
@@ -4,7 +4,7 @@
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width,initial-scale=1" />
6
6
  <title>Welcome · Pagenary Docs</title>
7
- <meta name="description" content="Pagenary developer documentation building, configuring, deploying, and extending the multi-tenant documentation publisher, published with Pagenary itself." />
7
+ <meta name="description" content="Turn a git repo of Markdown into a fast, searchable, SEO-ready docs site you host yourself for next to nothing — with the features you&#39;d expect from a paid docs platform. Pagenary&#39;s own developer docs, built and published with Pagenary." />
8
8
  <script>
9
9
  // Resolve all asset/module URLs against the tenant root in both deploy
10
10
  // modes: domain-per-tenant at root (production, with SPA fallback) and a
@@ -21,7 +21,7 @@
21
21
  </script>
22
22
  <link rel="icon" type="image/png" href="./favicon.png" />
23
23
  <link rel="stylesheet" href="./styles.css" />
24
- <meta name="x-build" content="2026-06-15T21:21:38.022Z" />
24
+ <meta name="x-build" content="2026-06-15T21:46:01.346Z" />
25
25
  </head>
26
26
  <body>
27
27
  <a class="skip-link" href="#app">Skip to content</a>
package/site/llms.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  # Pagenary Docs
2
2
 
3
- > Pagenary developer documentation building, configuring, deploying, and extending the multi-tenant documentation publisher, published with Pagenary itself.
3
+ > Turn a git repo of Markdown into a fast, searchable, SEO-ready docs site you host yourself for next to nothing — with the features you'd expect from a paid docs platform. Pagenary's own developer docs, built and published with Pagenary.
4
4
 
5
5
  - [Welcome](https://docs.pagenary.com/pages/welcome.html): What Pagenary is and how this dogfooded portal is built.
6
6
 
@@ -116,7 +116,9 @@ npx pagenary --help # confirm the CLI is available</code></pre>
116
116
  <h2 id="key-features">Key Features</h2>
117
117
  <p>Pagenary includes several powerful features out of the box:</p>
118
118
  <ul>
119
- <li><strong>Command Palette</strong> - Press `Ctrl+K` (or `Cmd+K` on Mac) to quickly navigate, search, and export</li>
119
+ <li><strong>Command Palette</strong> - Press `Ctrl+K` (or `Cmd+K` on Mac) for ranked full-text search (with snippets + infinite scroll), navigation, and export</li>
120
+ <li><strong>SEO-first output</strong> - metadata-driven titles, crawlable `/pages/` snapshots, sitemap/robots/llms.txt, JSON-LD, and Open Graph, generated at build time</li>
121
+ <li><strong>Deploy anywhere</strong> - the same bundle serves at a domain root or under a subpath; any static host, CDN, or the bundled Caddy</li>
120
122
  <li><strong>Mermaid Diagrams</strong> - Embed flowcharts, sequence diagrams, and more using Mermaid syntax</li>
121
123
  <li><strong>Smart External Links</strong> - External links automatically open in new tabs with security headers</li>
122
124
  </ul>
@@ -99,7 +99,7 @@
99
99
  <p>time by `scripts/lib/seo-generator.js` and configured via the tenant</p>
100
100
  <p><a href="#tenant-config#seo-seo">`seo` block</a>.</p>
101
101
  <h2 id="what-the-build-generates">What the build generates</h2>
102
- <table><thead><tr><th style="text-align: left">Artifact</th><th style="text-align: left">Purpose</th></tr></thead><tbody><tr><td style="text-align: left">`sitemap.xml`</td><td style="text-align: left">Absolute `&lt;loc&gt;` for the home page and every section&#39;s static snapshot</td></tr><tr><td style="text-align: left">`robots.txt`</td><td style="text-align: left">Allows `/` and `/pages/`, points at the sitemap</td></tr><tr><td style="text-align: left">`llms.txt`</td><td style="text-align: left">LLM-friendly site index (<a href="https://llmstxt.org/" target="_blank" rel="noopener noreferrer">llmstxt.org</a>)</td></tr><tr><td style="text-align: left">`/pages/&lt;id&gt;.html`</td><td style="text-align: left">Per-section static snapshots with full metadata + JSON-LD, for crawlers</td></tr><tr><td style="text-align: left">JSON-LD</td><td style="text-align: left">`TechArticle` + `BreadcrumbList` per page; `WebSite` + optional `Organization` site-wide</td></tr><tr><td style="text-align: left">Runtime meta</td><td style="text-align: left">`src/seo.js` keeps `&lt;title&gt;`, description, canonical, OG, and Twitter tags in sync as the SPA navigates</td></tr></tbody></table>
102
+ <table><thead><tr><th style="text-align: left">Artifact</th><th style="text-align: left">Purpose</th></tr></thead><tbody><tr><td style="text-align: left">`sitemap.xml`</td><td style="text-align: left">Absolute `&lt;loc&gt;` for the home page and every section&#39;s static snapshot</td></tr><tr><td style="text-align: left">`robots.txt`</td><td style="text-align: left">Allows `/` and `/pages/`, points at the sitemap</td></tr><tr><td style="text-align: left">`llms.txt`</td><td style="text-align: left">LLM-friendly site index (<a href="https://llmstxt.org/" target="_blank" rel="noopener noreferrer">llmstxt.org</a>)</td></tr><tr><td style="text-align: left">`/pages/&lt;id&gt;.html`</td><td style="text-align: left">Per-section static snapshots with full metadata + JSON-LD, for crawlers</td></tr><tr><td style="text-align: left">JSON-LD</td><td style="text-align: left">`TechArticle` + `BreadcrumbList` per page; `WebSite` + optional `Organization` site-wide</td></tr><tr><td style="text-align: left">Shell `&lt;title&gt;`</td><td style="text-align: left">The build sets the static shell title from the <strong>default page&#39;s metadata title</strong> (`&quot;&lt;page title&gt; · &lt;brand&gt;&quot;`), so the crawler-visible root URL is specific, not generic. The brand alone is only a fallback</td></tr><tr><td style="text-align: left">Runtime meta</td><td style="text-align: left">`src/seo.js` keeps `&lt;title&gt;`, description, canonical, OG, and Twitter tags in sync as the SPA navigates</td></tr></tbody></table>
103
103
  <h2 id="make-urls-absolute">Make URLs absolute</h2>
104
104
  <p>Declare a `domain` (or `seo.siteUrl`) on the tenant. This is what turns the</p>
105
105
  <p>sitemap `&lt;loc&gt;`, canonical, `og:url`, and `robots` `Sitemap:` into fully-qualified</p>
@@ -88,26 +88,28 @@
88
88
  <section class="section doc markdown">
89
89
  <div class="doc-content">
90
90
  <h1 id="where-documentation-takes-shape">Where documentation takes shape</h1>
91
- <p>Pagenary is a multi-tenant documentation publishing platform that turns one</p>
92
- <p>shared set of templates into many branded, tenant-specific static sites. Zero</p>
93
- <p>runtime dependencies, hash-based routing, and a Git-aware build pipeline make</p>
94
- <p>it suited to white-label documentation portals one source of truth, any</p>
95
- <p>number of published sites.</p>
91
+ <p>Pagenary turns a folder of Markdown in a git repo into a fast, searchable,</p>
92
+ <p>SEO-ready documentation site you host yourself for next to nothing. Write your</p>
93
+ <p>docs, run one tool, and deploy the static output to any free static host</p>
94
+ <p>(GitHub/Gitea Pages, Netlify, Cloudflare Pages, S3, a CDN, or your own box). No</p>
95
+ <p>server, no database, no monthly SaaS bill — just the things you&#39;d expect from a</p>
96
+ <p>paid docs platform: command-palette search with ranking, theming and branding,</p>
97
+ <p>Mermaid diagrams, syntax highlighting, SEO, and one-click export.</p>
96
98
  <p><strong>This portal is built by Pagenary, from Pagenary&#39;s own documentation.</strong> Every</p>
97
- <p>page you see here is the same publisher pipeline applied to the developer docs</p>
98
- <p>in the repository, served as a static single-page app.</p>
99
+ <p>page you see here is the same publisher pipeline applied to the developer docs in</p>
100
+ <p>the repository, served as a static single-page app.</p>
99
101
  <h2 id="start-here">Start here</h2>
100
102
  <ul>
101
- <li><strong><a href="#quickstart">Quickstart</a></strong> — install, build the default bundle, and serve it locally.</li>
102
- <li><strong><a href="#architecture">Architecture</a></strong> — the static SPA pattern, build pipeline, and tenant content model.</li>
103
- <li><strong><a href="#tenant-config">Tenant Configuration</a></strong> — every `config.json` option for branding, theming, and export.</li>
103
+ <li><strong><a href="#quickstart">Quickstart</a></strong> — install, build your first site, and serve it locally.</li>
104
+ <li><strong><a href="#architecture">Architecture</a></strong> — the static SPA pattern, build pipeline, and content model.</li>
105
+ <li><strong><a href="#tenant-config">Tenant Configuration</a></strong> — every `config.json` option for branding, theming, SEO, and export.</li>
104
106
  </ul>
105
- <h2 id="how-a-tenant-works">How a tenant works</h2>
106
- <p>A tenant is a thin layer — content, a `config.json`, and a `manifest.json` —</p>
107
- <p>over the shared template catalog. Branding, theming, and navigation are **data,</p>
108
- <p>not code**: a tenant changes its look through configuration, never by forking</p>
109
- <p>the generator. The build produces a self-contained bundle under</p>
110
- <p>`dist/&lt;tenant-id&gt;/` that you can host anywhere that serves files.</p>
107
+ <h2 id="scale-to-many-sites-when-you-need-to">Scale to many sites when you need to</h2>
108
+ <p>One site is just content, a `config.json`, and a `manifest.json`. Need more than</p>
109
+ <p>one? The same tool publishes many sites from a shared template catalog — branding,</p>
110
+ <p>theming, and navigation are <strong>data, not code</strong>, so standing up another branded</p>
111
+ <p>site is cheap, and a Git-aware build rebuilds only what changed. Pagenary scales</p>
112
+ <p>from a weekend project to a multi-product portal without changing tools.</p>
111
113
  </div>
112
114
  </section>
113
115
  </div>
package/site/robots.txt CHANGED
@@ -1,5 +1,5 @@
1
1
  # Pagenary Docs
2
- # Generated: 2026-06-15T21:21:38.574Z
2
+ # Generated: 2026-06-15T21:46:01.946Z
3
3
 
4
4
  User-agent: *
5
5
  Allow: /
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "schema_version": "aiwg.fortemi.index.chunk-manifest.v1",
3
- "generated_at": "1977-09-23T15:35:58.000Z",
3
+ "generated_at": "1989-11-27T18:58:05.000Z",
4
4
  "source": {
5
5
  "repo": "pagenary",
6
6
  "privacy": "public",
7
- "build_hash": "0e89445e615e2d69"
7
+ "build_hash": "257183bd1fb7ac71"
8
8
  },
9
9
  "total": 9,
10
10
  "part_size": 100,
@@ -40,7 +40,7 @@
40
40
  "classification": "public",
41
41
  "pii": false
42
42
  },
43
- "updated_at": "1977-09-23T15:35:58.000Z"
43
+ "updated_at": "1989-11-27T18:58:05.000Z"
44
44
  },
45
45
  {
46
46
  "schema_version": "aiwg.fortemi.index.record.v1",
@@ -79,7 +79,7 @@
79
79
  "classification": "public",
80
80
  "pii": false
81
81
  },
82
- "updated_at": "1977-09-23T15:35:58.000Z"
82
+ "updated_at": "1989-11-27T18:58:05.000Z"
83
83
  },
84
84
  {
85
85
  "schema_version": "aiwg.fortemi.index.record.v1",
@@ -118,7 +118,7 @@
118
118
  "classification": "public",
119
119
  "pii": false
120
120
  },
121
- "updated_at": "1977-09-23T15:35:58.000Z"
121
+ "updated_at": "1989-11-27T18:58:05.000Z"
122
122
  },
123
123
  {
124
124
  "schema_version": "aiwg.fortemi.index.record.v1",
@@ -157,7 +157,7 @@
157
157
  "classification": "public",
158
158
  "pii": false
159
159
  },
160
- "updated_at": "1977-09-23T15:35:58.000Z"
160
+ "updated_at": "1989-11-27T18:58:05.000Z"
161
161
  },
162
162
  {
163
163
  "schema_version": "aiwg.fortemi.index.record.v1",
@@ -196,7 +196,7 @@
196
196
  "classification": "public",
197
197
  "pii": false
198
198
  },
199
- "updated_at": "1977-09-23T15:35:58.000Z"
199
+ "updated_at": "1989-11-27T18:58:05.000Z"
200
200
  },
201
201
  {
202
202
  "schema_version": "aiwg.fortemi.index.record.v1",
@@ -208,7 +208,7 @@
208
208
  "locator": "#/quickstart"
209
209
  },
210
210
  "title": "Quickstart",
211
- "text": "Quickstart Install, build the default bundle, and serve it locally. Getting Started Quick Start Guide Create your first Pagenary documentation site in 10 minutes. For a more guided, zero-assumptions walkthrough, see Getting Started . Prerequisites Node.js ≥ 16 (20+ recommended) Step 1: Install Pagenary Use the published package — no clone required: npm install --save-dev @pagenary/publisher npx pagenary --help # confirm the CLI is available Building Pagenary from source instead? Clone the repo and work from the workspace (for contributors / modifying the generator): ```bash git clone https://github.com/jmagly/pagenary.git cd pagenary && npm run bootstrap npm run publisher:build && npm run publisher:serve ``` Key Features Pagenary includes several powerful features out of the box: Command Palette - Press `Ctrl+K` (or `Cmd+K` on Mac) to quickly navigate, search, and export Mermaid Diagrams - Embed flowcharts, sequence diagrams, and more using Mermaid syntax Smart External Links - External links automatically open in new tabs with security headers Step 2: Create Your Tenant Directory Create a new directory for your documentation (can be anywhere on your system): mkdir ~/my-docs cd ~/my-docs Create the basic structure: mkdir content Step 3: Add Branding Configuration Create `config.json`: { \"title\": \"My Product Documentation\", \"description\": \"Complete guide to using My Product\", \"brandMark\": \"MY\", \"brandSub\": \"PRODUCT\", \"tagline\": \"Documentation that works\", \"copyright\": \"My Company\", \"accentColor\": \"#3B82F6\", \"surfaceColor\": \"#F8FAFC\" } Step 4: Create Your First Content Create `content/welcome.md`: # Welcome to My Product This is your documentation home page. ## Getting Started Here's what you need to know to get started with My Product. ### Installation \\`\\`\\`bash npm install my-product \\`\\`\\` ### Quick Example \\`\\`\\`javascript import { MyProduct } from 'my-product'; const app = new MyProduct(); app.start(); \\`\\`\\` ## Features - **Fast** - Built for speed - **Simple** - Easy to use - **Powerful** - Full-featured ## Architecture \\`\\`\\`mermaid graph TD A[User] --> B[Frontend] B --> C[API] C --> D[Database] \\`\\`\\` Create `content/installation.md`: # Installation Guide ## Requirements - Node.js 18 or higher - npm or yarn ## Install via npm \\`\\`\\`bash npm install my-product \\`\\`\\` ## Install via yarn \\`\\`\\`bash yarn add my-product \\`\\`\\` ## Verify Installation \\`\\`\\`bash npx my-product --version \\`\\`\\` Step 5: Create Navigation Manifest Create `manifest.json`: [ { \"id\": \"welcome\", \"title\": \"Welcome\", \"summary\": \"Introduction to My Product\", \"file\": \"welcome.md\" }, { \"id\": \"installation\", \"title\": \"Installation\", \"summary\": \"How to install My Product\", \"file\": \"installation.md\" } ] Step 6: Register Your Tenant Create (or edit) a `tenants.json` at your project root and add your tenant. The registry is an array; `source` is an object (`local` or `git`): { \"tenants\": [ { \"id\": \"my-docs\", \"source\": { \"type\": \"local\", \"path\": \"./my-docs\" }, \"strictLinks\": true } ] } Building from source? Edit `apps/publisher/tenants.json` in the cloned repo instead. Step 7: Build and Preview # Build your tenant npx pagenary build:tenants my-docs # Start the server npx pagenary serve # Visit http://localhost:5173/my-docs/ From source, the equivalents are `npm run build:tenants my-docs` and `npm run serve`. You should see your documentation with your branding applied. Step 8: Set Up Local Domain (Optional) For a more realistic preview with custom domains: 1. Edit `/etc/hosts` (Linux/Mac) or `C:\\Windows\\System32\\drivers\\etc\\hosts` (Windows): 127.0.0.1 my-docs.local 2. Start the Caddy server: npm run caddy:up 3. Visit http://my-docs.local Next Steps Add More Content Create additional `.md`, `.html`, or `.js` files in `content/`: content/ ├── welcome.md ├── installation.md ├── guides/ │ ├── _manifest.json │ ├── getting-started.md │ └── advanced.md └── api/ ├── _manifest.json └── reference.md Organize with Section Manifests Create `content/guides/_manifest.json`: { \"title\": \"Guides\", \"sections\": [ { \"id\": \"getting-started\", \"title\": \"Getting Started\", \"file\": \"getting-started.md\" }, { \"id\": \"advanced\", \"title\": \"Advanced Usage\", \"file\": \"advanced.md\" } ] } Add Rich Content Tables: Feature Status Search Ready Export Ready Diagrams: sequenceDiagram User->>API: Request API->>DB: Query DB-->>API: Results API-->>User: Response Customize Theme Adjust colors in `config.json`: Color Purpose Example `accentColor` Links, buttons, highlights `#3B82F6` (blue) `surfaceColor` Page background `#F8FAFC` (off-white) Deploy Your built site is in `dist/my-docs/`. Deploy it anywhere that serves static files: Netlify/Vercel : Point to `dist/my-docs/` S3/GCS : Upload the folder Docker : Use the included Caddy setup Troubleshooting Content not appearing? 1. Check that `manifest.json` references the correct file paths 2. Verify files exist in `content/` 3. Run `npx pagenary build:tenants my-docs` and check for errors Styles not applied? 1. Verify `config.json` is valid JSON 2. Check color values are valid hex codes (e.g., `#3B82F6`) Search not working? The command palette loads a prebuilt static index (`dist/<tenant>/search-index/`) on first open — wait a moment for \"Indexing content…\" to clear. If that directory is missing (e.g., an older build), search falls back to indexing in the browser on first use. Rebuild with `npm run build:tenants` to regenerate the static index. Resources Tenant Configuration - All config options Architecture - How it works API Reference - Module documentation Deployment - Hosting guide",
211
+ "text": "Quickstart Install, build the default bundle, and serve it locally. Getting Started Quick Start Guide Create your first Pagenary documentation site in 10 minutes. For a more guided, zero-assumptions walkthrough, see Getting Started . Prerequisites Node.js ≥ 16 (20+ recommended) Step 1: Install Pagenary Use the published package — no clone required: npm install --save-dev @pagenary/publisher npx pagenary --help # confirm the CLI is available Building Pagenary from source instead? Clone the repo and work from the workspace (for contributors / modifying the generator): ```bash git clone https://github.com/jmagly/pagenary.git cd pagenary && npm run bootstrap npm run publisher:build && npm run publisher:serve ``` Key Features Pagenary includes several powerful features out of the box: Command Palette - Press `Ctrl+K` (or `Cmd+K` on Mac) for ranked full-text search (with snippets + infinite scroll), navigation, and export SEO-first output - metadata-driven titles, crawlable `/pages/` snapshots, sitemap/robots/llms.txt, JSON-LD, and Open Graph, generated at build time Deploy anywhere - the same bundle serves at a domain root or under a subpath; any static host, CDN, or the bundled Caddy Mermaid Diagrams - Embed flowcharts, sequence diagrams, and more using Mermaid syntax Smart External Links - External links automatically open in new tabs with security headers Step 2: Create Your Tenant Directory Create a new directory for your documentation (can be anywhere on your system): mkdir ~/my-docs cd ~/my-docs Create the basic structure: mkdir content Step 3: Add Branding Configuration Create `config.json`: { \"title\": \"My Product Documentation\", \"description\": \"Complete guide to using My Product\", \"brandMark\": \"MY\", \"brandSub\": \"PRODUCT\", \"tagline\": \"Documentation that works\", \"copyright\": \"My Company\", \"accentColor\": \"#3B82F6\", \"surfaceColor\": \"#F8FAFC\" } Step 4: Create Your First Content Create `content/welcome.md`: # Welcome to My Product This is your documentation home page. ## Getting Started Here's what you need to know to get started with My Product. ### Installation \\`\\`\\`bash npm install my-product \\`\\`\\` ### Quick Example \\`\\`\\`javascript import { MyProduct } from 'my-product'; const app = new MyProduct(); app.start(); \\`\\`\\` ## Features - **Fast** - Built for speed - **Simple** - Easy to use - **Powerful** - Full-featured ## Architecture \\`\\`\\`mermaid graph TD A[User] --> B[Frontend] B --> C[API] C --> D[Database] \\`\\`\\` Create `content/installation.md`: # Installation Guide ## Requirements - Node.js 18 or higher - npm or yarn ## Install via npm \\`\\`\\`bash npm install my-product \\`\\`\\` ## Install via yarn \\`\\`\\`bash yarn add my-product \\`\\`\\` ## Verify Installation \\`\\`\\`bash npx my-product --version \\`\\`\\` Step 5: Create Navigation Manifest Create `manifest.json`: [ { \"id\": \"welcome\", \"title\": \"Welcome\", \"summary\": \"Introduction to My Product\", \"file\": \"welcome.md\" }, { \"id\": \"installation\", \"title\": \"Installation\", \"summary\": \"How to install My Product\", \"file\": \"installation.md\" } ] Step 6: Register Your Tenant Create (or edit) a `tenants.json` at your project root and add your tenant. The registry is an array; `source` is an object (`local` or `git`): { \"tenants\": [ { \"id\": \"my-docs\", \"source\": { \"type\": \"local\", \"path\": \"./my-docs\" }, \"strictLinks\": true } ] } Building from source? Edit `apps/publisher/tenants.json` in the cloned repo instead. Step 7: Build and Preview # Build your tenant npx pagenary build:tenants my-docs # Start the server npx pagenary serve # Visit http://localhost:5173/my-docs/ From source, the equivalents are `npm run build:tenants my-docs` and `npm run serve`. You should see your documentation with your branding applied. Step 8: Set Up Local Domain (Optional) For a more realistic preview with custom domains: 1. Edit `/etc/hosts` (Linux/Mac) or `C:\\Windows\\System32\\drivers\\etc\\hosts` (Windows): 127.0.0.1 my-docs.local 2. Start the Caddy server: npm run caddy:up 3. Visit http://my-docs.local Next Steps Add More Content Create additional `.md`, `.html`, or `.js` files in `content/`: content/ ├── welcome.md ├── installation.md ├── guides/ │ ├── _manifest.json │ ├── getting-started.md │ └── advanced.md └── api/ ├── _manifest.json └── reference.md Organize with Section Manifests Create `content/guides/_manifest.json`: { \"title\": \"Guides\", \"sections\": [ { \"id\": \"getting-started\", \"title\": \"Getting Started\", \"file\": \"getting-started.md\" }, { \"id\": \"advanced\", \"title\": \"Advanced Usage\", \"file\": \"advanced.md\" } ] } Add Rich Content Tables: Feature Status Search Ready Export Ready Diagrams: sequenceDiagram User->>API: Request API->>DB: Query DB-->>API: Results API-->>User: Response Customize Theme Adjust colors in `config.json`: Color Purpose Example `accentColor` Links, buttons, highlights `#3B82F6` (blue) `surfaceColor` Page background `#F8FAFC` (off-white) Deploy Your built site is in `dist/my-docs/`. Deploy it anywhere that serves static files: Netlify/Vercel : Point to `dist/my-docs/` S3/GCS : Upload the folder Docker : Use the included Caddy setup Troubleshooting Content not appearing? 1. Check that `manifest.json` references the correct file paths 2. Verify files exist in `content/` 3. Run `npx pagenary build:tenants my-docs` and check for errors Styles not applied? 1. Verify `config.json` is valid JSON 2. Check color values are valid hex codes (e.g., `#3B82F6`) Search not working? The command palette loads a prebuilt static index (`dist/<tenant>/search-index/`) on first open — wait a moment for \"Indexing content…\" to clear. If that directory is missing (e.g., an older build), search falls back to indexing in the browser on first use. Rebuild with `npm run build:tenants` to regenerate the static index. Resources Tenant Configuration - All config options Architecture - How it works API Reference - Module documentation Deployment - Hosting guide",
212
212
  "facets": {
213
213
  "section": [
214
214
  "quickstart"
@@ -235,7 +235,7 @@
235
235
  "classification": "public",
236
236
  "pii": false
237
237
  },
238
- "updated_at": "1977-09-23T15:35:58.000Z"
238
+ "updated_at": "1989-11-27T18:58:05.000Z"
239
239
  },
240
240
  {
241
241
  "schema_version": "aiwg.fortemi.index.record.v1",
@@ -247,7 +247,7 @@
247
247
  "locator": "#/seo-strategy"
248
248
  },
249
249
  "title": "SEO Strategy",
250
- "text": "SEO Strategy Metadata, hash-routing considerations, and discoverability. Reference SEO Strategy Pagenary publishes a hash-routed single-page app, so it generates **crawler-facing static artifacts** alongside the SPA. These are produced automatically at build time by `scripts/lib/seo-generator.js` and configured via the tenant `seo` block . What the build generates Artifact Purpose `sitemap.xml` Absolute `<loc>` for the home page and every section's static snapshot `robots.txt` Allows `/` and `/pages/`, points at the sitemap `llms.txt` LLM-friendly site index ( llmstxt.org ) `/pages/<id>.html` Per-section static snapshots with full metadata + JSON-LD, for crawlers JSON-LD `TechArticle` + `BreadcrumbList` per page; `WebSite` + optional `Organization` site-wide Runtime meta `src/seo.js` keeps `<title>`, description, canonical, OG, and Twitter tags in sync as the SPA navigates Make URLs absolute Declare a `domain` (or `seo.siteUrl`) on the tenant. This is what turns the sitemap `<loc>`, canonical, `og:url`, and `robots` `Sitemap:` into fully-qualified URLs. The sitemap protocol requires absolute URLs, so a tenant with neither set emits a non-compliant sitemap — the build prints a warning when that happens. Precedence: `seo.siteUrl` → `domain` (https-prefixed) → relative (warned). Canonical strategy Static snapshots and the runtime SPA canonicalize to the crawlable static URL (`/pages/<id>.html`), not the SPA `#hash` route. Search engines ignore URL fragments, so hash canonicals (`/#section`) would collapse every page onto the homepage. The `#hash` route is still used for the human-facing \"interactive version\" link and the JavaScript redirect on the static page. Social cards Set `seo.ogImage` (absolute or site-relative) to emit `og:image` / `twitter:image` and upgrade `twitter:card` to `summary_large_image`. Individual pages can override it with an `ogImage` field on the manifest entry. Authoring practices Keep manifest `summary` values concise — they power the meta description, search results, link previews, and the export document. Use human-readable, hyphenated, lowercase section `id`s — they become both the hash route and the static page filename (`/` becomes `--`). Gate broken links in CI with `strictLinks: true` (see Tenant Configuration ).",
250
+ "text": "SEO Strategy Metadata, hash-routing considerations, and discoverability. Reference SEO Strategy Pagenary publishes a hash-routed single-page app, so it generates **crawler-facing static artifacts** alongside the SPA. These are produced automatically at build time by `scripts/lib/seo-generator.js` and configured via the tenant `seo` block . What the build generates Artifact Purpose `sitemap.xml` Absolute `<loc>` for the home page and every section's static snapshot `robots.txt` Allows `/` and `/pages/`, points at the sitemap `llms.txt` LLM-friendly site index ( llmstxt.org ) `/pages/<id>.html` Per-section static snapshots with full metadata + JSON-LD, for crawlers JSON-LD `TechArticle` + `BreadcrumbList` per page; `WebSite` + optional `Organization` site-wide Shell `<title>` The build sets the static shell title from the default page's metadata title (`\"<page title> · <brand>\"`), so the crawler-visible root URL is specific, not generic. The brand alone is only a fallback Runtime meta `src/seo.js` keeps `<title>`, description, canonical, OG, and Twitter tags in sync as the SPA navigates Make URLs absolute Declare a `domain` (or `seo.siteUrl`) on the tenant. This is what turns the sitemap `<loc>`, canonical, `og:url`, and `robots` `Sitemap:` into fully-qualified URLs. The sitemap protocol requires absolute URLs, so a tenant with neither set emits a non-compliant sitemap — the build prints a warning when that happens. Precedence: `seo.siteUrl` → `domain` (https-prefixed) → relative (warned). Canonical strategy Static snapshots and the runtime SPA canonicalize to the crawlable static URL (`/pages/<id>.html`), not the SPA `#hash` route. Search engines ignore URL fragments, so hash canonicals (`/#section`) would collapse every page onto the homepage. The `#hash` route is still used for the human-facing \"interactive version\" link and the JavaScript redirect on the static page. Social cards Set `seo.ogImage` (absolute or site-relative) to emit `og:image` / `twitter:image` and upgrade `twitter:card` to `summary_large_image`. Individual pages can override it with an `ogImage` field on the manifest entry. Authoring practices Keep manifest `summary` values concise — they power the meta description, search results, link previews, and the export document. Use human-readable, hyphenated, lowercase section `id`s — they become both the hash route and the static page filename (`/` becomes `--`). Gate broken links in CI with `strictLinks: true` (see Tenant Configuration ).",
251
251
  "facets": {
252
252
  "section": [
253
253
  "seo-strategy"
@@ -274,7 +274,7 @@
274
274
  "classification": "public",
275
275
  "pii": false
276
276
  },
277
- "updated_at": "1977-09-23T15:35:58.000Z"
277
+ "updated_at": "1989-11-27T18:58:05.000Z"
278
278
  },
279
279
  {
280
280
  "schema_version": "aiwg.fortemi.index.record.v1",
@@ -313,7 +313,7 @@
313
313
  "classification": "public",
314
314
  "pii": false
315
315
  },
316
- "updated_at": "1977-09-23T15:35:58.000Z"
316
+ "updated_at": "1989-11-27T18:58:05.000Z"
317
317
  },
318
318
  {
319
319
  "schema_version": "aiwg.fortemi.index.record.v1",
@@ -325,7 +325,7 @@
325
325
  "locator": "#/welcome"
326
326
  },
327
327
  "title": "Welcome",
328
- "text": "Welcome What Pagenary is and how this dogfooded portal is built. Welcome Where documentation takes shape Pagenary is a multi-tenant documentation publishing platform that turns one shared set of templates into many branded, tenant-specific static sites. Zero runtime dependencies, hash-based routing, and a Git-aware build pipeline make it suited to white-label documentation portalsone source of truth, any number of published sites. This portal is built by Pagenary, from Pagenary's own documentation. Every page you see here is the same publisher pipeline applied to the developer docs in the repository, served as a static single-page app. Start here Quickstart — install, build the default bundle, and serve it locally. Architecture — the static SPA pattern, build pipeline, and tenant content model. Tenant Configuration — every `config.json` option for branding, theming, and export. How a tenant works A tenant is a thin layer content, a `config.json`, and a `manifest.json` over the shared template catalog. Branding, theming, and navigation are **data, not code**: a tenant changes its look through configuration, never by forking the generator. The build produces a self-contained bundle under `dist/<tenant-id>/` that you can host anywhere that serves files.",
328
+ "text": "Welcome What Pagenary is and how this dogfooded portal is built. Welcome Where documentation takes shape Pagenary turns a folder of Markdown in a git repo into a fast, searchable, SEO-ready documentation site you host yourself for next to nothing. Write your docs, run one tool, and deploy the static output to any free static host (GitHub/Gitea Pages, Netlify, Cloudflare Pages, S3, a CDN, or your own box). No server, no database, no monthly SaaS bill just the things you'd expect from a paid docs platform: command-palette search with ranking, theming and branding, Mermaid diagrams, syntax highlighting, SEO, and one-click export. This portal is built by Pagenary, from Pagenary's own documentation. Every page you see here is the same publisher pipeline applied to the developer docs in the repository, served as a static single-page app. Start here Quickstart — install, build your first site, and serve it locally. Architecture — the static SPA pattern, build pipeline, and content model. Tenant Configuration — every `config.json` option for branding, theming, SEO, and export. Scale to many sites when you need to One site is just content, a `config.json`, and a `manifest.json`. Need more than one? The same tool publishes many sites from a shared template catalog — branding, theming, and navigation are data, not code , so standing up another branded site is cheap, and a Git-aware build rebuilds only what changed. Pagenary scales from a weekend project to a multi-product portal without changing tools.",
329
329
  "facets": {
330
330
  "section": [
331
331
  "welcome"
@@ -352,7 +352,7 @@
352
352
  "classification": "public",
353
353
  "pii": false
354
354
  },
355
- "updated_at": "1977-09-23T15:35:58.000Z"
355
+ "updated_at": "1989-11-27T18:58:05.000Z"
356
356
  }
357
357
  ]
358
358
  }
@@ -1,3 +1,3 @@
1
1
  export async function load() {
2
- return { html: "<section class=\"section doc markdown\">\n <div class=\"doc-content\">\n<h1 id=\"quick-start-guide\">Quick Start Guide</h1>\n<p>Create your first Pagenary documentation site in 10 minutes. For a more guided,</p>\n<p>zero-assumptions walkthrough, see <a href=\"#getting-started\">Getting Started</a>.</p>\n<h2 id=\"prerequisites\">Prerequisites</h2>\n<ul>\n<li>Node.js ≥ 16 (20+ recommended)</li>\n</ul>\n<h2 id=\"step-1-install-pagenary\">Step 1: Install Pagenary</h2>\n<p>Use the published package — no clone required:</p>\n<pre><code class=\"language-bash\">npm install --save-dev @pagenary/publisher\nnpx pagenary --help # confirm the CLI is available</code></pre>\n<blockquote>\n<p><strong>Building Pagenary from source instead?</strong> Clone the repo and work from the</p>\n<p>workspace (for contributors / modifying the generator):</p>\n<p>```bash</p>\n<p>git clone https://github.com/jmagly/pagenary.git</p>\n<p>cd pagenary &amp;&amp; npm run bootstrap</p>\n<p>npm run publisher:build &amp;&amp; npm run publisher:serve</p>\n<p>```</p>\n</blockquote>\n<h2 id=\"key-features\">Key Features</h2>\n<p>Pagenary includes several powerful features out of the box:</p>\n<ul>\n<li><strong>Command Palette</strong> - Press `Ctrl+K` (or `Cmd+K` on Mac) to quickly navigate, search, and export</li>\n<li><strong>Mermaid Diagrams</strong> - Embed flowcharts, sequence diagrams, and more using Mermaid syntax</li>\n<li><strong>Smart External Links</strong> - External links automatically open in new tabs with security headers</li>\n</ul>\n<h2 id=\"step-2-create-your-tenant-directory\">Step 2: Create Your Tenant Directory</h2>\n<p>Create a new directory for your documentation (can be anywhere on your system):</p>\n<pre><code class=\"language-bash\">mkdir ~/my-docs\ncd ~/my-docs</code></pre>\n<p>Create the basic structure:</p>\n<pre><code class=\"language-bash\">mkdir content</code></pre>\n<h2 id=\"step-3-add-branding-configuration\">Step 3: Add Branding Configuration</h2>\n<p>Create `config.json`:</p>\n<pre><code class=\"language-json\">{\n &quot;title&quot;: &quot;My Product Documentation&quot;,\n &quot;description&quot;: &quot;Complete guide to using My Product&quot;,\n &quot;brandMark&quot;: &quot;MY&quot;,\n &quot;brandSub&quot;: &quot;PRODUCT&quot;,\n &quot;tagline&quot;: &quot;Documentation that works&quot;,\n &quot;copyright&quot;: &quot;My Company&quot;,\n &quot;accentColor&quot;: &quot;#3B82F6&quot;,\n &quot;surfaceColor&quot;: &quot;#F8FAFC&quot;\n}</code></pre>\n<h2 id=\"step-4-create-your-first-content\">Step 4: Create Your First Content</h2>\n<p>Create `content/welcome.md`:</p>\n<pre><code class=\"language-markdown\"># Welcome to My Product\n\nThis is your documentation home page.\n\n## Getting Started\n\nHere&#39;s what you need to know to get started with My Product.\n\n### Installation\n\n\\`\\`\\`bash\nnpm install my-product\n\\`\\`\\`\n\n### Quick Example\n\n\\`\\`\\`javascript\nimport { MyProduct } from &#39;my-product&#39;;\n\nconst app = new MyProduct();\napp.start();\n\\`\\`\\`\n\n## Features\n\n- **Fast** - Built for speed\n- **Simple** - Easy to use\n- **Powerful** - Full-featured\n\n## Architecture\n\n\\`\\`\\`mermaid\ngraph TD\n A[User] --&gt; B[Frontend]\n B --&gt; C[API]\n C --&gt; D[Database]\n\\`\\`\\`</code></pre>\n<p>Create `content/installation.md`:</p>\n<pre><code class=\"language-markdown\"># Installation Guide\n\n## Requirements\n\n- Node.js 18 or higher\n- npm or yarn\n\n## Install via npm\n\n\\`\\`\\`bash\nnpm install my-product\n\\`\\`\\`\n\n## Install via yarn\n\n\\`\\`\\`bash\nyarn add my-product\n\\`\\`\\`\n\n## Verify Installation\n\n\\`\\`\\`bash\nnpx my-product --version\n\\`\\`\\`</code></pre>\n<h2 id=\"step-5-create-navigation-manifest\">Step 5: Create Navigation Manifest</h2>\n<p>Create `manifest.json`:</p>\n<pre><code class=\"language-json\">[\n {\n &quot;id&quot;: &quot;welcome&quot;,\n &quot;title&quot;: &quot;Welcome&quot;,\n &quot;summary&quot;: &quot;Introduction to My Product&quot;,\n &quot;file&quot;: &quot;welcome.md&quot;\n },\n {\n &quot;id&quot;: &quot;installation&quot;,\n &quot;title&quot;: &quot;Installation&quot;,\n &quot;summary&quot;: &quot;How to install My Product&quot;,\n &quot;file&quot;: &quot;installation.md&quot;\n }\n]</code></pre>\n<h2 id=\"step-6-register-your-tenant\">Step 6: Register Your Tenant</h2>\n<p>Create (or edit) a `tenants.json` at your project root and add your tenant. The</p>\n<p>registry is an array; `source` is an object (`local` or `git`):</p>\n<pre><code class=\"language-json\">{\n &quot;tenants&quot;: [\n {\n &quot;id&quot;: &quot;my-docs&quot;,\n &quot;source&quot;: { &quot;type&quot;: &quot;local&quot;, &quot;path&quot;: &quot;./my-docs&quot; },\n &quot;strictLinks&quot;: true\n }\n ]\n}</code></pre>\n<blockquote>\n<p>Building from source? Edit `apps/publisher/tenants.json` in the cloned repo instead.</p>\n</blockquote>\n<h2 id=\"step-7-build-and-preview\">Step 7: Build and Preview</h2>\n<pre><code class=\"language-bash\"># Build your tenant\nnpx pagenary build:tenants my-docs\n\n# Start the server\nnpx pagenary serve\n\n# Visit http://localhost:5173/my-docs/</code></pre>\n<blockquote>\n<p>From source, the equivalents are `npm run build:tenants my-docs` and `npm run serve`.</p>\n</blockquote>\n<p>You should see your documentation with your branding applied.</p>\n<h2 id=\"step-8-set-up-local-domain-optional\">Step 8: Set Up Local Domain (Optional)</h2>\n<p>For a more realistic preview with custom domains:</p>\n<p>1. Edit `/etc/hosts` (Linux/Mac) or `C:\\Windows\\System32\\drivers\\etc\\hosts` (Windows):</p>\n<pre><code>127.0.0.1 my-docs.local</code></pre>\n<p>2. Start the Caddy server:</p>\n<pre><code class=\"language-bash\">npm run caddy:up</code></pre>\n<p>3. Visit http://my-docs.local</p>\n<h2 id=\"next-steps\">Next Steps</h2>\n<h3 id=\"add-more-content\">Add More Content</h3>\n<p>Create additional `.md`, `.html`, or `.js` files in `content/`:</p>\n<pre><code>content/\n├── welcome.md\n├── installation.md\n├── guides/\n│ ├── _manifest.json\n│ ├── getting-started.md\n│ └── advanced.md\n└── api/\n ├── _manifest.json\n └── reference.md</code></pre>\n<h3 id=\"organize-with-section-manifests\">Organize with Section Manifests</h3>\n<p>Create `content/guides/_manifest.json`:</p>\n<pre><code class=\"language-json\">{\n &quot;title&quot;: &quot;Guides&quot;,\n &quot;sections&quot;: [\n { &quot;id&quot;: &quot;getting-started&quot;, &quot;title&quot;: &quot;Getting Started&quot;, &quot;file&quot;: &quot;getting-started.md&quot; },\n { &quot;id&quot;: &quot;advanced&quot;, &quot;title&quot;: &quot;Advanced Usage&quot;, &quot;file&quot;: &quot;advanced.md&quot; }\n ]\n}</code></pre>\n<h3 id=\"add-rich-content\">Add Rich Content</h3>\n<p><strong>Tables:</strong></p>\n<div class=\"html-block\"><table class=\"spec-table\">\n <thead>\n <tr><th>Feature</th><th>Status</th></tr>\n </thead>\n <tbody>\n <tr><td>Search</td><td>Ready</td></tr>\n <tr><td>Export</td><td>Ready</td></tr>\n </tbody>\n</table></div>\n<p><strong>Diagrams:</strong></p>\n<pre><code class=\"language-mermaid\">sequenceDiagram\n User-&gt;&gt;API: Request\n API-&gt;&gt;DB: Query\n DB--&gt;&gt;API: Results\n API--&gt;&gt;User: Response</code></pre>\n<h3 id=\"customize-theme\">Customize Theme</h3>\n<p>Adjust colors in `config.json`:</p>\n<table><thead><tr><th style=\"text-align: left\">Color</th><th style=\"text-align: left\">Purpose</th><th style=\"text-align: left\">Example</th></tr></thead><tbody><tr><td style=\"text-align: left\">`accentColor`</td><td style=\"text-align: left\">Links, buttons, highlights</td><td style=\"text-align: left\">`#3B82F6` (blue)</td></tr><tr><td style=\"text-align: left\">`surfaceColor`</td><td style=\"text-align: left\">Page background</td><td style=\"text-align: left\">`#F8FAFC` (off-white)</td></tr></tbody></table>\n<h3 id=\"deploy\">Deploy</h3>\n<p>Your built site is in `dist/my-docs/`. Deploy it anywhere that serves static files:</p>\n<ul>\n<li><strong>Netlify/Vercel</strong>: Point to `dist/my-docs/`</li>\n<li><strong>S3/GCS</strong>: Upload the folder</li>\n<li><strong>Docker</strong>: Use the included Caddy setup</li>\n</ul>\n<h2 id=\"troubleshooting\">Troubleshooting</h2>\n<h3 id=\"content-not-appearing\">Content not appearing?</h3>\n<p>1. Check that `manifest.json` references the correct file paths</p>\n<p>2. Verify files exist in `content/`</p>\n<p>3. Run `npx pagenary build:tenants my-docs` and check for errors</p>\n<h3 id=\"styles-not-applied\">Styles not applied?</h3>\n<p>1. Verify `config.json` is valid JSON</p>\n<p>2. Check color values are valid hex codes (e.g., `#3B82F6`)</p>\n<h3 id=\"search-not-working\">Search not working?</h3>\n<p>The command palette loads a prebuilt static index (`dist/&lt;tenant&gt;/search-index/`)</p>\n<p>on first open — wait a moment for &quot;Indexing content…&quot; to clear. If that directory</p>\n<p>is missing (e.g., an older build), search falls back to indexing in the browser on</p>\n<p>first use. Rebuild with `npm run build:tenants` to regenerate the static index.</p>\n<h2 id=\"resources\">Resources</h2>\n<ul>\n<li><a href=\"#tenant-config\">Tenant Configuration</a> - All config options</li>\n<li><a href=\"#architecture\">Architecture</a> - How it works</li>\n<li><a href=\"#api\">API Reference</a> - Module documentation</li>\n<li><a href=\"#deployment\">Deployment</a> - Hosting guide</li>\n</ul>\n </div>\n</section>" };
2
+ return { html: "<section class=\"section doc markdown\">\n <div class=\"doc-content\">\n<h1 id=\"quick-start-guide\">Quick Start Guide</h1>\n<p>Create your first Pagenary documentation site in 10 minutes. For a more guided,</p>\n<p>zero-assumptions walkthrough, see <a href=\"#getting-started\">Getting Started</a>.</p>\n<h2 id=\"prerequisites\">Prerequisites</h2>\n<ul>\n<li>Node.js ≥ 16 (20+ recommended)</li>\n</ul>\n<h2 id=\"step-1-install-pagenary\">Step 1: Install Pagenary</h2>\n<p>Use the published package — no clone required:</p>\n<pre><code class=\"language-bash\">npm install --save-dev @pagenary/publisher\nnpx pagenary --help # confirm the CLI is available</code></pre>\n<blockquote>\n<p><strong>Building Pagenary from source instead?</strong> Clone the repo and work from the</p>\n<p>workspace (for contributors / modifying the generator):</p>\n<p>```bash</p>\n<p>git clone https://github.com/jmagly/pagenary.git</p>\n<p>cd pagenary &amp;&amp; npm run bootstrap</p>\n<p>npm run publisher:build &amp;&amp; npm run publisher:serve</p>\n<p>```</p>\n</blockquote>\n<h2 id=\"key-features\">Key Features</h2>\n<p>Pagenary includes several powerful features out of the box:</p>\n<ul>\n<li><strong>Command Palette</strong> - Press `Ctrl+K` (or `Cmd+K` on Mac) for ranked full-text search (with snippets + infinite scroll), navigation, and export</li>\n<li><strong>SEO-first output</strong> - metadata-driven titles, crawlable `/pages/` snapshots, sitemap/robots/llms.txt, JSON-LD, and Open Graph, generated at build time</li>\n<li><strong>Deploy anywhere</strong> - the same bundle serves at a domain root or under a subpath; any static host, CDN, or the bundled Caddy</li>\n<li><strong>Mermaid Diagrams</strong> - Embed flowcharts, sequence diagrams, and more using Mermaid syntax</li>\n<li><strong>Smart External Links</strong> - External links automatically open in new tabs with security headers</li>\n</ul>\n<h2 id=\"step-2-create-your-tenant-directory\">Step 2: Create Your Tenant Directory</h2>\n<p>Create a new directory for your documentation (can be anywhere on your system):</p>\n<pre><code class=\"language-bash\">mkdir ~/my-docs\ncd ~/my-docs</code></pre>\n<p>Create the basic structure:</p>\n<pre><code class=\"language-bash\">mkdir content</code></pre>\n<h2 id=\"step-3-add-branding-configuration\">Step 3: Add Branding Configuration</h2>\n<p>Create `config.json`:</p>\n<pre><code class=\"language-json\">{\n &quot;title&quot;: &quot;My Product Documentation&quot;,\n &quot;description&quot;: &quot;Complete guide to using My Product&quot;,\n &quot;brandMark&quot;: &quot;MY&quot;,\n &quot;brandSub&quot;: &quot;PRODUCT&quot;,\n &quot;tagline&quot;: &quot;Documentation that works&quot;,\n &quot;copyright&quot;: &quot;My Company&quot;,\n &quot;accentColor&quot;: &quot;#3B82F6&quot;,\n &quot;surfaceColor&quot;: &quot;#F8FAFC&quot;\n}</code></pre>\n<h2 id=\"step-4-create-your-first-content\">Step 4: Create Your First Content</h2>\n<p>Create `content/welcome.md`:</p>\n<pre><code class=\"language-markdown\"># Welcome to My Product\n\nThis is your documentation home page.\n\n## Getting Started\n\nHere&#39;s what you need to know to get started with My Product.\n\n### Installation\n\n\\`\\`\\`bash\nnpm install my-product\n\\`\\`\\`\n\n### Quick Example\n\n\\`\\`\\`javascript\nimport { MyProduct } from &#39;my-product&#39;;\n\nconst app = new MyProduct();\napp.start();\n\\`\\`\\`\n\n## Features\n\n- **Fast** - Built for speed\n- **Simple** - Easy to use\n- **Powerful** - Full-featured\n\n## Architecture\n\n\\`\\`\\`mermaid\ngraph TD\n A[User] --&gt; B[Frontend]\n B --&gt; C[API]\n C --&gt; D[Database]\n\\`\\`\\`</code></pre>\n<p>Create `content/installation.md`:</p>\n<pre><code class=\"language-markdown\"># Installation Guide\n\n## Requirements\n\n- Node.js 18 or higher\n- npm or yarn\n\n## Install via npm\n\n\\`\\`\\`bash\nnpm install my-product\n\\`\\`\\`\n\n## Install via yarn\n\n\\`\\`\\`bash\nyarn add my-product\n\\`\\`\\`\n\n## Verify Installation\n\n\\`\\`\\`bash\nnpx my-product --version\n\\`\\`\\`</code></pre>\n<h2 id=\"step-5-create-navigation-manifest\">Step 5: Create Navigation Manifest</h2>\n<p>Create `manifest.json`:</p>\n<pre><code class=\"language-json\">[\n {\n &quot;id&quot;: &quot;welcome&quot;,\n &quot;title&quot;: &quot;Welcome&quot;,\n &quot;summary&quot;: &quot;Introduction to My Product&quot;,\n &quot;file&quot;: &quot;welcome.md&quot;\n },\n {\n &quot;id&quot;: &quot;installation&quot;,\n &quot;title&quot;: &quot;Installation&quot;,\n &quot;summary&quot;: &quot;How to install My Product&quot;,\n &quot;file&quot;: &quot;installation.md&quot;\n }\n]</code></pre>\n<h2 id=\"step-6-register-your-tenant\">Step 6: Register Your Tenant</h2>\n<p>Create (or edit) a `tenants.json` at your project root and add your tenant. The</p>\n<p>registry is an array; `source` is an object (`local` or `git`):</p>\n<pre><code class=\"language-json\">{\n &quot;tenants&quot;: [\n {\n &quot;id&quot;: &quot;my-docs&quot;,\n &quot;source&quot;: { &quot;type&quot;: &quot;local&quot;, &quot;path&quot;: &quot;./my-docs&quot; },\n &quot;strictLinks&quot;: true\n }\n ]\n}</code></pre>\n<blockquote>\n<p>Building from source? Edit `apps/publisher/tenants.json` in the cloned repo instead.</p>\n</blockquote>\n<h2 id=\"step-7-build-and-preview\">Step 7: Build and Preview</h2>\n<pre><code class=\"language-bash\"># Build your tenant\nnpx pagenary build:tenants my-docs\n\n# Start the server\nnpx pagenary serve\n\n# Visit http://localhost:5173/my-docs/</code></pre>\n<blockquote>\n<p>From source, the equivalents are `npm run build:tenants my-docs` and `npm run serve`.</p>\n</blockquote>\n<p>You should see your documentation with your branding applied.</p>\n<h2 id=\"step-8-set-up-local-domain-optional\">Step 8: Set Up Local Domain (Optional)</h2>\n<p>For a more realistic preview with custom domains:</p>\n<p>1. Edit `/etc/hosts` (Linux/Mac) or `C:\\Windows\\System32\\drivers\\etc\\hosts` (Windows):</p>\n<pre><code>127.0.0.1 my-docs.local</code></pre>\n<p>2. Start the Caddy server:</p>\n<pre><code class=\"language-bash\">npm run caddy:up</code></pre>\n<p>3. Visit http://my-docs.local</p>\n<h2 id=\"next-steps\">Next Steps</h2>\n<h3 id=\"add-more-content\">Add More Content</h3>\n<p>Create additional `.md`, `.html`, or `.js` files in `content/`:</p>\n<pre><code>content/\n├── welcome.md\n├── installation.md\n├── guides/\n│ ├── _manifest.json\n│ ├── getting-started.md\n│ └── advanced.md\n└── api/\n ├── _manifest.json\n └── reference.md</code></pre>\n<h3 id=\"organize-with-section-manifests\">Organize with Section Manifests</h3>\n<p>Create `content/guides/_manifest.json`:</p>\n<pre><code class=\"language-json\">{\n &quot;title&quot;: &quot;Guides&quot;,\n &quot;sections&quot;: [\n { &quot;id&quot;: &quot;getting-started&quot;, &quot;title&quot;: &quot;Getting Started&quot;, &quot;file&quot;: &quot;getting-started.md&quot; },\n { &quot;id&quot;: &quot;advanced&quot;, &quot;title&quot;: &quot;Advanced Usage&quot;, &quot;file&quot;: &quot;advanced.md&quot; }\n ]\n}</code></pre>\n<h3 id=\"add-rich-content\">Add Rich Content</h3>\n<p><strong>Tables:</strong></p>\n<div class=\"html-block\"><table class=\"spec-table\">\n <thead>\n <tr><th>Feature</th><th>Status</th></tr>\n </thead>\n <tbody>\n <tr><td>Search</td><td>Ready</td></tr>\n <tr><td>Export</td><td>Ready</td></tr>\n </tbody>\n</table></div>\n<p><strong>Diagrams:</strong></p>\n<pre><code class=\"language-mermaid\">sequenceDiagram\n User-&gt;&gt;API: Request\n API-&gt;&gt;DB: Query\n DB--&gt;&gt;API: Results\n API--&gt;&gt;User: Response</code></pre>\n<h3 id=\"customize-theme\">Customize Theme</h3>\n<p>Adjust colors in `config.json`:</p>\n<table><thead><tr><th style=\"text-align: left\">Color</th><th style=\"text-align: left\">Purpose</th><th style=\"text-align: left\">Example</th></tr></thead><tbody><tr><td style=\"text-align: left\">`accentColor`</td><td style=\"text-align: left\">Links, buttons, highlights</td><td style=\"text-align: left\">`#3B82F6` (blue)</td></tr><tr><td style=\"text-align: left\">`surfaceColor`</td><td style=\"text-align: left\">Page background</td><td style=\"text-align: left\">`#F8FAFC` (off-white)</td></tr></tbody></table>\n<h3 id=\"deploy\">Deploy</h3>\n<p>Your built site is in `dist/my-docs/`. Deploy it anywhere that serves static files:</p>\n<ul>\n<li><strong>Netlify/Vercel</strong>: Point to `dist/my-docs/`</li>\n<li><strong>S3/GCS</strong>: Upload the folder</li>\n<li><strong>Docker</strong>: Use the included Caddy setup</li>\n</ul>\n<h2 id=\"troubleshooting\">Troubleshooting</h2>\n<h3 id=\"content-not-appearing\">Content not appearing?</h3>\n<p>1. Check that `manifest.json` references the correct file paths</p>\n<p>2. Verify files exist in `content/`</p>\n<p>3. Run `npx pagenary build:tenants my-docs` and check for errors</p>\n<h3 id=\"styles-not-applied\">Styles not applied?</h3>\n<p>1. Verify `config.json` is valid JSON</p>\n<p>2. Check color values are valid hex codes (e.g., `#3B82F6`)</p>\n<h3 id=\"search-not-working\">Search not working?</h3>\n<p>The command palette loads a prebuilt static index (`dist/&lt;tenant&gt;/search-index/`)</p>\n<p>on first open — wait a moment for &quot;Indexing content…&quot; to clear. If that directory</p>\n<p>is missing (e.g., an older build), search falls back to indexing in the browser on</p>\n<p>first use. Rebuild with `npm run build:tenants` to regenerate the static index.</p>\n<h2 id=\"resources\">Resources</h2>\n<ul>\n<li><a href=\"#tenant-config\">Tenant Configuration</a> - All config options</li>\n<li><a href=\"#architecture\">Architecture</a> - How it works</li>\n<li><a href=\"#api\">API Reference</a> - Module documentation</li>\n<li><a href=\"#deployment\">Deployment</a> - Hosting guide</li>\n</ul>\n </div>\n</section>" };
3
3
  }
@@ -1,3 +1,3 @@
1
1
  export async function load() {
2
- return { html: "<section class=\"section doc markdown\">\n <div class=\"doc-content\">\n<h1 id=\"seo-strategy\">SEO Strategy</h1>\n<p>Pagenary publishes a hash-routed single-page app, so it generates **crawler-facing</p>\n<p>static artifacts** alongside the SPA. These are produced automatically at build</p>\n<p>time by `scripts/lib/seo-generator.js` and configured via the tenant</p>\n<p><a href=\"#tenant-config#seo-seo\">`seo` block</a>.</p>\n<h2 id=\"what-the-build-generates\">What the build generates</h2>\n<table><thead><tr><th style=\"text-align: left\">Artifact</th><th style=\"text-align: left\">Purpose</th></tr></thead><tbody><tr><td style=\"text-align: left\">`sitemap.xml`</td><td style=\"text-align: left\">Absolute `&lt;loc&gt;` for the home page and every section&#39;s static snapshot</td></tr><tr><td style=\"text-align: left\">`robots.txt`</td><td style=\"text-align: left\">Allows `/` and `/pages/`, points at the sitemap</td></tr><tr><td style=\"text-align: left\">`llms.txt`</td><td style=\"text-align: left\">LLM-friendly site index (<a href=\"https://llmstxt.org/\" target=\"_blank\" rel=\"noopener noreferrer\">llmstxt.org</a>)</td></tr><tr><td style=\"text-align: left\">`/pages/&lt;id&gt;.html`</td><td style=\"text-align: left\">Per-section static snapshots with full metadata + JSON-LD, for crawlers</td></tr><tr><td style=\"text-align: left\">JSON-LD</td><td style=\"text-align: left\">`TechArticle` + `BreadcrumbList` per page; `WebSite` + optional `Organization` site-wide</td></tr><tr><td style=\"text-align: left\">Runtime meta</td><td style=\"text-align: left\">`src/seo.js` keeps `&lt;title&gt;`, description, canonical, OG, and Twitter tags in sync as the SPA navigates</td></tr></tbody></table>\n<h2 id=\"make-urls-absolute\">Make URLs absolute</h2>\n<p>Declare a `domain` (or `seo.siteUrl`) on the tenant. This is what turns the</p>\n<p>sitemap `&lt;loc&gt;`, canonical, `og:url`, and `robots` `Sitemap:` into fully-qualified</p>\n<p>URLs. The <a href=\"https://www.sitemaps.org/protocol.html\" target=\"_blank\" rel=\"noopener noreferrer\">sitemap protocol</a> requires</p>\n<p>absolute URLs, so a tenant with neither set emits a non-compliant sitemap — the</p>\n<p>build prints a warning when that happens.</p>\n<p>Precedence: `seo.siteUrl` → `domain` (https-prefixed) → relative (warned).</p>\n<h2 id=\"canonical-strategy\">Canonical strategy</h2>\n<p>Static snapshots and the runtime SPA canonicalize to the <strong>crawlable static URL</strong></p>\n<p>(`/pages/&lt;id&gt;.html`), not the SPA `#hash` route. Search engines ignore URL</p>\n<p>fragments, so hash canonicals (`/#section`) would collapse every page onto the</p>\n<p>homepage. The `#hash` route is still used for the human-facing &quot;interactive</p>\n<p>version&quot; link and the JavaScript redirect on the static page.</p>\n<h2 id=\"social-cards\">Social cards</h2>\n<p>Set `seo.ogImage` (absolute or site-relative) to emit `og:image` /</p>\n<p>`twitter:image` and upgrade `twitter:card` to `summary_large_image`. Individual</p>\n<p>pages can override it with an `ogImage` field on the manifest entry.</p>\n<h2 id=\"authoring-practices\">Authoring practices</h2>\n<ul>\n<li>Keep manifest `summary` values concise — they power the meta description, search</li>\n</ul>\n<p>results, link previews, and the export document.</p>\n<ul>\n<li>Use human-readable, hyphenated, lowercase section `id`s — they become both the</li>\n</ul>\n<p>hash route and the static page filename (`/` becomes `--`).</p>\n<ul>\n<li>Gate broken links in CI with `strictLinks: true` (see</li>\n</ul>\n<p><a href=\"#tenant-config\">Tenant Configuration</a>).</p>\n </div>\n</section>" };
2
+ return { html: "<section class=\"section doc markdown\">\n <div class=\"doc-content\">\n<h1 id=\"seo-strategy\">SEO Strategy</h1>\n<p>Pagenary publishes a hash-routed single-page app, so it generates **crawler-facing</p>\n<p>static artifacts** alongside the SPA. These are produced automatically at build</p>\n<p>time by `scripts/lib/seo-generator.js` and configured via the tenant</p>\n<p><a href=\"#tenant-config#seo-seo\">`seo` block</a>.</p>\n<h2 id=\"what-the-build-generates\">What the build generates</h2>\n<table><thead><tr><th style=\"text-align: left\">Artifact</th><th style=\"text-align: left\">Purpose</th></tr></thead><tbody><tr><td style=\"text-align: left\">`sitemap.xml`</td><td style=\"text-align: left\">Absolute `&lt;loc&gt;` for the home page and every section&#39;s static snapshot</td></tr><tr><td style=\"text-align: left\">`robots.txt`</td><td style=\"text-align: left\">Allows `/` and `/pages/`, points at the sitemap</td></tr><tr><td style=\"text-align: left\">`llms.txt`</td><td style=\"text-align: left\">LLM-friendly site index (<a href=\"https://llmstxt.org/\" target=\"_blank\" rel=\"noopener noreferrer\">llmstxt.org</a>)</td></tr><tr><td style=\"text-align: left\">`/pages/&lt;id&gt;.html`</td><td style=\"text-align: left\">Per-section static snapshots with full metadata + JSON-LD, for crawlers</td></tr><tr><td style=\"text-align: left\">JSON-LD</td><td style=\"text-align: left\">`TechArticle` + `BreadcrumbList` per page; `WebSite` + optional `Organization` site-wide</td></tr><tr><td style=\"text-align: left\">Shell `&lt;title&gt;`</td><td style=\"text-align: left\">The build sets the static shell title from the <strong>default page&#39;s metadata title</strong> (`&quot;&lt;page title&gt; · &lt;brand&gt;&quot;`), so the crawler-visible root URL is specific, not generic. The brand alone is only a fallback</td></tr><tr><td style=\"text-align: left\">Runtime meta</td><td style=\"text-align: left\">`src/seo.js` keeps `&lt;title&gt;`, description, canonical, OG, and Twitter tags in sync as the SPA navigates</td></tr></tbody></table>\n<h2 id=\"make-urls-absolute\">Make URLs absolute</h2>\n<p>Declare a `domain` (or `seo.siteUrl`) on the tenant. This is what turns the</p>\n<p>sitemap `&lt;loc&gt;`, canonical, `og:url`, and `robots` `Sitemap:` into fully-qualified</p>\n<p>URLs. The <a href=\"https://www.sitemaps.org/protocol.html\" target=\"_blank\" rel=\"noopener noreferrer\">sitemap protocol</a> requires</p>\n<p>absolute URLs, so a tenant with neither set emits a non-compliant sitemap — the</p>\n<p>build prints a warning when that happens.</p>\n<p>Precedence: `seo.siteUrl` → `domain` (https-prefixed) → relative (warned).</p>\n<h2 id=\"canonical-strategy\">Canonical strategy</h2>\n<p>Static snapshots and the runtime SPA canonicalize to the <strong>crawlable static URL</strong></p>\n<p>(`/pages/&lt;id&gt;.html`), not the SPA `#hash` route. Search engines ignore URL</p>\n<p>fragments, so hash canonicals (`/#section`) would collapse every page onto the</p>\n<p>homepage. The `#hash` route is still used for the human-facing &quot;interactive</p>\n<p>version&quot; link and the JavaScript redirect on the static page.</p>\n<h2 id=\"social-cards\">Social cards</h2>\n<p>Set `seo.ogImage` (absolute or site-relative) to emit `og:image` /</p>\n<p>`twitter:image` and upgrade `twitter:card` to `summary_large_image`. Individual</p>\n<p>pages can override it with an `ogImage` field on the manifest entry.</p>\n<h2 id=\"authoring-practices\">Authoring practices</h2>\n<ul>\n<li>Keep manifest `summary` values concise — they power the meta description, search</li>\n</ul>\n<p>results, link previews, and the export document.</p>\n<ul>\n<li>Use human-readable, hyphenated, lowercase section `id`s — they become both the</li>\n</ul>\n<p>hash route and the static page filename (`/` becomes `--`).</p>\n<ul>\n<li>Gate broken links in CI with `strictLinks: true` (see</li>\n</ul>\n<p><a href=\"#tenant-config\">Tenant Configuration</a>).</p>\n </div>\n</section>" };
3
3
  }
@@ -1,3 +1,3 @@
1
1
  export async function load() {
2
- return { html: "<section class=\"section doc markdown\">\n <div class=\"doc-content\">\n<h1 id=\"where-documentation-takes-shape\">Where documentation takes shape</h1>\n<p>Pagenary is a multi-tenant documentation publishing platform that turns one</p>\n<p>shared set of templates into many branded, tenant-specific static sites. Zero</p>\n<p>runtime dependencies, hash-based routing, and a Git-aware build pipeline make</p>\n<p>it suited to white-label documentation portalsone source of truth, any</p>\n<p>number of published sites.</p>\n<p><strong>This portal is built by Pagenary, from Pagenary&#39;s own documentation.</strong> Every</p>\n<p>page you see here is the same publisher pipeline applied to the developer docs</p>\n<p>in the repository, served as a static single-page app.</p>\n<h2 id=\"start-here\">Start here</h2>\n<ul>\n<li><strong><a href=\"#quickstart\">Quickstart</a></strong> — install, build the default bundle, and serve it locally.</li>\n<li><strong><a href=\"#architecture\">Architecture</a></strong> — the static SPA pattern, build pipeline, and tenant content model.</li>\n<li><strong><a href=\"#tenant-config\">Tenant Configuration</a></strong> — every `config.json` option for branding, theming, and export.</li>\n</ul>\n<h2 id=\"how-a-tenant-works\">How a tenant works</h2>\n<p>A tenant is a thin layer — content, a `config.json`, and a `manifest.json` —</p>\n<p>over the shared template catalog. Branding, theming, and navigation are **data,</p>\n<p>not code**: a tenant changes its look through configuration, never by forking</p>\n<p>the generator. The build produces a self-contained bundle under</p>\n<p>`dist/&lt;tenant-id&gt;/` that you can host anywhere that serves files.</p>\n </div>\n</section>" };
2
+ return { html: "<section class=\"section doc markdown\">\n <div class=\"doc-content\">\n<h1 id=\"where-documentation-takes-shape\">Where documentation takes shape</h1>\n<p>Pagenary turns a folder of Markdown in a git repo into a fast, searchable,</p>\n<p>SEO-ready documentation site you host yourself — for next to nothing. Write your</p>\n<p>docs, run one tool, and deploy the static output to any free static host</p>\n<p>(GitHub/Gitea Pages, Netlify, Cloudflare Pages, S3, a CDN, or your own box). No</p>\n<p>server, no database, no monthly SaaS bill just the things you&#39;d expect from a</p>\n<p>paid docs platform: command-palette search with ranking, theming and branding,</p>\n<p>Mermaid diagrams, syntax highlighting, SEO, and one-click export.</p>\n<p><strong>This portal is built by Pagenary, from Pagenary&#39;s own documentation.</strong> Every</p>\n<p>page you see here is the same publisher pipeline applied to the developer docs in</p>\n<p>the repository, served as a static single-page app.</p>\n<h2 id=\"start-here\">Start here</h2>\n<ul>\n<li><strong><a href=\"#quickstart\">Quickstart</a></strong> — install, build your first site, and serve it locally.</li>\n<li><strong><a href=\"#architecture\">Architecture</a></strong> — the static SPA pattern, build pipeline, and content model.</li>\n<li><strong><a href=\"#tenant-config\">Tenant Configuration</a></strong> — every `config.json` option for branding, theming, SEO, and export.</li>\n</ul>\n<h2 id=\"scale-to-many-sites-when-you-need-to\">Scale to many sites when you need to</h2>\n<p>One site is just content, a `config.json`, and a `manifest.json`. Need more than</p>\n<p>one? The same tool publishes many sites from a shared template catalog branding,</p>\n<p>theming, and navigation are <strong>data, not code</strong>, so standing up another branded</p>\n<p>site is cheap, and a Git-aware build rebuilds only what changed. Pagenary scales</p>\n<p>from a weekend project to a multi-product portal without changing tools.</p>\n </div>\n</section>" };
3
3
  }