Nitro Hooks
These hooks run in the Nitro server. Use Nuxt hooks for build-time output.
'ai-ready:page:markdown'
Type: (ctx: MarkdownContext) => void | Promise<void>
Runs when the module converts rendered HTML to Markdown: a runtime .md request, prerendering, and page indexing. Change ctx.markdown before the module serves, writes, or stores it.
A supplied Markdown source bypasses this conversion hook.
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('ai-ready:page:markdown', (ctx) => {
ctx.markdown += '\n\n---\n*Generated with mdream*'
})
})MarkdownContext:
| Property | Type | Description |
|---|---|---|
html | string | Original HTML |
markdown | string | Generated markdown (modify this) |
route | string | The route the module is processing |
title | string | Page title |
description | string | Page description |
isPrerender | boolean | true during prerendering, false for a runtime request |
event | H3Event | undefined | H3 event object. Undefined when indexing runs outside a request |
'ai-ready:mdreamConfig'
Type: (config: MdreamOptions) => void | Promise<void>
Runs before the module converts rendered HTML to Markdown: at runtime, during prerendering, and during page indexing. Change mdream options for that conversion. Source Markdown does not call this hook.
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('ai-ready:mdreamConfig', (config) => {
config.filter ??= {}
config.filter.exclude = [...(config.filter.exclude || []), '.author-bio']
})
})The hook receives conversion options, without a route field. config.origin contains only the origin.
If you need to change a particular page's Markdown, use ctx.route in ai-ready:page:markdown.
'ai-ready:page:indexed'
Type: (ctx: PageIndexedContext) => void | Promise<void>
Runs after runtime indexing writes a page to the database. Check contentChanged before updating another system.
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('ai-ready:page:indexed', (ctx) => {
if (!ctx.contentChanged)
return
console.info(`Changed page: ${ctx.route}`)
})
})Replace the log with your integration. First indexing counts as a change.
isUpdate only tells you whether an indexed row already existed.
A forced reindex of unchanged content can run the hook with contentChanged: false.
If an external call fails, retry that call separately. The stored hash already changed before the hook ran.
A freshness skip or skipHook: true prevents this hook from running.
The IndexNow recipe shows a changed-URL submission.
PageIndexedContext:
| Property | Type | Description |
|---|---|---|
route | string | Page route |
title | string | Page title |
description | string | Page description |
headings | Array<Record<string, string>> | Parsed headings, such as [{ h1: "Title" }] |
keywords | string[] | Extracted keywords from content |
markdown | string | Full markdown content |
updatedAt | string | ISO timestamp |
isUpdate | boolean | true if an indexed row existed |
contentChanged | boolean | Whether the converted Markdown hash differs |
Manual Indexing Utils
Use indexPage when you have HTML, or indexPageByRoute when the module should fetch it.
These functions belong in trusted server code. See Composables for complete examples.
| Option | Type | Description |
|---|---|---|
ttl | number | Override the freshness window in seconds |
force | boolean | Reindex even if fresh |
skipHook | boolean | Skip ai-ready:page:indexed |
indexPageByRoute takes the event as its second argument. indexPage takes it as the fourth argument.
'ai-ready:markdown:source'
Supply Markdown you already hold instead of converting the rendered HTML.
The route has no .md suffix. Leave ctx.source as null to use normal conversion.
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('ai-ready:markdown:source', (ctx) => {
if (ctx.route === '/about') {
ctx.source = {
title: 'About',
markdown: '# About\n\nOur documentation site.',
}
}
})
})The payload contains route: string, event: H3Event, and source: MarkdownSource | null.
A source requires markdown. It may also provide title, description, and updatedAt.
The module adds its frontmatter to the supplied body. This hook serves Markdown; it does not update the runtime page index.
If the source has page metadata, include it directly in source.markdown.
Image fields stay in frontmatter. JSON-LD stays in a JSON fence:
---
meta:
og:image: https://example.com/cover.png
---
# About
```json
{"@context":"https://schema.org","@type":"Article","headline":"About"}
```The module preserves these source fields while adding its title, canonical URL, and other supplied metadata. It does not fetch HTML to find missing fields or apply HTML conversion limits to supplied Markdown.