@docsector/docsector-reader 4.5.2 β†’ 4.5.4

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
@@ -27,7 +27,7 @@ Transform Markdown content into beautiful, navigable documentation sites β€” wit
27
27
  - πŸ€– **Open in ChatGPT / Claude** β€” One-click links to open the current page directly in ChatGPT or Claude for Q&A
28
28
  - πŸ€– **LLM Bot Detection** β€” Automatically serves raw Markdown to known AI crawlers (GPTBot, ClaudeBot, PerplexityBot, Cloudflare-AI-Search, GrokBot, and others)
29
29
  - πŸ—ΊοΈ **Sitemap Generation** β€” Automatic `sitemap.xml` generation at build time with root-relative URLs by default and absolute URLs when `siteUrl` is configured
30
- - πŸ€– **AI-Friendly robots.txt** β€” Scaffold includes a `robots.txt` explicitly allowing 24 AI crawlers (GPTBot, ClaudeBot, PerplexityBot, Cloudflare-AI-Search, GrokBot, etc.) and advertises `Sitemap: /sitemap.xml`
30
+ - πŸ€– **AI-Friendly robots.txt** β€” Scaffold includes a `robots.txt` explicitly allowing 24 AI crawlers (GPTBot, ClaudeBot, PerplexityBot, Cloudflare-AI-Search, GrokBot, etc.), and the build appends `Sitemap: /sitemap.xml` at the end for crawler discovery
31
31
  - 🧭 **Content Signals** β€” Optional `Content-Signal` directive for declaring AI usage policy (`ai-train`, `search`, `ai-input`) in `robots.txt`
32
32
  - 🧩 **Agent Skills Discovery Index** β€” Optional `/.well-known/agent-skills/index.json` with RFC v0.2.0 schema and SHA-256 digests
33
33
  - ✍️ **Docsector Authoring Skill** β€” Publishable `SKILL.md` that teaches agents Docsector blocks, page patterns, MCP lookup, and WebMCP tools
@@ -46,6 +46,7 @@ Transform Markdown content into beautiful, navigable documentation sites β€” wit
46
46
  - πŸ“‹ **Clickable Inline Code** β€” Backtick-rendered inline code snippets are clickable across pages, subpages, and AI assistant answers
47
47
  - πŸ”½ **Nested Markdown Lists** β€” Ordered and unordered lists preserve sublist hierarchy across multiple indentation levels
48
48
  - β˜‘οΈ **Markdown Task Lists** β€” GitBook-style `- [ ]` and `- [x]` items render as read-only checkboxes with nested subtasks
49
+ - ⌨️ **Keyboard Shortcut Keycaps** β€” Author GitBook-style shortcuts with raw `<kbd>...</kbd>` tags, rendered consistently across docs and AI assistant answers
49
50
  - πŸ–ΌοΈ **Block Image Captions & Zoom** β€” Standalone Markdown images render as zoomable figures, and raw `figure` / `picture` markup supports separate alt text and captions
50
51
  - 🧱 **Raw HTML in Markdown** β€” Renders inline and block HTML tags inside markdown sections (including homepage remote README content)
51
52
  - 🧩 **Mermaid Diagrams** β€” Native support for fenced ` ```mermaid ` blocks, with automatic dark/light theme switching
@@ -77,6 +78,7 @@ Transform Markdown content into beautiful, navigable documentation sites β€” wit
77
78
  - 🌍 **Remote README as Home** β€” Optional build-time remote README source for homepage with automatic local fallback and automatic primary-title handoff when the remote README already provides the project heading
78
79
  - πŸ”— **GitHub-Compatible Heading Anchors** β€” Markdown headings use GitHub-style slugs so standard README Table of Contents links work inside Docsector
79
80
  - 🧬 **Scaffolded Homepage Override Wiring** β€” New consumer projects automatically wire `virtual:docsector-homepage-override` into i18n message building
81
+ - 🧰 **Scaffolded Dev Reliability** β€” New consumer projects protect Docsector virtual registries and Markdown CommonJS plugins from Vite optimizer edge cases during dev and build
80
82
  - πŸ“– **Expandable Markdown Sections** β€” Use `<d-block-expandable title="...">...</d-block-expandable>` to collapse secondary content while keeping rich Markdown support inside the body
81
83
  - 1️⃣ **Stepper Guides** β€” Use `<d-block-stepper>` with nested `<d-block-step title="...">...</d-block-step>` items to render native Quasar vertical steppers with rich Markdown and optional per-step icon overrides
82
84
  - πŸ•’ **Timeline Updates** β€” Use `<d-block-timeline>` with nested `<d-block-timeline-item date="...">...</d-block-timeline-item>` entries and optional `<d-block-timeline-tag>` labels to publish GitBook-inspired changelog items with direct-link anchors, tag icons/colors, and rich Markdown bodies
@@ -350,8 +352,8 @@ export default {
350
352
  Use Cloudflare AI Search as the first provider path:
351
353
 
352
354
  - Create an AI Search instance in Cloudflare.
353
- - Build and deploy the Docsector site first; build output always publishes `/sitemap.xml` and adds `Sitemap: /sitemap.xml` to `robots.txt` for crawler discovery.
354
- - Use a Website data source. For the cleanest retrieval, point its specific sitemap to `/ai-search-sitemap.xml`; otherwise the crawler can discover `/sitemap.xml` from `robots.txt`.
355
+ - Build and deploy the Docsector site first; build output always publishes `/sitemap.xml` and appends `Sitemap: /sitemap.xml` to the end of `robots.txt` for crawler discovery.
356
+ - Use a Website data source. For the cleanest retrieval, point its specific sitemap to `/ai-search-sitemap.xml`. Docsector keeps that Markdown-focused sitemap available for explicit AI Search configuration, but does not auto-announce it from `robots.txt` so Cloudflare does not index the same content twice alongside `/sitemap.xml`.
355
357
  - Add metadata fields such as title, path, locale, book, version, and subpage if you want filtering later.
356
358
  - Set `AI_SEARCH_INSTANCE_NAME` as a Cloudflare Pages environment variable or local `.dev.vars` entry.
357
359
  - Bind the instance to Pages as `AI_SEARCH` when available, or set encrypted Pages secrets for `CLOUDFLARE_ACCOUNT_ID` and `CLOUDFLARE_API_TOKEN` with AI Search run access.
@@ -366,7 +368,7 @@ When enabled, `docsector build` can generate:
366
368
  | `functions/assistant.js` | Cloudflare Pages Function for browser assistant requests |
367
369
  | `dist/spa/sitemap.xml` | Default crawler sitemap advertised from `robots.txt` |
368
370
  | `dist/spa/robots.txt` | Crawler policy with `Sitemap: /sitemap.xml` |
369
- | `dist/spa/ai-search-sitemap.xml` | Markdown-focused sitemap for AI Search crawling |
371
+ | `dist/spa/ai-search-sitemap.xml` | Markdown-focused sitemap for explicit AI Search Website data source configuration |
370
372
  | `dist/spa/.well-known/ai-search/manifest.json` | Source metadata for indexed documentation pages |
371
373
  | `dist/spa/_routes.json` | Routes the internal assistant endpoint to the Pages Function |
372
374
 
@@ -617,7 +619,7 @@ Notes:
617
619
  - `aiTrain`, `search`, and `aiInput` accept `yes` / `no` (or booleans).
618
620
  - Default scope is only `User-agent: *`.
619
621
  - Build patch is idempotent: repeated builds do not duplicate `Content-Signal` lines.
620
- - Build also keeps `Sitemap: /sitemap.xml` discoverable in `robots.txt` so crawlers can find the generated sitemap automatically.
622
+ - Build also keeps `Sitemap: /sitemap.xml` discoverable at the end of `robots.txt` so crawlers can find the generated sitemap automatically.
621
623
 
622
624
  ### Validate
623
625
 
@@ -732,6 +734,8 @@ npm install
732
734
 
733
735
  This creates a minimal project with `quasar.config.js`, `docsector.config.js`, `src/pages/`, `src/i18n/`, and `public/` β€” all powered by the docsector-reader engine.
734
736
 
737
+ The scaffolded `quasar.config.js` delegates to `createQuasarConfig()`, which registers Docsector virtual registries and keeps the engine router out of Vite dependency optimization so modules like `virtual:docsector-books` resolve during dev and build.
738
+
735
739
  ### πŸ’» Development
736
740
 
737
741
  ```bash
package/bin/docsector.js CHANGED
@@ -24,7 +24,7 @@ const packageRoot = resolve(__dirname, '..')
24
24
  const args = process.argv.slice(2)
25
25
  const command = args[0]
26
26
 
27
- const VERSION = '4.5.2'
27
+ const VERSION = '4.5.4'
28
28
  const AUTHORING_SKILL_NAME = 'docsector-documentation-authoring'
29
29
  const AUTHORING_SKILL_DESCRIPTION = 'Author Docsector documentation with Markdown, custom blocks, MCP, and WebMCP.'
30
30
  const AUTHORING_SKILL_PUBLIC_PATH = `/.well-known/agent-skills/${AUTHORING_SKILL_NAME}/SKILL.md`
@@ -157,6 +157,32 @@ export default {
157
157
  // sitemap.xml is still generated with root-relative URLs when omitted.
158
158
  // siteUrl: 'https://docs.example.com',
159
159
 
160
+ // @ Home page source (optional)
161
+ // Use a remote README.md as homepage content at build-time.
162
+ // Falls back to local src/pages/Homepage.{lang}.md on fetch failure by default.
163
+ // homePage: {
164
+ // source: 'remote-readme', // 'local' | 'remote-readme'
165
+ // remoteReadmeUrl: 'https://raw.githubusercontent.com/your-org/your-repo/main/README.md',
166
+ // timeoutMs: 8000,
167
+ // fallbackToLocal: true
168
+ // },
169
+
170
+ // --- Language configs ---
171
+
172
+ // @ Languages
173
+ languages: [
174
+ {
175
+ image: '/images/flags/united-states-of-america.png',
176
+ label: 'English (US)',
177
+ value: 'en-US'
178
+ }
179
+ ],
180
+
181
+ // @ Default language
182
+ defaultLanguage: 'en-US'
183
+
184
+ // --- AI configs ---
185
+
160
186
  // @ MCP (Model Context Protocol)
161
187
  // Uncomment to enable an MCP server at /mcp for AI assistant integration.
162
188
  // Requires Cloudflare Pages Functions (or compatible serverless platform).
@@ -197,16 +223,6 @@ export default {
197
223
  // }
198
224
  // },
199
225
 
200
- // @ Home page source (optional)
201
- // Use a remote README.md as homepage content at build-time.
202
- // Falls back to local src/pages/Homepage.{lang}.md on fetch failure by default.
203
- // homePage: {
204
- // source: 'remote-readme', // 'local' | 'remote-readme'
205
- // remoteReadmeUrl: 'https://raw.githubusercontent.com/your-org/your-repo/main/README.md',
206
- // timeoutMs: 8000,
207
- // fallbackToLocal: true
208
- // },
209
-
210
226
  // @ Homepage Link headers for agent discovery (optional)
211
227
  // linkHeaders: {
212
228
  // enabled: true,
@@ -270,19 +286,7 @@ export default {
270
286
  // url: '${AUTHORING_SKILL_PUBLIC_PATH}'
271
287
  // }
272
288
  // ]
273
- // },
274
-
275
- // @ Languages
276
- languages: [
277
- {
278
- image: '/images/flags/united-states-of-america.png',
279
- label: 'English (US)',
280
- value: 'en-US'
281
- }
282
- ],
283
-
284
- // @ Default language
285
- defaultLanguage: 'en-US'
289
+ // }
286
290
  }
287
291
  `
288
292
 
@@ -437,7 +441,10 @@ export default {
437
441
  label: 'Guide',
438
442
  icon: 'school',
439
443
  order: 1,
440
- color: 'secondary'
444
+ color: {
445
+ active: 'white',
446
+ inactive: 'white'
447
+ }
441
448
  }
442
449
  `
443
450
 
@@ -635,7 +642,6 @@ const TEMPLATE_ROBOTS_TXT = `\
635
642
  User-agent: *
636
643
  Allow: /
637
644
  Content-Signal: ai-train=yes, search=yes, ai-input=yes
638
- Sitemap: /sitemap.xml
639
645
 
640
646
  # Explicitly allow AI crawlers
641
647
  # OpenAI
@@ -790,7 +796,7 @@ npm run build
790
796
  \`\`\`
791
797
 
792
798
  The optimized SPA output will be in \`dist/spa/\`.
793
- Docsector also generates \`dist/spa/sitemap.xml\` and keeps \`robots.txt\` discoverable with \`Sitemap: /sitemap.xml\`. Set \`siteUrl\` in \`docsector.config.js\` when you want absolute sitemap URLs.
799
+ Docsector also generates \`dist/spa/sitemap.xml\` and appends \`Sitemap: /sitemap.xml\` to the end of \`dist/spa/robots.txt\` during build. Set \`siteUrl\` in \`docsector.config.js\` when you want absolute sitemap URLs.
794
800
  `
795
801
 
796
802
  // =============================================================================
@@ -82,16 +82,16 @@ export default {
82
82
  namespace: '',
83
83
  accountIdEnv: 'CLOUDFLARE_ACCOUNT_ID',
84
84
  apiTokenEnv: 'CLOUDFLARE_API_TOKEN',
85
- model: '@cf/meta/llama-3.3-70b-instruct-fp8-fast',
85
+ model: '@cf/meta/llama-4-scout-17b-16e-instruct',
86
86
  retrievalType: 'vector',
87
- maxResults: 6,
87
+ maxResults: 10,
88
88
  matchThreshold: 0.4,
89
89
  contextExpansion: 1,
90
90
  queryRewrite: {
91
91
  enabled: true
92
92
  },
93
93
  reranking: {
94
- enabled: false,
94
+ enabled: true,
95
95
  model: '@cf/baai/bge-reranker-base',
96
96
  matchThreshold: 0.4
97
97
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docsector/docsector-reader",
3
- "version": "4.5.2",
3
+ "version": "4.5.4",
4
4
  "description": "A documentation rendering engine built with Vue 3, Quasar v2 and Vite. Transform Markdown into beautiful, navigable documentation sites.",
5
5
  "productName": "Docsector Reader",
6
6
  "author": "Rodrigo de Araujo Vieira",
@@ -309,9 +309,11 @@ Use raw HTML only when Markdown is not expressive enough or when authoring Docse
309
309
  <div data-kind="secondary-note">
310
310
  This block uses raw HTML inside the page source.
311
311
  </div>
312
+
313
+ Press <kbd>⌘</kbd> + <kbd>B</kbd> to toggle bold text.
312
314
  ```
313
315
 
314
- Prefer plain Markdown first. Keep raw markup readable because documentation content still needs maintenance.
316
+ Prefer plain Markdown first. Use `<kbd>...</kbd>` for keyboard shortcuts that should read like GitBook-style keycaps. Keep raw markup readable because documentation content still needs maintenance.
315
317
 
316
318
  ## Renderer and Parser References
317
319
 
package/public/robots.txt CHANGED
@@ -1,6 +1,5 @@
1
1
  User-agent: *
2
2
  Allow: /
3
- Sitemap: /sitemap.xml
4
3
 
5
4
  User-agent: Cloudflare-AI-Search
6
5
  Allow: /
@@ -251,7 +251,7 @@ function buildSystemPrompt (body, currentPageMarkdown = '') {
251
251
  const lines = [
252
252
  'You are Docsector Assistant, a concise documentation assistant.',
253
253
  'Answer using the indexed documentation context. If the answer is not in the docs, say so clearly.',
254
- 'Prefer short, actionable answers and cite the relevant source chunks when available.'
254
+ 'Prefer short, actionable answers.'
255
255
  ]
256
256
 
257
257
  if (locale) lines.push(`User locale: ${locale}.`)
package/src/css/app.sass CHANGED
@@ -20,6 +20,10 @@ body.body--light
20
20
  --task-list-checkbox-checked-bg: #5e4c1f
21
21
  --task-list-checkbox-checked-border: #4f3f18
22
22
  --task-list-checkbox-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2.3' d='M3.25 8.5 6.4 11.4 12.75 4.9'/%3E%3C/svg%3E")
23
+ --kbd-color: #272b33
24
+ --kbd-background: #f7f8fa
25
+ --kbd-border: #d5dae0
26
+ --kbd-shadow: inset 0 -1px 0 #c4cad3, 0 1px 2px rgba(15, 23, 42, 0.08)
23
27
 
24
28
  --q-primary-background: #FFF !important
25
29
 
@@ -58,6 +62,10 @@ body.body--dark
58
62
  --task-list-checkbox-checked-bg: #d3b874
59
63
  --task-list-checkbox-checked-border: #ebd08a
60
64
  --task-list-checkbox-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23151515' stroke-linecap='round' stroke-linejoin='round' stroke-width='2.3' d='M3.25 8.5 6.4 11.4 12.75 4.9'/%3E%3C/svg%3E")
65
+ --kbd-color: #f3f5f7
66
+ --kbd-background: #2a303a
67
+ --kbd-border: #4d5663
68
+ --kbd-shadow: inset 0 -1px 0 #3a414d, 0 1px 2px rgba(0, 0, 0, 0.45)
61
69
 
62
70
  --q-light-in-dark-1: #ababab
63
71
  --q-light-in-dark-2: #c9c9c9
@@ -199,6 +207,27 @@ body.body--dark
199
207
  display: inline
200
208
  line-height: 0.85em
201
209
 
210
+ kbd
211
+ display: inline-flex
212
+ align-items: center
213
+ justify-content: center
214
+ min-width: 1.8em
215
+ padding: 0.18rem 0.42rem
216
+ margin: 0 0.1rem
217
+ border: 1px solid var(--kbd-border)
218
+ border-radius: 0.45rem
219
+ background: var(--kbd-background)
220
+ box-shadow: var(--kbd-shadow)
221
+ color: var(--kbd-color)
222
+ font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif
223
+ font-size: 0.85em
224
+ font-weight: 600
225
+ line-height: 1.1
226
+ letter-spacing: 0.01em
227
+ vertical-align: middle
228
+ white-space: nowrap
229
+ text-transform: none
230
+
202
231
  .katex
203
232
  color: inherit
204
233
  max-width: 100%
package/src/index.js CHANGED
@@ -179,7 +179,7 @@ export function createDocsector (config = {}) {
179
179
  },
180
180
 
181
181
  contentSignals: {
182
- enabled: false,
182
+ enabled: true,
183
183
  aiTrain: 'yes',
184
184
  search: 'yes',
185
185
  aiInput: 'yes',
@@ -189,7 +189,7 @@ export function createDocsector (config = {}) {
189
189
  },
190
190
 
191
191
  agentSkills: {
192
- enabled: false,
192
+ enabled: true,
193
193
  path: '/.well-known/agent-skills/index.json',
194
194
  schema: 'https://schemas.agentskills.io/discovery/0.2.0/schema.json',
195
195
  skills: [],
@@ -47,7 +47,7 @@ For cleaner retrieval, point the specific sitemap setting to:
47
47
  https://docs.example.com/ai-search-sitemap.xml
48
48
  ```
49
49
 
50
- The AI Search sitemap points to Markdown URLs, which are cleaner for retrieval than rendered SPA HTML. The manifest at `/.well-known/ai-search/manifest.json` lists titles, routes, locales, books, versions, and subpages for the same source set.
50
+ The AI Search sitemap points to Markdown URLs, which are cleaner for retrieval than rendered SPA HTML. Docsector keeps it available for explicit Cloudflare configuration, but does not auto-advertise it from `robots.txt` to avoid duplicate indexing alongside `/sitemap.xml`. The manifest at `/.well-known/ai-search/manifest.json` lists titles, routes, locales, books, versions, and subpages for the same source set.
51
51
 
52
52
  ## Runtime Endpoint
53
53
 
@@ -47,7 +47,7 @@ Para uma recuperaΓ§Γ£o mais limpa, aponte a configuraΓ§Γ£o de sitemap especΓ­fic
47
47
  https://docs.example.com/ai-search-sitemap.xml
48
48
  ```
49
49
 
50
- O sitemap do AI Search aponta para URLs Markdown, que sΓ£o mais limpas para recuperaΓ§Γ£o do que HTML renderizado pela SPA. O manifest em `/.well-known/ai-search/manifest.json` lista tΓ­tulos, rotas, locales, books, versΓ΅es e subpΓ‘ginas do mesmo conjunto de fontes.
50
+ O sitemap do AI Search aponta para URLs Markdown, que sΓ£o mais limpas para recuperaΓ§Γ£o do que HTML renderizado pela SPA. O Docsector mantΓ©m esse arquivo disponΓ­vel para configuraΓ§Γ£o explΓ­cita no Cloudflare, mas nΓ£o o anuncia automaticamente em `robots.txt`, para evitar indexaΓ§Γ£o duplicada junto com `/sitemap.xml`. O manifest em `/.well-known/ai-search/manifest.json` lista tΓ­tulos, rotas, locales, books, versΓ΅es e subpΓ‘ginas do mesmo conjunto de fontes.
51
51
 
52
52
  ## Endpoint Runtime
53
53
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Raw HTML can be used inside Markdown when the native Markdown syntax is not expressive enough.
4
4
 
5
- This is useful for custom wrappers, inline labels, embedded elements, and Docsector-specific custom elements such as expandable blocks and quick links.
5
+ This is useful for custom wrappers, inline labels, keyboard shortcut keycaps, embedded elements, and Docsector-specific custom elements such as expandable blocks and quick links.
6
6
 
7
7
  ## Markdown Example
8
8
 
@@ -10,10 +10,13 @@ This is useful for custom wrappers, inline labels, embedded elements, and Docsec
10
10
  <div data-kind="secondary-note">
11
11
  This block uses raw HTML inside the page source.
12
12
  </div>
13
+
14
+ Press <kbd>⌘</kbd> + <kbd>B</kbd> to toggle bold text.
13
15
  ```
14
16
 
15
17
  ## Notes
16
18
 
17
19
  - Prefer plain Markdown first when it already solves the problem.
18
20
  - Use raw HTML when you need structure or attributes that Markdown does not provide.
21
+ - Author GitBook-style keyboard shortcuts with `<kbd>...</kbd>` when you want keycaps inside normal prose.
19
22
  - Keep the markup readable, because documentation content still needs to be maintained by humans.
@@ -9,4 +9,8 @@
9
9
 
10
10
  ### Inline Badge
11
11
 
12
- Use <span style="padding: 0.15rem 0.45rem; border: 1px solid currentColor; border-radius: 999px;">beta</span> labels directly inside a sentence.
12
+ Use <span style="padding: 0.15rem 0.45rem; border: 1px solid currentColor; border-radius: 999px;">beta</span> labels directly inside a sentence.
13
+
14
+ ### Keyboard Shortcuts
15
+
16
+ Use <kbd>⌘</kbd> + <kbd>B</kbd> for bold, <kbd>⌘</kbd> + <kbd>K</kbd> to open quick search, and <kbd>Shift</kbd> + <kbd>Alt</kbd> + <kbd>S</kbd> for multi-key shortcuts.
@@ -875,8 +875,8 @@ export default {
875
875
  },
876
876
  metadata: {
877
877
  tags: {
878
- 'en-US': 'raw html markup inline block custom elements markdown',
879
- 'pt-BR': 'html bruto marcaΓ§Γ£o inline bloco elementos customizados markdown'
878
+ 'en-US': 'raw html markup inline block custom elements markdown keyboard shortcut shortcuts kbd keycap gitbook',
879
+ 'pt-BR': 'html bruto marcaΓ§Γ£o inline bloco elementos customizados markdown teclado atalho atalhos kbd keycap gitbook'
880
880
  }
881
881
  }
882
882
  },
@@ -74,6 +74,28 @@ function normalizePathForMatch (path) {
74
74
 
75
75
  const CURRENT_VERSION_KEY = '__current__'
76
76
 
77
+ const DOCSECTOR_VIRTUAL_MODULE_IDS = Object.freeze([
78
+ 'virtual:docsector-books',
79
+ 'virtual:docsector-homepage-override',
80
+ 'virtual:docsector-code-examples',
81
+ 'virtual:docsector-git-dates'
82
+ ])
83
+
84
+ const DOCSECTOR_CONSUMER_OPTIMIZE_DEPS_EXCLUDE = Object.freeze([
85
+ '@docsector/docsector-reader',
86
+ '@docsector/docsector-reader/src/App.vue',
87
+ '@docsector/docsector-reader/src/router/index',
88
+ '@docsector/docsector-reader/src/router/index.js',
89
+ '@docsector/docsector-reader/src/router/routes',
90
+ '@docsector/docsector-reader/src/router/routes.js',
91
+ 'node_modules/@docsector/docsector-reader/src/App.vue',
92
+ 'node_modules/@docsector/docsector-reader/src/router/index',
93
+ 'node_modules/@docsector/docsector-reader/src/router/index.js',
94
+ 'node_modules/@docsector/docsector-reader/src/router/routes',
95
+ 'node_modules/@docsector/docsector-reader/src/router/routes.js',
96
+ ...DOCSECTOR_VIRTUAL_MODULE_IDS
97
+ ])
98
+
77
99
  function trimSlashes (value) {
78
100
  return String(value || '').replace(/^\/+|\/+$/g, '')
79
101
  }
@@ -1936,6 +1958,16 @@ function collectStandardSitemapEntries ({ pagesDir, pageEntries = [], defaultLan
1936
1958
  return entries
1937
1959
  }
1938
1960
 
1961
+ export function getAdvertisedRobotsSitemapPaths ({ sitemapEnabled = true } = {}) {
1962
+ const paths = []
1963
+
1964
+ if (sitemapEnabled) {
1965
+ paths.push('/sitemap.xml')
1966
+ }
1967
+
1968
+ return paths
1969
+ }
1970
+
1939
1971
  /**
1940
1972
  * Create a Vite plugin that generates static `.md` files at build time.
1941
1973
  *
@@ -2439,9 +2471,7 @@ export async function onRequest (context) {
2439
2471
  }
2440
2472
  }
2441
2473
 
2442
- const robotsSitemapPaths = []
2443
- if (sitemapEnabled) robotsSitemapPaths.push('/sitemap.xml')
2444
- if (aiSearchSitemapGenerated) robotsSitemapPaths.push('/ai-search-sitemap.xml')
2474
+ const robotsSitemapPaths = getAdvertisedRobotsSitemapPaths({ sitemapEnabled })
2445
2475
 
2446
2476
  if (robotsSitemapPaths.length > 0) {
2447
2477
  const robotsPath = resolve(distDir, 'robots.txt')
@@ -3203,21 +3233,23 @@ export function createQuasarConfig (options = {}) {
3203
3233
  ...(viteConf.optimizeDeps.include || []),
3204
3234
  'vue', 'vue-router', 'vuex', 'vue-i18n',
3205
3235
  'prismjs', 'markdown-it', 'markdown-it-attrs',
3236
+ 'markdown-it-task-lists', 'markdown-it-texmath',
3206
3237
  'hjson', 'q-colorize-mixin', 'mermaid'
3207
3238
  ]
3208
3239
 
3209
- // Exclude boot files and the router from pre-bundling.
3240
+ // Exclude boot files and Docsector runtime entry points from pre-bundling.
3210
3241
  // Boot files (especially boot/i18n) import the consumer's src/i18n/index.js
3211
3242
  // which uses import.meta.glob β€” a compile-time Vite directive that only
3212
3243
  // works in source files. If pre-bundled, the glob calls become dead code
3213
3244
  // and no i18n messages are loaded.
3214
- // The router is excluded because routes.js imports consumer content via
3215
- // the `pages` alias. If pre-bundled, consumer content gets embedded in
3216
- // the optimizer cache whose hash doesn't track source file changes,
3217
- // causing stale routes after editing page registry files.
3245
+ // In consumer mode, the package router also imports Vite virtual modules
3246
+ // and consumer content via the `pages` alias. If pre-bundled, Vite can
3247
+ // try resolving those virtual IDs before Docsector's plugins handle them,
3248
+ // or embed stale consumer registry content in the optimizer cache.
3218
3249
  viteConf.optimizeDeps.exclude = [
3219
3250
  ...(viteConf.optimizeDeps.exclude || []),
3220
- 'boot/i18n', 'boot/store', 'boot/QZoom', 'boot/axios'
3251
+ 'boot/i18n', 'boot/store', 'boot/QZoom', 'boot/axios',
3252
+ ...(!isStandalone ? DOCSECTOR_CONSUMER_OPTIMIZE_DEPS_EXCLUDE : [])
3221
3253
  ]
3222
3254
 
3223
3255
  if (!isStandalone) {
package/src/sitemap.js CHANGED
@@ -76,28 +76,37 @@ export function appendSitemapsToRobots (robotsContent, { sitemaps = [], siteUrl
76
76
  ? robotsContent
77
77
  : 'User-agent: *\nAllow: /\n'
78
78
 
79
- const existingIdentities = new Set(
80
- input
81
- .replace(/\r\n/g, '\n')
82
- .split('\n')
83
- .map(line => line.match(/^\s*Sitemap\s*:\s*(.+?)\s*$/i)?.[1])
84
- .filter(Boolean)
85
- .map(normalizeSitemapIdentity)
86
- )
87
-
88
- const addedIdentities = new Set()
89
- const sitemapLines = (Array.isArray(sitemaps) ? sitemaps : [sitemaps])
79
+ const bodyLines = []
80
+ const existingSitemaps = []
81
+
82
+ for (const line of input.replace(/\r\n/g, '\n').split('\n')) {
83
+ const sitemap = line.match(/^\s*Sitemap\s*:\s*(.+?)\s*$/i)?.[1]
84
+ if (sitemap) {
85
+ existingSitemaps.push(sitemap)
86
+ continue
87
+ }
88
+
89
+ bodyLines.push(line)
90
+ }
91
+
92
+ const seenIdentities = new Set()
93
+ const normalizedSitemaps = [
94
+ ...(Array.isArray(sitemaps) ? sitemaps : [sitemaps]),
95
+ ...existingSitemaps
96
+ ]
90
97
  .filter(Boolean)
91
98
  .map(sitemap => resolveSitemapUrl(sitemap, siteUrl))
92
99
  .filter(sitemap => {
93
100
  const identity = normalizeSitemapIdentity(sitemap)
94
- if (existingIdentities.has(identity) || addedIdentities.has(identity)) return false
95
- addedIdentities.add(identity)
101
+ if (seenIdentities.has(identity)) return false
102
+ seenIdentities.add(identity)
96
103
  return true
97
104
  })
98
- .map(sitemap => `Sitemap: ${sitemap}`)
99
105
 
100
- if (sitemapLines.length === 0) return input
106
+ if (normalizedSitemaps.length === 0) return input
107
+
108
+ const body = bodyLines.join('\n').replace(/\s+$/g, '')
109
+ const sitemapLines = normalizedSitemaps.map(sitemap => `Sitemap: ${sitemap}`)
101
110
 
102
- return `${input.replace(/\s+$/g, '')}\n${sitemapLines.join('\n')}\n`
111
+ return `${body}\n\n${sitemapLines.join('\n')}\n`
103
112
  }