[{"data":1,"prerenderedAt":2630},["ShallowReactive",2],{"duxt-navigation-docs-docs":3,"i-lucide:puzzle":942,"i-lucide:search":947,"i-simple-icons:meilisearch":949,"i-lucide:rocket":951,"i-lucide:compass":953,"i-lucide:book-open":955,"i-lucide:list":957,"i-lucide:ruler":959,"i-lucide:gavel":961,"docs-en-US-\u002Fadd-ons\u002Ftypesense":963,"duxt-preferred-missing-\u002Fadd-ons\u002Ftypesense":945,"i-lucide:copy":2558,"i-lucide:chevron-down":2560,"i-lucide:thumbs-up":2562,"i-lucide:thumbs-down":2564,"i-lucide:star":2566,"i-lucide:circle-alert":2568,"i-simple-icons:discord":2570,"i-lucide:book-open-text":2572,"i-lucide:arrow-up-right":2574,"i-lucide:file-code-2":2576,"duxt-version-missing-\u002Fadd-ons\u002Ftypesense":2578,"i-lucide:menu":2587,"i-lucide:keyboard":2589,"i-simple-icons:github":2591,"i-lucide:moon":2593,"duxt-code-ts-export default defineNuxtConfig({\n  extends: ['@kirchdev\u002Fduxt', 'duxt-typesense']\n});\n":13,"i-lucide:info":2595,"i-lucide:lightbulb":2597,"i-lucide:arrow-left":2599,"i-lucide:arrow-right":2601,"i-lucide:chevron-right":2603,"i-flag:us-4x3":2605,"package-managers-add @kirchdev\u002Fduxt-typesense":2609,"i-vscode-icons:file-type-light-pnpm":2614,"i-vscode-icons:file-type-pnpm":2617,"i-vscode-icons:file-type-npm":2619,"i-vscode-icons:file-type-yarn":2621,"i-vscode-icons:file-type-bun":2623,"duxt-code-ts-export default defineNuxtConfig({\n  extends: ['@kirchdev\u002Fduxt', '@kirchdev\u002Fduxt-typesense'],\n  duxtTypesense: {\n    endpoint: process.env.TYPESENSE_ENDPOINT,\n    collection: 'docs',\n    adminKey: process.env.TYPESENSE_ADMIN_KEY,\n    searchKey: process.env.TYPESENSE_SEARCH_KEY\n  }\n})\n":13,"package-managers-add -D typesense":2625,"duxt-code-ts-import type { CollectionCreateSchema } from 'typesense';\n\nexport const docs: CollectionCreateSchema = {\n  name: 'docs',\n  fields: [\n    { name: 'url', type: 'string' },\n    { name: 'title', type: 'string' },\n    { name: 'content', type: 'string' },\n    { name: 'source', type: 'string', facet: true },\n    { name: 'version', type: 'string', facet: true, optional: true },\n    { name: 'locale', type: 'string', facet: true }\n  ]\n};\n":13,"duxt-code-ts-import { defineNuxtModule } from '@nuxt\u002Fkit';\nimport { Client } from 'typesense';\nimport type { DuxtSearchRecord } from '@kirchdev\u002Fduxt\u002Fsearch-records';\nimport { docs } from '..\u002Fserver\u002Ftypesense-schema';\n\nexport default defineNuxtModule({\n  meta: { name: 'typesense-sync' },\n  setup(_options, nuxt) {\n    const key = process.env.TYPESENSE_ADMIN_KEY;\n    \u002F\u002F No key is a local build, not a failure: skip rather than break it.\n    if (!key) return;\n\n    nuxt.hook('duxt:search:records', async (records) => {\n      const client = new Client({\n        nodes: [{ url: process.env.TYPESENSE_URL! }],\n        apiKey: key\n      });\n\n      await sync(client, records);\n    });\n  }\n});\n":13,"duxt-code-ts-async function sync(client: Client, records: readonly DuxtSearchRecord[]) {\n  const collection = client.collections(docs.name);\n\n  \u002F\u002F Typesense creates nothing implicitly: importing into a collection\n  \u002F\u002F that does not exist fails outright, so the first build makes it.\n  if (!(await collection.exists())) await client.collections().create(docs);\n\n  await collection.documents().import(\n    records.map((record) => ({ ...record })),\n    { action: 'upsert' }\n  );\n\n  \u002F\u002F Everything the build did not hand over is no longer on the site.\n  const kept = new Set(records.map((record) => record.id));\n  const live = await collection.documents().export();\n\n  const stale = live\n    .split('\\n')\n    .filter(Boolean)\n    .map((line) => JSON.parse(line).id as string)\n    .filter((id) => !kept.has(id));\n\n  \u002F\u002F Delete in batches: every id goes into the filter string, and one\n  \u002F\u002F large rename would build one long enough for Typesense to reject.\n  for (let index = 0; index \u003C stale.length; index += 100) {\n    const batch = stale.slice(index, index + 100).join(',');\n    await collection.documents().delete({ filter_by: `id:[${batch}]` });\n  }\n}\n":13,"duxt-code-ts-\u002F\u002F `locale` is the language the CONTENT is in, not the interface language.\n\u002F\u002F `version` is absent on an unversioned source, so the clause is added\n\u002F\u002F only when there is one — pasted in flat, it filters on `undefined`.\nconst filters = [`locale:${locale}`];\nif (version) filters.push(`version:${version}`);\n\nconst results = await client.collections('docs').documents().search({\n  q: query,\n  query_by: 'title,content',\n  filter_by: filters.join(' && ')\n});\n":13},[4,31,111,183,826,845,853,878],{"title":5,"path":6,"stem":7,"children":8},"Introduction","\u002Fgetting-started","1.getting-started",[9,14,20,26],{"title":5,"path":6,"stem":10,"icon":11,"description":12,"subcategory":13},"1.getting-started\u002Findex","lucide:rocket","What duxt is, and what arrives with a single line of config.",null,{"title":15,"path":16,"stem":17,"icon":18,"description":19,"subcategory":13},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F1.installation","lucide:download","Add the layer, extend it, write Markdown.",{"title":21,"path":22,"stem":23,"icon":24,"description":25,"subcategory":13},"Configuration","\u002Fgetting-started\u002Fconfiguration","1.getting-started\u002F2.configuration","lucide:settings","One file configures the whole site — what belongs in it, and how it merges.",{"title":27,"path":28,"stem":29,"icon":11,"description":30,"subcategory":13},"Start from the starter","\u002Fgetting-started\u002Ffrom-starter","1.getting-started\u002F3.from-starter","Create a ready-to-run duxt documentation site with Nuxi.",{"title":32,"path":33,"stem":34,"children":35},"Concepts","\u002Fconcepts","2.concepts",[36,40,46,52,58,64,70,76,81,87,93,99,105],{"title":32,"path":33,"stem":37,"icon":38,"description":39,"subcategory":13},"2.concepts\u002Findex","lucide:compass","How the layer works — the sources model, the URL scheme, the collections and the checks.",{"title":41,"path":42,"stem":43,"icon":44,"description":45,"subcategory":13},"Layers and overriding","\u002Fconcepts\u002Flayers","2.concepts\u002F1.layers","lucide:layers","What a Nuxt layer gives you, what it takes away, and which paths do not resolve the way they read.",{"title":47,"path":48,"stem":49,"icon":50,"description":51,"subcategory":13},"Theming","\u002Fconcepts\u002Ftheming","2.concepts\u002F10.theming","lucide:palette","How the theme is put together — owned components, one token layer, and a dark mode that switches on a class.",{"title":53,"path":54,"stem":55,"icon":56,"description":57,"subcategory":13},"Databases","\u002Fconcepts\u002Fdatabases","2.concepts\u002F11.databases","lucide:database","Which Content database adapters a duxt site can deploy on, which of them have been verified, and the one rule that keeps the layer out of the way.",{"title":59,"path":60,"stem":61,"icon":62,"description":63,"subcategory":13},"Keyboard shortcuts","\u002Fconcepts\u002Fkeyboard-shortcuts","2.concepts\u002F12.keyboard-shortcuts","lucide:keyboard","The four keys the theme binds, where each one applies, and where the reader is told about it.",{"title":65,"path":66,"stem":67,"icon":68,"description":69,"subcategory":13},"Sources","\u002Fconcepts\u002Fsources","2.concepts\u002F2.sources","lucide:git-branch","One list of sources becomes every collection, prefix and version the site serves.",{"title":71,"path":72,"stem":73,"icon":74,"description":75,"subcategory":13},"URLs and versions","\u002Fconcepts\u002Furls-and-versions","2.concepts\u002F3.urls-and-versions","lucide:git-compare","How the repository and version segments appear, and what a reader in an old version is told.",{"title":77,"path":78,"stem":79,"icon":56,"description":80,"subcategory":13},"Collections","\u002Fconcepts\u002Fcollections","2.concepts\u002F4.collections","What Content builds from the sources, and the four things the schema adds.",{"title":82,"path":83,"stem":84,"icon":85,"description":86,"subcategory":13},"Generated sections","\u002Fconcepts\u002Fgenerated-sections","2.concepts\u002F5.generated-sections","lucide:file-cog","An artefact plus a type, published as pages — what the registry is, and the two policies a type answers.",{"title":88,"path":89,"stem":90,"icon":91,"description":92,"subcategory":13},"What the build checks","\u002Fconcepts\u002Fbuild-checks","2.concepts\u002F6.build-checks","lucide:shield-check","The silent failures this layer had, turned into messages.",{"title":94,"path":95,"stem":96,"icon":97,"description":98,"subcategory":13},"Machine readers","\u002Fconcepts\u002Fmachine-readers","2.concepts\u002F7.machine-readers","lucide:bot","What a model gets — llms.txt, the raw Markdown of any page, and a real MCP server.",{"title":100,"path":101,"stem":102,"icon":103,"description":104,"subcategory":13},"SEO","\u002Fconcepts\u002Fseo","2.concepts\u002F8.seo","lucide:search","What every page emits for crawlers and social cards, which module writes it, and the one value the layer cannot guess.",{"title":106,"path":107,"stem":108,"icon":109,"description":110,"subcategory":13},"Localisation","\u002Fconcepts\u002Flocalisation","2.concepts\u002F9.localisation","lucide:languages","Seven locales ship with the layer, and every configured string takes three forms.",{"title":112,"path":113,"stem":114,"children":115},"Guides","\u002Fguides","3.guides",[116,120,126,132,138,143,148,153,159,165,171,177],{"title":112,"path":113,"stem":117,"icon":118,"description":119,"subcategory":13},"3.guides\u002Findex","lucide:book-open","One task per page, start to finish — several repositories, several versions, several languages, and a deploy.",{"title":121,"path":122,"stem":123,"icon":124,"description":125,"subcategory":13},"Several repositories","\u002Fguides\u002Fseveral-repositories","3.guides\u002F1.several-repositories","lucide:folder-git","Serve the documentation of several projects from one site.",{"title":127,"path":128,"stem":129,"icon":130,"description":131,"subcategory":13},"Publish Terraform provider docs","\u002Fguides\u002Fpublish-terraform-provider-docs","3.guides\u002F10.publish-terraform-provider-docs","simple-icons:terraform","Turn a tfplugindocs Markdown tree into a versioned provider reference with provider-aware navigation.",{"title":133,"path":134,"stem":135,"icon":136,"description":137,"subcategory":13},"Cache remote sources and OG images","\u002Fguides\u002Fcache-build-work","3.guides\u002F11.cache-build-work","lucide:database-zap","Reuse downloaded public repositories and rendered social cards safely between CI builds.",{"title":139,"path":140,"stem":141,"icon":74,"description":142,"subcategory":13},"Several versions","\u002Fguides\u002Fseveral-versions","3.guides\u002F2.several-versions","Serve the same documentation at several refs, with a switcher and a banner.",{"title":144,"path":145,"stem":146,"icon":109,"description":147,"subcategory":13},"Several languages","\u002Fguides\u002Fseveral-languages","3.guides\u002F3.several-languages","Serve the interface in several languages, and translate the pages themselves.",{"title":149,"path":150,"stem":151,"icon":50,"description":152,"subcategory":13},"Override the theme","\u002Fguides\u002Foverride-the-theme","3.guides\u002F4.override-the-theme","Change a colour, replace a component, add a shadcn-vue primitive.",{"title":154,"path":155,"stem":156,"icon":157,"description":158,"subcategory":13},"Move a page","\u002Fguides\u002Fmove-a-page","3.guides\u002F5.move-a-page","lucide:signpost","redirectFrom in the frontmatter, turned into route rules under every prefix.",{"title":160,"path":161,"stem":162,"icon":163,"description":164,"subcategory":13},"Deploy a site","\u002Fguides\u002Fdeploy-a-site","3.guides\u002F6.deploy-a-site","lucide:cloud-upload","Where a duxt site can run, what it needs there, and why content is not refreshed at runtime.",{"title":166,"path":167,"stem":168,"icon":169,"description":170,"subcategory":13},"Collect page feedback","\u002Fguides\u002Fcollect-page-feedback","3.guides\u002F7.collect-page-feedback","lucide:thumbs-up","Wrap DuxtPageFeedback, keep the answer where your analytics already live.",{"title":172,"path":173,"stem":174,"icon":175,"description":176,"subcategory":13},"Brand your site","\u002Fguides\u002Fbrand-your-site","3.guides\u002F8.brand-your-site","lucide:badge-check","Set the name, the wordmark and the icons, so the site reads as yours rather than as the layer's.",{"title":178,"path":179,"stem":180,"icon":181,"description":182,"subcategory":13},"Send analytics events","\u002Fguides\u002Fsend-analytics-events","3.guides\u002F9.send-analytics-events","lucide:chart-line","One callback, five events, no provider — wire duxt's reader interactions into the analytics you already run.",{"title":184,"path":185,"stem":186,"children":187},"Reference","\u002Freference","4.reference",[188,192,196,228,258,264,268,273,413,570,696,741,801],{"title":184,"path":185,"stem":189,"icon":190,"description":191,"subcategory":13},"4.reference\u002Findex","lucide:list","The layer's public surface — config keys, frontmatter, components, composables and endpoints.",{"title":21,"path":193,"stem":194,"icon":24,"description":195,"subcategory":13},"\u002Freference\u002Fconfiguration","4.reference\u002F1.configuration","Every key under duxt in app.config.ts — what it controls, and when it is read.",{"title":197,"path":198,"stem":199,"children":200,"icon":202,"description":203,"subcategory":13},"Changelog","\u002Freference\u002Fchangelog","4.reference\u002F10.changelog\u002Findex",[201,204,210,216,222],{"title":197,"path":198,"stem":199,"icon":202,"description":203,"subcategory":13},"lucide:tag","A release log, published as pages — a timeline, a page per release, and a feed.",{"title":205,"path":206,"stem":207,"icon":208,"description":209,"subcategory":13},"Declaring the section","\u002Freference\u002Fchangelog\u002Fsection","4.reference\u002F10.changelog\u002F1.section","lucide:file-clock","The `changelog` section type — where the file lives, and the two policies it answers.",{"title":211,"path":212,"stem":213,"icon":214,"description":215,"subcategory":13},"Granularity","\u002Freference\u002Fchangelog\u002Fgranularity","4.reference\u002F10.changelog\u002F2.granularity","lucide:split","A page per release, or the file as the one page it was written as.",{"title":217,"path":218,"stem":219,"icon":220,"description":221,"subcategory":13},"What is read","\u002Freference\u002Fchangelog\u002Fwhat-is-read","4.reference\u002F10.changelog\u002F3.what-is-read","lucide:scan-text","Which headings become releases, which become groups, and what happens to the rest.",{"title":223,"path":224,"stem":225,"icon":226,"description":227,"subcategory":13},"Layout and components","\u002Freference\u002Fchangelog\u002Fcomponents","4.reference\u002F10.changelog\u002F4.components","lucide:box","The layout a split history renders in, and the two MDC components its pages are made of.",{"title":229,"path":230,"stem":231,"children":232,"icon":234,"description":235,"subcategory":13},"Bruno collections","\u002Freference\u002Fbruno","4.reference\u002F11.bruno\u002Findex",[233,236,241,247,253],{"title":229,"path":230,"stem":231,"icon":234,"description":235,"subcategory":13},"lucide:send","A Bruno collection, published as request-centred reference pages with a downloadable archive.",{"title":205,"path":237,"stem":238,"icon":239,"description":240,"subcategory":13},"\u002Freference\u002Fbruno\u002Fsection","4.reference\u002F11.bruno\u002F1.section","lucide:file-code","The `bruno` section type — where the collection lives, and what it becomes.",{"title":242,"path":243,"stem":244,"icon":245,"description":246,"subcategory":13},"What is published","\u002Freference\u002Fbruno\u002Fwhat-is-published","4.reference\u002F11.bruno\u002F2.what-is-published","lucide:shield","Environments, credentials, scripts and tests never reach a page — and what that means for the archive.",{"title":248,"path":249,"stem":250,"icon":251,"description":252,"subcategory":13},"The request client","\u002Freference\u002Fbruno\u002Ftry-it","4.reference\u002F11.bruno\u002F3.try-it","lucide:send-horizontal","Off until a site turns it on, and pointed only at what the site declared public.",{"title":254,"path":255,"stem":256,"icon":18,"description":257,"subcategory":13},"Getting the collection","\u002Freference\u002Fbruno\u002Fgetting-the-collection","4.reference\u002F11.bruno\u002F4.getting-the-collection","The archive is pinned to the page you are on; the Bruno deep link is not.",{"title":259,"path":260,"stem":261,"icon":262,"description":263,"subcategory":13},"Hooks","\u002Freference\u002Fhooks","4.reference\u002F12.hooks","lucide:plug","The one build-time hook duxt emits, what it hands you, and why there is only one.",{"title":65,"path":265,"stem":266,"icon":68,"description":267,"subcategory":13},"\u002Freference\u002Fsources","4.reference\u002F2.sources","The fields of a source entry, its refs, and the options that shape the URLs.",{"title":269,"path":270,"stem":271,"icon":239,"description":272,"subcategory":13},"Frontmatter","\u002Freference\u002Ffrontmatter","4.reference\u002F3.frontmatter","The fields a page may carry beyond title and description, and the two the build fills in.",{"title":274,"path":275,"stem":276,"children":277,"icon":279,"description":280,"subcategory":13},"MDC components","\u002Freference\u002Fmdc-components","4.reference\u002F4.mdc-components\u002Findex",[278,281,287,293,299,305,311,317,323,329,367,373,378,384,390,396,402,408],{"title":274,"path":275,"stem":276,"icon":279,"description":280,"subcategory":13},"lucide:blocks","The blocks a Markdown page can call, one page each, with their props.",{"title":282,"path":283,"stem":284,"icon":285,"description":286,"subcategory":13},"Callout","\u002Freference\u002Fmdc-components\u002Fcallout","4.reference\u002F4.mdc-components\u002F1.callout","lucide:message-square-warning","An aside the reader is meant to stop at — a tip, a warning, a danger.",{"title":288,"path":289,"stem":290,"icon":291,"description":292,"subcategory":13},"Package managers","\u002Freference\u002Fmdc-components\u002Fpackage-managers","4.reference\u002F4.mdc-components\u002F10.package-managers","lucide:package","One command, one tab per package manager, remembered across pages.",{"title":294,"path":295,"stem":296,"icon":297,"description":298,"subcategory":13},"File tree","\u002Freference\u002Fmdc-components\u002Ffile-tree","4.reference\u002F4.mdc-components\u002F11.file-tree","lucide:folder-tree","A folder structure, with icons per file type.",{"title":300,"path":301,"stem":302,"icon":303,"description":304,"subcategory":13},"Preview","\u002Freference\u002Fmdc-components\u002Fpreview","4.reference\u002F4.mdc-components\u002F12.preview","lucide:eye","A component rendered as the page renders it, with its source beside it.",{"title":306,"path":307,"stem":308,"icon":309,"description":310,"subcategory":13},"Page cards","\u002Freference\u002Fmdc-components\u002Fpage-cards","4.reference\u002F4.mdc-components\u002F13.page-cards","lucide:layout-grid","A section's children, as cards.",{"title":312,"path":313,"stem":314,"icon":315,"description":316,"subcategory":13},"Partial","\u002Freference\u002Fmdc-components\u002Fpartial","4.reference\u002F4.mdc-components\u002F14.partial","lucide:puzzle","A block written once and rendered in every source that needs it.",{"title":318,"path":319,"stem":320,"icon":321,"description":322,"subcategory":13},"Since","\u002Freference\u002Fmdc-components\u002Fsince","4.reference\u002F4.mdc-components\u002F15.since","lucide:milestone","The version something arrived in, beside a heading.",{"title":324,"path":325,"stem":326,"icon":327,"description":328,"subcategory":13},"Mermaid","\u002Freference\u002Fmdc-components\u002Fmermaid","4.reference\u002F4.mdc-components\u002F16.mermaid","lucide:workflow","A diagram from a fence or a prop.",{"title":330,"path":331,"stem":332,"children":333,"icon":335,"description":336,"subcategory":13},"Prose overrides","\u002Freference\u002Fmdc-components\u002Fprose","4.reference\u002F4.mdc-components\u002F17.prose\u002Findex",[334,337,343,349,355,361],{"title":330,"path":331,"stem":332,"icon":335,"description":336,"subcategory":13},"lucide:type","What the layer changes about plain Markdown — links, headings, images, code and tables.",{"title":338,"path":339,"stem":340,"icon":341,"description":342,"subcategory":13},"ProseA","\u002Freference\u002Fmdc-components\u002Fprose\u002Fprose-a","4.reference\u002F4.mdc-components\u002F17.prose\u002F1.prose-a","lucide:link","A link, resolved against the source it was written in.",{"title":344,"path":345,"stem":346,"icon":347,"description":348,"subcategory":13},"ProseH2, ProseH3, ProseH4","\u002Freference\u002Fmdc-components\u002Fprose\u002Fprose-headings","4.reference\u002F4.mdc-components\u002F17.prose\u002F2.prose-headings","lucide:heading","Headings, each with a permalink anchor.",{"title":350,"path":351,"stem":352,"icon":353,"description":354,"subcategory":13},"ProseImg","\u002Freference\u002Fmdc-components\u002Fprose\u002Fprose-img","4.reference\u002F4.mdc-components\u002F17.prose\u002F3.prose-img","lucide:image","An image: theme-aware, responsive, and zoomable.",{"title":356,"path":357,"stem":358,"icon":359,"description":360,"subcategory":13},"ProsePre","\u002Freference\u002Fmdc-components\u002Fprose\u002Fprose-pre","4.reference\u002F4.mdc-components\u002F17.prose\u002F4.prose-pre","lucide:terminal","The code block: filename, language icon, copy button.",{"title":362,"path":363,"stem":364,"icon":365,"description":366,"subcategory":13},"ProseTable","\u002Freference\u002Fmdc-components\u002Fprose\u002Fprose-table","4.reference\u002F4.mdc-components\u002F17.prose\u002F5.prose-table","lucide:table","A table that scrolls instead of the page.",{"title":368,"path":369,"stem":370,"icon":371,"description":372,"subcategory":13},"Steps","\u002Freference\u002Fmdc-components\u002Fsteps","4.reference\u002F4.mdc-components\u002F2.steps","lucide:list-ordered","An ordered list drawn as numbered steps on a rail.",{"title":374,"path":375,"stem":376,"icon":239,"description":377,"subcategory":13},"Code group","\u002Freference\u002Fmdc-components\u002Fcode-group","4.reference\u002F4.mdc-components\u002F3.code-group","Several fences as one tabbed block, labelled by filename.",{"title":379,"path":380,"stem":381,"icon":382,"description":383,"subcategory":13},"Tab group","\u002Freference\u002Fmdc-components\u002Ftab-group","4.reference\u002F4.mdc-components\u002F4.tab-group","lucide:panels-top-left","Tabs for anything that is not code.",{"title":385,"path":386,"stem":387,"icon":388,"description":389,"subcategory":13},"Tab","\u002Freference\u002Fmdc-components\u002Ftab","4.reference\u002F4.mdc-components\u002F5.tab","lucide:square","One panel of a tab group.",{"title":391,"path":392,"stem":393,"icon":394,"description":395,"subcategory":13},"Accordion","\u002Freference\u002Fmdc-components\u002Faccordion","4.reference\u002F4.mdc-components\u002F6.accordion","lucide:chevrons-up-down","Collapsible sections — a FAQ, or answers a reader picks from.",{"title":397,"path":398,"stem":399,"icon":400,"description":401,"subcategory":13},"Accordion item","\u002Freference\u002Fmdc-components\u002Faccordion-item","4.reference\u002F4.mdc-components\u002F7.accordion-item","lucide:chevron-down","One collapsible section.",{"title":403,"path":404,"stem":405,"icon":406,"description":407,"subcategory":13},"Field group","\u002Freference\u002Fmdc-components\u002Ffield-group","4.reference\u002F4.mdc-components\u002F8.field-group","lucide:list-tree","A list of fields as one block.",{"title":409,"path":410,"stem":411,"icon":202,"description":412,"subcategory":13},"Field","\u002Freference\u002Fmdc-components\u002Ffield","4.reference\u002F4.mdc-components\u002F9.field","One parameter, property or option, with its type and default.",{"title":414,"path":415,"stem":416,"children":417,"icon":419,"description":420,"subcategory":13},"Components","\u002Freference\u002Fcomponents","4.reference\u002F5.components\u002Findex",[418,421,447,488,539],{"title":414,"path":415,"stem":416,"icon":419,"description":420,"subcategory":13},"lucide:component","The layer's own components, one page each — what each is for, and what it takes.",{"title":422,"path":423,"stem":424,"children":425,"icon":427,"description":428,"subcategory":13},"Layout","\u002Freference\u002Fcomponents\u002Flayout","4.reference\u002F5.components\u002F1.layout\u002Findex",[426,429,435,441],{"title":422,"path":423,"stem":424,"icon":427,"description":428,"subcategory":13},"lucide:layout-panel-top","The three components that frame a page — the navbar, the footer and the site notices.",{"title":430,"path":431,"stem":432,"icon":433,"description":434,"subcategory":13},"DuxtHeader","\u002Freference\u002Fcomponents\u002Flayout\u002Fduxt-header","4.reference\u002F5.components\u002F1.layout\u002F1.duxt-header","lucide:panel-top","The navbar: title, navigation, search, and the icon links.",{"title":436,"path":437,"stem":438,"icon":439,"description":440,"subcategory":13},"DuxtFooter","\u002Freference\u002Fcomponents\u002Flayout\u002Fduxt-footer","4.reference\u002F5.components\u002F1.layout\u002F2.duxt-footer","lucide:panel-bottom","The footer: the site's name, its legal links, and the layer's own line.",{"title":442,"path":443,"stem":444,"icon":445,"description":446,"subcategory":13},"DuxtAnnouncements","\u002Freference\u002Fcomponents\u002Flayout\u002Fduxt-announcements","4.reference\u002F5.components\u002F1.layout\u002F3.duxt-announcements","lucide:megaphone","The site's own notices: one strip per placement, drawn only when there is something to say.",{"title":448,"path":449,"stem":450,"children":451,"icon":38,"description":453,"subcategory":13},"Navigation","\u002Freference\u002Fcomponents\u002Fnavigation","4.reference\u002F5.components\u002F2.navigation\u002Findex",[452,454,460,465,471,477,482],{"title":448,"path":449,"stem":450,"icon":38,"description":453,"subcategory":13},"Getting around — the section row, the sidebar, the trail, the contents and prev\u002Fnext.",{"title":455,"path":456,"stem":457,"icon":458,"description":459,"subcategory":13},"DuxtSections","\u002Freference\u002Fcomponents\u002Fnavigation\u002Fduxt-sections","4.reference\u002F5.components\u002F2.navigation\u002F1.duxt-sections","lucide:rows-3","The second navbar row — the top-level parts of the documentation.",{"title":461,"path":462,"stem":463,"icon":406,"description":464,"subcategory":13},"DuxtNavigation","\u002Freference\u002Fcomponents\u002Fnavigation\u002Fduxt-navigation","4.reference\u002F5.components\u002F2.navigation\u002F2.duxt-navigation","The sidebar tree.",{"title":466,"path":467,"stem":468,"icon":469,"description":470,"subcategory":13},"DuxtNavigationLink","\u002Freference\u002Fcomponents\u002Fnavigation\u002Fduxt-navigation-link","4.reference\u002F5.components\u002F2.navigation\u002F3.duxt-navigation-link","lucide:link-2","One entry of the sidebar.",{"title":472,"path":473,"stem":474,"icon":475,"description":476,"subcategory":13},"DuxtBreadcrumb","\u002Freference\u002Fcomponents\u002Fnavigation\u002Fduxt-breadcrumb","4.reference\u002F5.components\u002F2.navigation\u002F4.duxt-breadcrumb","lucide:chevrons-right","The trail above the page title.",{"title":478,"path":479,"stem":480,"icon":190,"description":481,"subcategory":13},"DuxtToc","\u002Freference\u002Fcomponents\u002Fnavigation\u002Fduxt-toc","4.reference\u002F5.components\u002F2.navigation\u002F5.duxt-toc","The table of contents, and the aside under it.",{"title":483,"path":484,"stem":485,"icon":486,"description":487,"subcategory":13},"DuxtPageNav","\u002Freference\u002Fcomponents\u002Fnavigation\u002Fduxt-page-nav","4.reference\u002F5.components\u002F2.navigation\u002F6.duxt-page-nav","lucide:arrow-left-right","Previous and next, bounded by the section.",{"title":489,"path":490,"stem":491,"children":492,"icon":494,"description":495,"subcategory":13},"Controls","\u002Freference\u002Fcomponents\u002Fcontrols","4.reference\u002F5.components\u002F3.controls\u002Findex",[493,496,501,506,512,517,523,528,534],{"title":489,"path":490,"stem":491,"icon":494,"description":495,"subcategory":13},"lucide:sliders-horizontal","What a reader operates — search, the switchers, the shortcut sheet, and two indicators.",{"title":497,"path":498,"stem":499,"icon":103,"description":500,"subcategory":13},"DuxtSearch","\u002Freference\u002Fcomponents\u002Fcontrols\u002Fduxt-search","4.reference\u002F5.components\u002F3.controls\u002F1.duxt-search","Search every active source and interleave its locally ranked results.",{"title":502,"path":503,"stem":504,"icon":44,"description":505,"subcategory":13},"DuxtVersion","\u002Freference\u002Fcomponents\u002Fcontrols\u002Fduxt-version","4.reference\u002F5.components\u002F3.controls\u002F2.duxt-version","The version badge, and the switcher when there is more than one.",{"title":507,"path":508,"stem":509,"icon":510,"description":511,"subcategory":13},"DuxtVersionBanner","\u002Freference\u002Fcomponents\u002Fcontrols\u002Fduxt-version-banner","4.reference\u002F5.components\u002F3.controls\u002F3.duxt-version-banner","lucide:triangle-alert","The bar telling a reader this version is not the current one.",{"title":513,"path":514,"stem":515,"icon":109,"description":516,"subcategory":13},"DuxtLocale","\u002Freference\u002Fcomponents\u002Fcontrols\u002Fduxt-locale","4.reference\u002F5.components\u002F3.controls\u002F4.duxt-locale","The language switcher.",{"title":518,"path":519,"stem":520,"icon":521,"description":522,"subcategory":13},"DuxtProgress","\u002Freference\u002Fcomponents\u002Fcontrols\u002Fduxt-progress","4.reference\u002F5.components\u002F3.controls\u002F5.duxt-progress","lucide:loader","How far down the page the reader is.",{"title":524,"path":525,"stem":526,"icon":62,"description":527,"subcategory":13},"DuxtShortcuts","\u002Freference\u002Fcomponents\u002Fcontrols\u002Fduxt-shortcuts","4.reference\u002F5.components\u002F3.controls\u002F6.duxt-shortcuts","The keyboard shortcut sheet, on ?.",{"title":529,"path":530,"stem":531,"icon":532,"description":533,"subcategory":13},"DuxtSkipLink","\u002Freference\u002Fcomponents\u002Fcontrols\u002Fduxt-skip-link","4.reference\u002F5.components\u002F3.controls\u002F7.duxt-skip-link","lucide:skip-forward","The first focusable element on the page.",{"title":535,"path":536,"stem":537,"icon":62,"description":538,"subcategory":13},"DuxtShortcutsTrigger","\u002Freference\u002Fcomponents\u002Fcontrols\u002Fduxt-shortcuts-trigger","4.reference\u002F5.components\u002F3.controls\u002F8.duxt-shortcuts-trigger","The button that opens the shortcut sheet.",{"title":540,"path":541,"stem":542,"children":543,"icon":545,"description":546,"subcategory":13},"Page","\u002Freference\u002Fcomponents\u002Fpage","4.reference\u002F5.components\u002F4.page\u002Findex",[544,547,553,559,564],{"title":540,"path":541,"stem":542,"icon":545,"description":546,"subcategory":13},"lucide:file-text","The components that belong to the page itself.",{"title":548,"path":549,"stem":550,"icon":551,"description":552,"subcategory":13},"DuxtPageInfo","\u002Freference\u002Fcomponents\u002Fpage\u002Fduxt-page-info","4.reference\u002F5.components\u002F4.page\u002F1.duxt-page-info","lucide:git-commit-horizontal","Where the page came from: edit link, last updated, contributors.",{"title":554,"path":555,"stem":556,"icon":557,"description":558,"subcategory":13},"DuxtCopyPage","\u002Freference\u002Fcomponents\u002Fpage\u002Fduxt-copy-page","4.reference\u002F5.components\u002F4.page\u002F2.duxt-copy-page","lucide:clipboard-copy","Hand this page to a model, or read its source.",{"title":560,"path":561,"stem":562,"icon":169,"description":563,"subcategory":13},"DuxtPageFeedback","\u002Freference\u002Fcomponents\u002Fpage\u002Fduxt-page-feedback","4.reference\u002F5.components\u002F4.page\u002F3.duxt-page-feedback","Was this page helpful?",{"title":565,"path":566,"stem":567,"icon":568,"description":569,"subcategory":13},"DuxtCodeBlock","\u002Freference\u002Fcomponents\u002Fpage\u002Fduxt-code-block","4.reference\u002F5.components\u002F4.page\u002F4.duxt-code-block","lucide:code","The card around a code block.",{"title":571,"path":572,"stem":573,"children":574,"icon":576,"description":577,"subcategory":13},"Composables","\u002Freference\u002Fcomposables","4.reference\u002F6.composables\u002Findex",[575,578,612,641],{"title":571,"path":572,"stem":573,"icon":576,"description":577,"subcategory":13},"lucide:function-square","The functions the layer exposes to your own components, one page each.",{"title":579,"path":580,"stem":581,"children":582,"icon":56,"description":584,"subcategory":13},"Config and content","\u002Freference\u002Fcomposables\u002Fconfig-and-content","4.reference\u002F6.composables\u002F1.config-and-content\u002Findex",[583,585,590,596,601,607],{"title":579,"path":580,"stem":581,"icon":56,"description":584,"subcategory":13},"The merged config, and which collection serves the page being read.",{"title":586,"path":587,"stem":588,"icon":24,"description":589,"subcategory":13},"useDuxtConfig()","\u002Freference\u002Fcomposables\u002Fconfig-and-content\u002Fuse-duxt-config","4.reference\u002F6.composables\u002F1.config-and-content\u002F1.use-duxt-config","The merged config, every text field already resolved.",{"title":591,"path":592,"stem":593,"icon":594,"description":595,"subcategory":13},"useDuxtCollection()","\u002Freference\u002Fcomposables\u002Fconfig-and-content\u002Fuse-duxt-collection","4.reference\u002F6.composables\u002F1.config-and-content\u002F2.use-duxt-collection","lucide:library","Which collection serves this route.",{"title":597,"path":598,"stem":599,"icon":406,"description":600,"subcategory":13},"useDuxtNavigation()","\u002Freference\u002Fcomposables\u002Fconfig-and-content\u002Fuse-duxt-navigation","4.reference\u002F6.composables\u002F1.config-and-content\u002F3.use-duxt-navigation","The navigation tree for the collection serving this route.",{"title":602,"path":603,"stem":604,"icon":605,"description":606,"subcategory":13},"useDuxtSection()","\u002Freference\u002Fcomposables\u002Fconfig-and-content\u002Fuse-duxt-section","4.reference\u002F6.composables\u002F1.config-and-content\u002F4.use-duxt-section","lucide:folder-open","The part of the documentation this page is in.",{"title":608,"path":609,"stem":610,"icon":475,"description":611,"subcategory":13},"useDuxtBreadcrumb()","\u002Freference\u002Fcomposables\u002Fconfig-and-content\u002Fuse-duxt-breadcrumb","4.reference\u002F6.composables\u002F1.config-and-content\u002F5.use-duxt-breadcrumb","The trail from the section down to a page.",{"title":613,"path":614,"stem":615,"children":616,"icon":618,"description":619,"subcategory":13},"Paths and versions","\u002Freference\u002Fcomposables\u002Fpaths-and-versions","4.reference\u002F6.composables\u002F2.paths-and-versions\u002Findex",[617,620,625,630,635],{"title":613,"path":614,"stem":615,"icon":618,"description":619,"subcategory":13},"lucide:route","Reading a URL, writing one back out, and knowing which version is being read.",{"title":621,"path":622,"stem":623,"icon":321,"description":624,"subcategory":13},"useDuxtPath()","\u002Freference\u002Fcomposables\u002Fpaths-and-versions\u002Fuse-duxt-path","4.reference\u002F6.composables\u002F2.paths-and-versions\u002F1.use-duxt-path","The path the documentation is at, locale stripped.",{"title":626,"path":627,"stem":628,"icon":341,"description":629,"subcategory":13},"useDuxtLink()","\u002Freference\u002Fcomposables\u002Fpaths-and-versions\u002Fuse-duxt-link","4.reference\u002F6.composables\u002F2.paths-and-versions\u002F2.use-duxt-link","A documentation path, written back out as a link.",{"title":631,"path":632,"stem":633,"icon":44,"description":634,"subcategory":13},"useDuxtVersion()","\u002Freference\u002Fcomposables\u002Fpaths-and-versions\u002Fuse-duxt-version","4.reference\u002F6.composables\u002F2.paths-and-versions\u002F3.use-duxt-version","What the switcher shows, what the banner says, whether to index.",{"title":636,"path":637,"stem":638,"icon":639,"description":640,"subcategory":13},"useDuxtSiteUrl()","\u002Freference\u002Fcomposables\u002Fpaths-and-versions\u002Fuse-duxt-site-url","4.reference\u002F6.composables\u002F2.paths-and-versions\u002F4.use-duxt-site-url","lucide:globe","The configured origin, and paths made absolute.",{"title":642,"path":643,"stem":644,"children":645,"icon":118,"description":647,"subcategory":13},"Reading experience","\u002Freference\u002Fcomposables\u002Freading","4.reference\u002F6.composables\u002F3.reading\u002Findex",[646,648,652,658,663,669,675,680,686,691],{"title":642,"path":643,"stem":644,"icon":118,"description":647,"subcategory":13},"Search, headings, focus, history, and the choices a reader makes.",{"title":649,"path":650,"stem":651,"icon":103,"description":500,"subcategory":13},"useDuxtSearch()","\u002Freference\u002Fcomposables\u002Freading\u002Fuse-duxt-search","4.reference\u002F6.composables\u002F3.reading\u002F1.use-duxt-search",{"title":653,"path":654,"stem":655,"icon":656,"description":657,"subcategory":13},"useFuzzySearch()","\u002Freference\u002Fcomposables\u002Freading\u002Fuse-fuzzy-search","4.reference\u002F6.composables\u002F3.reading\u002F2.use-fuzzy-search","lucide:spell-check","Typo tolerance beside the exact index.",{"title":659,"path":660,"stem":661,"icon":347,"description":662,"subcategory":13},"useActiveHeading()","\u002Freference\u002Fcomposables\u002Freading\u002Fuse-active-heading","4.reference\u002F6.composables\u002F3.reading\u002F3.use-active-heading","The heading currently in view.",{"title":664,"path":665,"stem":666,"icon":667,"description":668,"subcategory":13},"useDuxtPageFocus()","\u002Freference\u002Fcomposables\u002Freading\u002Fuse-duxt-page-focus","4.reference\u002F6.composables\u002F3.reading\u002F4.use-duxt-page-focus","lucide:focus","Moves focus to the heading after a client-side navigation.",{"title":670,"path":671,"stem":672,"icon":673,"description":674,"subcategory":13},"useRecentPages()","\u002Freference\u002Fcomposables\u002Freading\u002Fuse-recent-pages","4.reference\u002F6.composables\u002F3.reading\u002F5.use-recent-pages","lucide:history","The most recent pages this reader opened, up to the configured limit.",{"title":676,"path":677,"stem":678,"icon":291,"description":679,"subcategory":13},"usePackageManager()","\u002Freference\u002Fcomposables\u002Freading\u002Fuse-package-manager","4.reference\u002F6.composables\u002F3.reading\u002F6.use-package-manager","The package manager a reader picked.",{"title":681,"path":682,"stem":683,"icon":684,"description":685,"subcategory":13},"useDuxtToast()","\u002Freference\u002Fcomposables\u002Freading\u002Fuse-duxt-toast","4.reference\u002F6.composables\u002F3.reading\u002F7.use-duxt-toast","lucide:bell","Notifications, wrapped so no component imports the library.",{"title":687,"path":688,"stem":689,"icon":62,"description":690,"subcategory":13},"useDuxtShortcuts()","\u002Freference\u002Fcomposables\u002Freading\u002Fuse-duxt-shortcuts","4.reference\u002F6.composables\u002F3.reading\u002F8.use-duxt-shortcuts","The keys the theme listens to.",{"title":692,"path":693,"stem":694,"icon":181,"description":695,"subcategory":13},"useDuxtAnalytics()","\u002Freference\u002Fcomposables\u002Freading\u002Fuse-duxt-analytics","4.reference\u002F6.composables\u002F3.reading\u002F9.use-duxt-analytics","Report one reader interaction to the site's own callback, or to nobody.",{"title":697,"path":698,"stem":699,"children":700,"icon":618,"description":702,"subcategory":13},"Endpoints","\u002Freference\u002Fendpoints","4.reference\u002F7.endpoints\u002Findex",[701,703,708,714,719,724,729,735],{"title":697,"path":698,"stem":699,"icon":618,"description":702,"subcategory":13},"Everything the site serves besides pages, one page each.",{"title":704,"path":705,"stem":706,"icon":545,"description":707,"subcategory":13},"\u002Fllms.txt","\u002Freference\u002Fendpoints\u002Fllms-txt","4.reference\u002F7.endpoints\u002F1.llms-txt","The documentation as a Markdown index, per llmstxt.org.",{"title":709,"path":710,"stem":711,"icon":712,"description":713,"subcategory":13},"\u002Fllms-full.txt","\u002Freference\u002Fendpoints\u002Fllms-full-txt","4.reference\u002F7.endpoints\u002F2.llms-full-txt","lucide:file-stack","A duxt extension with the same pages in one Markdown file.",{"title":715,"path":716,"stem":717,"icon":239,"description":718,"subcategory":13},"\u003Cpage>.md","\u002Freference\u002Fendpoints\u002Fpage-markdown","4.reference\u002F7.endpoints\u002F3.page-markdown","Any page source, at its own URL plus .md.",{"title":720,"path":721,"stem":722,"icon":97,"description":723,"subcategory":13},"\u002Fmcp","\u002Freference\u002Fendpoints\u002Fmcp","4.reference\u002F7.endpoints\u002F4.mcp","An MCP server over the same content.",{"title":725,"path":726,"stem":727,"icon":103,"description":728,"subcategory":13},"\u002Fsitemap.xml and \u002Frobots.txt","\u002Freference\u002Fendpoints\u002Fsitemap-and-robots","4.reference\u002F7.endpoints\u002F5.sitemap-and-robots","What a crawler is pointed at, and what it is kept out of.",{"title":730,"path":731,"stem":732,"icon":733,"description":734,"subcategory":13},"\u002Frss.xml","\u002Freference\u002Fendpoints\u002Frss-xml","4.reference\u002F7.endpoints\u002F6.rss-xml","lucide:rss","The feed, once a section is named.",{"title":736,"path":737,"stem":738,"icon":739,"description":740,"subcategory":13},"\u002F_duxt\u002Fdevtools","\u002Freference\u002Fendpoints\u002Fdevtools","4.reference\u002F7.endpoints\u002F7.devtools","lucide:wrench","The route the Nuxt Devtools panel is served from. Dev only.",{"title":742,"path":743,"stem":744,"children":745,"icon":739,"description":747,"subcategory":13},"Devtools","\u002Freference\u002Fdevtools","4.reference\u002F8.devtools\u002Findex",[746,748,752,757,762,768,774,780,785,790,795],{"title":742,"path":743,"stem":744,"icon":739,"description":747,"subcategory":13},"Ten panels that show what your sources became. Dev only.",{"title":65,"path":749,"stem":750,"icon":594,"description":751,"subcategory":13},"\u002Freference\u002Fdevtools\u002Fsources","4.reference\u002F8.devtools\u002F1.sources","What `duxt.sources` became — one collection per source, version and language.",{"title":753,"path":754,"stem":755,"icon":157,"description":756,"subcategory":13},"Redirects","\u002Freference\u002Fdevtools\u002Fredirects","4.reference\u002F8.devtools\u002F10.redirects","Every redirect the server ships, and which of them the layer wrote.",{"title":758,"path":759,"stem":760,"icon":618,"description":761,"subcategory":13},"Paths","\u002Freference\u002Fdevtools\u002Fpaths","4.reference\u002F8.devtools\u002F2.paths","Paste a URL, see which source claims it and what it finds there.",{"title":763,"path":764,"stem":765,"icon":766,"description":767,"subcategory":13},"Pages","\u002Freference\u002Fdevtools\u002Fpages","4.reference\u002F8.devtools\u002F3.pages","lucide:files","Every page of every collection, with its frontmatter and git metadata.",{"title":769,"path":770,"stem":771,"icon":772,"description":773,"subcategory":13},"Versions","\u002Freference\u002Fdevtools\u002Fversions","4.reference\u002F8.devtools\u002F4.versions","lucide:columns-3","Which version — and which language — carries which page.",{"title":775,"path":776,"stem":777,"icon":778,"description":779,"subcategory":13},"Checks","\u002Freference\u002Fdevtools\u002Fchecks","4.reference\u002F8.devtools\u002F5.checks","lucide:check-check","The build validator, run against what the site is serving now.",{"title":781,"path":782,"stem":783,"icon":103,"description":784,"subcategory":13},"Search","\u002Freference\u002Fdevtools\u002Fsearch","4.reference\u002F8.devtools\u002F6.search","What the search index holds, through the same query the dialog runs.",{"title":786,"path":787,"stem":788,"icon":494,"description":789,"subcategory":13},"Config","\u002Freference\u002Fdevtools\u002Fconfig","4.reference\u002F8.devtools\u002F7.config","The merged `duxt` config, and which side of the merge each value came from.",{"title":791,"path":792,"stem":793,"icon":109,"description":794,"subcategory":13},"i18n","\u002Freference\u002Fdevtools\u002Fi18n","4.reference\u002F8.devtools\u002F8.i18n","Message keys per locale, against the base language.",{"title":796,"path":797,"stem":798,"icon":799,"description":800,"subcategory":13},"Cache","\u002Freference\u002Fdevtools\u002Fcache","4.reference\u002F8.devtools\u002F9.cache","lucide:hard-drive","Content's download cache, and a way to drop one entry.",{"title":802,"path":803,"stem":804,"children":805,"icon":262,"description":807,"subcategory":13},"API reference","\u002Freference\u002Fopenapi","4.reference\u002F9.openapi\u002Findex",[806,808,812,816,821],{"title":802,"path":803,"stem":804,"icon":262,"description":807,"subcategory":13},"An OpenAPI document, published as reference pages with a client that sends real requests.",{"title":205,"path":809,"stem":810,"icon":239,"description":811,"subcategory":13},"\u002Freference\u002Fopenapi\u002Fsection","4.reference\u002F9.openapi\u002F1.section","The `openapi` section type — where the document lives, and what it becomes.",{"title":414,"path":813,"stem":814,"icon":226,"description":815,"subcategory":13},"\u002Freference\u002Fopenapi\u002Fcomponents","4.reference\u002F9.openapi\u002F2.components","The three MDC components a generated reference page is made of.",{"title":817,"path":818,"stem":819,"icon":234,"description":820,"subcategory":13},"The try-it client","\u002Freference\u002Fopenapi\u002Ftry-it","4.reference\u002F9.openapi\u002F3.try-it","A real request, sent by the reader's own browser.",{"title":822,"path":823,"stem":824,"icon":568,"description":825,"subcategory":13},"Request samples","\u002Freference\u002Fopenapi\u002Frequest-samples","4.reference\u002F9.openapi\u002F4.request-samples","The same request in twelve clients, and how to add your own.",{"title":827,"path":828,"stem":829,"children":830},"Add-ons","\u002Fadd-ons","5.add-ons",[831,834,839],{"title":827,"path":828,"stem":832,"icon":315,"description":833,"subcategory":13},"5.add-ons\u002Findex","Companion layers that extend a duxt site — each one its own package, added with one more entry in extends.",{"title":835,"path":836,"stem":837,"icon":103,"description":838,"subcategory":13},"Typesense","\u002Fadd-ons\u002Ftypesense","5.add-ons\u002F1.typesense","Consume duxt's one build hook into a Typesense collection — every source, version and language, upserted by a stable id.",{"title":840,"path":841,"stem":842,"icon":843,"description":844,"subcategory":13},"Meilisearch","\u002Fadd-ons\u002Fmeilisearch","5.add-ons\u002F2.meilisearch","simple-icons:meilisearch","Add the official companion layer for atomic build-time indexing and optional browser search.",{"title":846,"path":847,"stem":848,"children":849,"icon":851,"description":852,"subcategory":13},"Credits","\u002Fcredits","6.credits\u002Findex",[850],{"title":846,"path":847,"stem":848,"icon":851,"description":852,"subcategory":13},"lucide:heart","What duxt is built on, and what it was built after.",{"title":854,"path":855,"stem":856,"children":857},"Conventions","\u002Fconventions","7.conventions",[858,862,868,873],{"title":854,"path":855,"stem":859,"icon":860,"description":861,"subcategory":13},"7.conventions\u002Findex","lucide:ruler","Project-specific rules — the ones a reader could not infer from the code.",{"title":863,"path":864,"stem":865,"icon":866,"description":867,"subcategory":13},"Branding","\u002Fconventions\u002Fbranding","7.conventions\u002F1.branding","lucide:shapes","The [d]uxt mark — where each asset is used, why the icon's brackets are redrawn, and the colours that are fixed.",{"title":869,"path":870,"stem":871,"icon":353,"description":872,"subcategory":13},"Icons","\u002Fconventions\u002Ficons","7.conventions\u002F2.icons","Four icon sets, and the one question that decides which of them draws a given mark.",{"title":874,"path":875,"stem":876,"icon":91,"description":877,"subcategory":13},"Dependency security","\u002Fconventions\u002Fdependency-security","7.conventions\u002F3.dependency-security","Review dependency advisories without hiding affected paths.",{"title":879,"path":880,"stem":881,"children":882},"Architecture decisions","\u002Fadr","99.adr",[883,887,892,897,902,907,912,917,922,927,932,937],{"title":879,"path":880,"stem":884,"icon":885,"description":886,"subcategory":13},"99.adr\u002Findex","lucide:gavel","The decision log — every architecture decision recorded for duxt.",{"title":888,"path":889,"stem":890,"icon":13,"description":891,"subcategory":13},"Build duxt as a layer carrying a module","\u002Fadr\u002F0001-build-duxt-as-a-layer-carrying-a-module","99.adr\u002F0001-build-duxt-as-a-layer-carrying-a-module","Distribute the theme as a Nuxt layer whose root is the package, rather than as a starter template.",{"title":893,"path":894,"stem":895,"icon":13,"description":896,"subcategory":13},"Generate the collections from one source list","\u002Fadr\u002F0002-generate-the-collections-from-one-source-list","99.adr\u002F0002-generate-the-collections-from-one-source-list","Compute Content collections from a compact sources list at config load time instead of having consumers declare them.",{"title":898,"path":899,"stem":900,"icon":13,"description":901,"subcategory":13},"Decide the URL prefixes at build time","\u002Fadr\u002F0003-decide-the-url-prefixes-at-build-time","99.adr\u002F0003-decide-the-url-prefixes-at-build-time","Whether a repository or version segment appears is settled by the source list before the first request, never per request.",{"title":903,"path":904,"stem":905,"icon":13,"description":906,"subcategory":13},"Render Markdown components with MDC","\u002Fadr\u002F0004-render-markdown-components-with-mdc","99.adr\u002F0004-render-markdown-components-with-mdc","Use Content's own MDC syntax for components inside Markdown rather than adopting MDX.",{"title":908,"path":909,"stem":910,"icon":13,"description":911,"subcategory":13},"Ship the layer without owner-specific links","\u002Fadr\u002F0005-ship-the-layer-without-owner-specific-links","99.adr\u002F0005-ship-the-layer-without-owner-specific-links","Every default that would name a specific project — repository, issue tracker, community, imprint — ships empty.",{"title":913,"path":914,"stem":915,"icon":13,"description":916,"subcategory":13},"Rebuild on a schedule rather than refresh at runtime","\u002Fadr\u002F0006-rebuild-on-a-schedule-rather-than-refresh-at-runtime","99.adr\u002F0006-rebuild-on-a-schedule-rather-than-refresh-at-runtime","A site reading another repository picks up its changes when it builds, and no runtime refresh is offered.",{"title":918,"path":919,"stem":920,"icon":13,"description":921,"subcategory":13},"Serve translations as collections of their own","\u002Fadr\u002F0007-serve-translations-as-collections-of-their-own","99.adr\u002F0007-serve-translations-as-collections-of-their-own","Add a locale dimension to a source rather than a locale segment to the content path.",{"title":923,"path":924,"stem":925,"icon":13,"description":926,"subcategory":13},"Build the theme on owned shadcn-vue components","\u002Fadr\u002F0008-build-the-theme-on-owned-shadcn-vue-components","99.adr\u002F0008-build-the-theme-on-owned-shadcn-vue-components","The layer holds the source of its interface components rather than importing them from a component library or a ready-made documentation theme.",{"title":928,"path":929,"stem":930,"icon":13,"description":931,"subcategory":13},"Take the SEO stack from the Nuxt SEO bundle","\u002Fadr\u002F0009-take-the-seo-stack-from-the-nuxt-seo-bundle","99.adr\u002F0009-take-the-seo-stack-from-the-nuxt-seo-bundle","The layer installs @nuxtjs\u002Fseo and hands it the head tags and structured data it used to write by hand, keeping only the rules that depend on versions and translations.",{"title":933,"path":934,"stem":935,"icon":13,"description":936,"subcategory":13},"Keep Content's per-collection search as the default","\u002Fadr\u002F0010-keep-contents-per-collection-search-as-the-default","99.adr\u002F0010-keep-contents-per-collection-search-as-the-default","One index across every source was measured against Content's one-index-per-collection search and is not the layer's default; the build-time hook makes it a provider layer instead.",{"title":938,"path":939,"stem":940,"icon":13,"description":941,"subcategory":13},"Host the provider layers in a Turborepo monorepo","\u002Fadr\u002F0011-host-the-provider-layers-in-a-turborepo-monorepo","99.adr\u002F0011-host-the-provider-layers-in-a-turborepo-monorepo","The layer moves to packages\u002Fduxt and the site to apps\u002Fwww, every published package versions and tags on its own as \u003Cname>@vX.Y.Z, and the own-repository decision recorded in",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":946},0,24,false,"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15.39 4.39a1 1 0 0 0 1.68-.474a2.5 2.5 0 1 1 3.014 3.015a1 1 0 0 0-.474 1.68l1.683 1.682a2.414 2.414 0 0 1 0 3.414L19.61 15.39a1 1 0 0 1-1.68-.474a2.5 2.5 0 1 0-3.014 3.015a1 1 0 0 1 .474 1.68l-1.683 1.682a2.414 2.414 0 0 1-3.414 0L8.61 19.61a1 1 0 0 0-1.68.474a2.5 2.5 0 1 1-3.014-3.015a1 1 0 0 0 .474-1.68l-1.683-1.682a2.414 2.414 0 0 1 0-3.414L4.39 8.61a1 1 0 0 1 1.68.474a2.5 2.5 0 1 0 3.014-3.015a1 1 0 0 1-.474-1.68l1.683-1.682a2.414 2.414 0 0 1 3.414 0z\"\u002F>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":948},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"m21 21l-4.34-4.34\"\u002F>\u003Ccircle cx=\"11\" cy=\"11\" r=\"8\"\u002F>\u003C\u002Fg>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":950},"\u003Cpath fill=\"currentColor\" d=\"m6.505 18.998l4.434-11.345a4.17 4.17 0 0 1 3.882-2.651h2.674l-4.434 11.345a4.17 4.17 0 0 1-3.883 2.651zm6.505 0l4.434-11.345a4.17 4.17 0 0 1 3.883-2.651H24l-4.434 11.345a4.17 4.17 0 0 1-3.882 2.651zm-13.01 0L4.434 7.653a4.17 4.17 0 0 1 3.882-2.651h2.674L6.556 16.347a4.17 4.17 0 0 1-3.883 2.651z\"\u002F>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":952},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09\"\u002F>\u003Cpath d=\"M9 12a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.4 22.4 0 0 1-4 2z\"\u002F>\u003Cpath d=\"M9 12H4s.55-3.03 2-4c1.62-1.08 5 .05 5 .05\"\u002F>\u003C\u002Fg>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":954},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cpath d=\"m16.24 7.76l-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z\"\u002F>\u003C\u002Fg>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":956},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 5v16m8.001-2A2 2 0 0 0 22 17V5a2 2 0 0 0-1.999-2L16 3.002A5 5 0 0 0 12 5a5 5 0 0 0-4-2H4a2 2 0 0 0-2 2v12a2 2 0 0 0 1.999 2H8a5 5 0 0 1 4 2a5 5 0 0 1 4-2z\"\u002F>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":958},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M3 5h.01M3 12h.01M3 19h.01M8 5h13M8 12h13M8 19h13\"\u002F>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":960},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M21.3 15.3a2.4 2.4 0 0 1 0 3.4l-2.6 2.6a2.4 2.4 0 0 1-3.4 0L2.7 8.7a2.41 2.41 0 0 1 0-3.4l2.6-2.6a2.41 2.41 0 0 1 3.4 0Zm-6.8-2.8l2-2m-5-1l2-2m-5-1l2-2m7 11l2-2\"\u002F>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":962},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m14 13l-8.381 8.38a1 1 0 0 1-3.001-3l8.384-8.381M16 16l6-6m-.5.5l-8-8M8 8l6-6M8.5 7.5l8 8\"\u002F>",{"page":964,"from":2556,"asked":2557},{"id":965,"title":835,"body":966,"breadcrumb":1193,"category":13,"compare":13,"contributors":13,"copyPage":1193,"date":13,"description":838,"extension":2548,"feedback":1193,"fullWidth":945,"icon":103,"lastUpdated":13,"layout":13,"meta":2549,"navigation":1193,"pageInfo":1193,"page_title":13,"path":836,"prevNext":1193,"rawbody":2550,"redirectFrom":2551,"release":13,"search":1193,"seo":2553,"sitemap":2554,"stem":837,"subcategory":13,"toc":13,"__hash__":2555},"docs\u002F5.add-ons\u002F1.typesense.md",{"type":967,"value":968,"toc":2541},"minimark",[969,982,994,999,1007,1011,1122,1133,1136,2338,2342,2349,2413,2420,2424,2435,2468,2474,2478,2537],[970,971,972,973,977,978,981],"p",{},"duxt emits ",[974,975,976],"a",{"href":260},"one build-time hook",", and it hands over every page\nof every source, version and language as flat records. A site that already runs\n",[979,980,835],"strong",{}," turns those records into a collection of its own — without\nre-crawling the rendered site, and without reimplementing duxt's source, version\nand locale logic.",[983,984,987],"callout",{"title":985,"type":986},"The service is yours, not duxt's","info",[970,988,989,990,993],{},"duxt ships no Typesense SDK, credentials or service configuration. The optional companion layer owns that integration; you own the service and its keys. Without a provider or a custom listener, duxt ",[974,991,992],{"href":260},"builds no payload at all",".",[995,996,998],"h2",{"id":997},"use-the-companion-layer","Use the companion layer",[970,1000,1001,1002,1006],{},"For the packaged integration, install ",[1003,1004,1005],"code",{},"@kirchdev\u002Fduxt-typesense"," and extend it after duxt. It synchronizes the complete set through a staging collection and alias swap, removes the previous managed collection, and connects the existing search dialog with a search-only key. The steps below remain a recipe for custom synchronization.",[1008,1009],"package-managers",{"command":1010},"add @kirchdev\u002Fduxt-typesense",[1012,1013,1019],"pre",{"className":1014,"code":1015,"filename":1016,"language":1017,"meta":1018,"style":1018},"language-ts shiki shiki-themes github-light github-dark","export default defineNuxtConfig({\n  extends: ['@kirchdev\u002Fduxt', '@kirchdev\u002Fduxt-typesense'],\n  duxtTypesense: {\n    endpoint: process.env.TYPESENSE_ENDPOINT,\n    collection: 'docs',\n    adminKey: process.env.TYPESENSE_ADMIN_KEY,\n    searchKey: process.env.TYPESENSE_SEARCH_KEY\n  }\n})\n","nuxt.config.ts","ts","",[1003,1020,1021,1041,1060,1066,1079,1090,1101,1110,1116],{"__ignoreMap":1018},[1022,1023,1026,1030,1033,1037],"span",{"class":1024,"line":1025},"line",1,[1022,1027,1029],{"class":1028},"szBVR","export",[1022,1031,1032],{"class":1028}," default",[1022,1034,1036],{"class":1035},"sScJk"," defineNuxtConfig",[1022,1038,1040],{"class":1039},"sVt8B","({\n",[1022,1042,1044,1047,1051,1054,1057],{"class":1024,"line":1043},2,[1022,1045,1046],{"class":1039},"  extends: [",[1022,1048,1050],{"class":1049},"sZZnC","'@kirchdev\u002Fduxt'",[1022,1052,1053],{"class":1039},", ",[1022,1055,1056],{"class":1049},"'@kirchdev\u002Fduxt-typesense'",[1022,1058,1059],{"class":1039},"],\n",[1022,1061,1063],{"class":1024,"line":1062},3,[1022,1064,1065],{"class":1039},"  duxtTypesense: {\n",[1022,1067,1069,1072,1076],{"class":1024,"line":1068},4,[1022,1070,1071],{"class":1039},"    endpoint: process.env.",[1022,1073,1075],{"class":1074},"sj4cs","TYPESENSE_ENDPOINT",[1022,1077,1078],{"class":1039},",\n",[1022,1080,1082,1085,1088],{"class":1024,"line":1081},5,[1022,1083,1084],{"class":1039},"    collection: ",[1022,1086,1087],{"class":1049},"'docs'",[1022,1089,1078],{"class":1039},[1022,1091,1093,1096,1099],{"class":1024,"line":1092},6,[1022,1094,1095],{"class":1039},"    adminKey: process.env.",[1022,1097,1098],{"class":1074},"TYPESENSE_ADMIN_KEY",[1022,1100,1078],{"class":1039},[1022,1102,1104,1107],{"class":1024,"line":1103},7,[1022,1105,1106],{"class":1039},"    searchKey: process.env.",[1022,1108,1109],{"class":1074},"TYPESENSE_SEARCH_KEY\n",[1022,1111,1113],{"class":1024,"line":1112},8,[1022,1114,1115],{"class":1039},"  }\n",[1022,1117,1119],{"class":1024,"line":1118},9,[1022,1120,1121],{"class":1039},"})\n",[970,1123,1124,1125,1128,1129,1132],{},"Keep the admin key in build-only configuration. ",[1003,1126,1127],{},"searchKey"," must have only ",[1003,1130,1131],{},"documents:search"," for this alias, and Typesense must allow browser requests from your site.",[995,1134,368],{"id":1135},"steps",[1135,1137,1138,1152,1155,1163,1347,1354,1374,1391,1403,1667,1674,1687,2162,2169,2180,2192,2326],{},[1139,1140,1141],"ol",{},[1142,1143,1144,1147,1148,1151],"li",{},[979,1145,1146],{},"Install the client in your site."," It is a build-time dependency: the sync\nruns in Node during ",[1003,1149,1150],{},"nuxt build",", never in the browser.",[1008,1153],{"command":1154},"add -D typesense",[1139,1156,1157],{"start":1043},[1142,1158,1159,1162],{},[979,1160,1161],{},"Declare the collection."," Every field a duxt record carries maps onto one\nTypesense field, and the two provenance fields are what a reader filters by:",[1012,1164,1167],{"className":1014,"code":1165,"filename":1166,"language":1017,"meta":1018,"style":1018},"import type { CollectionCreateSchema } from 'typesense';\n\nexport const docs: CollectionCreateSchema = {\n  name: 'docs',\n  fields: [\n    { name: 'url', type: 'string' },\n    { name: 'title', type: 'string' },\n    { name: 'content', type: 'string' },\n    { name: 'source', type: 'string', facet: true },\n    { name: 'version', type: 'string', facet: true, optional: true },\n    { name: 'locale', type: 'string', facet: true }\n  ]\n};\n","server\u002Ftypesense-schema.ts",[1003,1168,1169,1189,1195,1217,1226,1231,1248,1261,1274,1293,1316,1335,1341],{"__ignoreMap":1018},[1022,1170,1171,1174,1177,1180,1183,1186],{"class":1024,"line":1025},[1022,1172,1173],{"class":1028},"import",[1022,1175,1176],{"class":1028}," type",[1022,1178,1179],{"class":1039}," { CollectionCreateSchema } ",[1022,1181,1182],{"class":1028},"from",[1022,1184,1185],{"class":1049}," 'typesense'",[1022,1187,1188],{"class":1039},";\n",[1022,1190,1191],{"class":1024,"line":1043},[1022,1192,1194],{"emptyLinePlaceholder":1193},true,"\n",[1022,1196,1197,1199,1202,1205,1208,1211,1214],{"class":1024,"line":1062},[1022,1198,1029],{"class":1028},[1022,1200,1201],{"class":1028}," const",[1022,1203,1204],{"class":1074}," docs",[1022,1206,1207],{"class":1028},":",[1022,1209,1210],{"class":1035}," CollectionCreateSchema",[1022,1212,1213],{"class":1028}," =",[1022,1215,1216],{"class":1039}," {\n",[1022,1218,1219,1222,1224],{"class":1024,"line":1068},[1022,1220,1221],{"class":1039},"  name: ",[1022,1223,1087],{"class":1049},[1022,1225,1078],{"class":1039},[1022,1227,1228],{"class":1024,"line":1081},[1022,1229,1230],{"class":1039},"  fields: [\n",[1022,1232,1233,1236,1239,1242,1245],{"class":1024,"line":1092},[1022,1234,1235],{"class":1039},"    { name: ",[1022,1237,1238],{"class":1049},"'url'",[1022,1240,1241],{"class":1039},", type: ",[1022,1243,1244],{"class":1049},"'string'",[1022,1246,1247],{"class":1039}," },\n",[1022,1249,1250,1252,1255,1257,1259],{"class":1024,"line":1103},[1022,1251,1235],{"class":1039},[1022,1253,1254],{"class":1049},"'title'",[1022,1256,1241],{"class":1039},[1022,1258,1244],{"class":1049},[1022,1260,1247],{"class":1039},[1022,1262,1263,1265,1268,1270,1272],{"class":1024,"line":1112},[1022,1264,1235],{"class":1039},[1022,1266,1267],{"class":1049},"'content'",[1022,1269,1241],{"class":1039},[1022,1271,1244],{"class":1049},[1022,1273,1247],{"class":1039},[1022,1275,1276,1278,1281,1283,1285,1288,1291],{"class":1024,"line":1118},[1022,1277,1235],{"class":1039},[1022,1279,1280],{"class":1049},"'source'",[1022,1282,1241],{"class":1039},[1022,1284,1244],{"class":1049},[1022,1286,1287],{"class":1039},", facet: ",[1022,1289,1290],{"class":1074},"true",[1022,1292,1247],{"class":1039},[1022,1294,1296,1298,1301,1303,1305,1307,1309,1312,1314],{"class":1024,"line":1295},10,[1022,1297,1235],{"class":1039},[1022,1299,1300],{"class":1049},"'version'",[1022,1302,1241],{"class":1039},[1022,1304,1244],{"class":1049},[1022,1306,1287],{"class":1039},[1022,1308,1290],{"class":1074},[1022,1310,1311],{"class":1039},", optional: ",[1022,1313,1290],{"class":1074},[1022,1315,1247],{"class":1039},[1022,1317,1319,1321,1324,1326,1328,1330,1332],{"class":1024,"line":1318},11,[1022,1320,1235],{"class":1039},[1022,1322,1323],{"class":1049},"'locale'",[1022,1325,1241],{"class":1039},[1022,1327,1244],{"class":1049},[1022,1329,1287],{"class":1039},[1022,1331,1290],{"class":1074},[1022,1333,1334],{"class":1039}," }\n",[1022,1336,1338],{"class":1024,"line":1337},12,[1022,1339,1340],{"class":1039},"  ]\n",[1022,1342,1344],{"class":1024,"line":1343},13,[1022,1345,1346],{"class":1039},"};\n",[970,1348,1349,1350,1353],{},"Typed as ",[1003,1351,1352],{},"CollectionCreateSchema",", because step 4 hands this very object to\nTypesense to create the collection with.",[970,1355,1356,1359,1360,1362,1363,1365,1366,1369,1370,1373],{},[1003,1357,1358],{},"id"," is not in the list on purpose: Typesense already treats ",[1003,1361,1358],{}," as the\ndocument's primary key, and duxt's ",[1003,1364,1358],{}," is\n",[974,1367,1368],{"href":260},"a hex digest of the URL"," — valid as a key, identical on\nevery machine, and unchanged for as long as the page stays where it is. That\nis what lets the sync ",[979,1371,1372],{},"upsert"," instead of rebuild.",[970,1375,1376,1379,1380,1383,1384,1387,1388,1390],{},[1003,1377,1378],{},"version"," is ",[1003,1381,1382],{},"optional",", because a source with only one version carries none.\n",[1003,1385,1386],{},"source"," deliberately has the version stripped out of it, so a facet built on\nit survives a release and ",[1003,1389,1378],{}," beside it is what narrows to one.",[1139,1392,1393],{"start":1062},[1142,1394,1395,1398,1399,1402],{},[979,1396,1397],{},"Write the module that listens."," A Nuxt module in your own site is the\nwhole integration — ",[1003,1400,1401],{},"defineNuxtModule",", one hook, one import:",[1012,1404,1407],{"className":1014,"code":1405,"filename":1406,"language":1017,"meta":1018,"style":1018},"import { defineNuxtModule } from '@nuxt\u002Fkit';\nimport { Client } from 'typesense';\nimport type { DuxtSearchRecord } from '@kirchdev\u002Fduxt\u002Fsearch-records';\nimport { docs } from '..\u002Fserver\u002Ftypesense-schema';\n\nexport default defineNuxtModule({\n  meta: { name: 'typesense-sync' },\n  setup(_options, nuxt) {\n    const key = process.env.TYPESENSE_ADMIN_KEY;\n    \u002F\u002F No key is a local build, not a failure: skip rather than break it.\n    if (!key) return;\n\n    nuxt.hook('duxt:search:records', async (records) => {\n      const client = new Client({\n        nodes: [{ url: process.env.TYPESENSE_URL! }],\n        apiKey: key\n      });\n\n      await sync(client, records);\n    });\n  }\n});\n","modules\u002Ftypesense.ts",[1003,1408,1409,1423,1436,1452,1466,1470,1481,1491,1511,1528,1534,1553,1557,1588,1607,1621,1627,1633,1638,1650,1656,1661],{"__ignoreMap":1018},[1022,1410,1411,1413,1416,1418,1421],{"class":1024,"line":1025},[1022,1412,1173],{"class":1028},[1022,1414,1415],{"class":1039}," { defineNuxtModule } ",[1022,1417,1182],{"class":1028},[1022,1419,1420],{"class":1049}," '@nuxt\u002Fkit'",[1022,1422,1188],{"class":1039},[1022,1424,1425,1427,1430,1432,1434],{"class":1024,"line":1043},[1022,1426,1173],{"class":1028},[1022,1428,1429],{"class":1039}," { Client } ",[1022,1431,1182],{"class":1028},[1022,1433,1185],{"class":1049},[1022,1435,1188],{"class":1039},[1022,1437,1438,1440,1442,1445,1447,1450],{"class":1024,"line":1062},[1022,1439,1173],{"class":1028},[1022,1441,1176],{"class":1028},[1022,1443,1444],{"class":1039}," { DuxtSearchRecord } ",[1022,1446,1182],{"class":1028},[1022,1448,1449],{"class":1049}," '@kirchdev\u002Fduxt\u002Fsearch-records'",[1022,1451,1188],{"class":1039},[1022,1453,1454,1456,1459,1461,1464],{"class":1024,"line":1068},[1022,1455,1173],{"class":1028},[1022,1457,1458],{"class":1039}," { docs } ",[1022,1460,1182],{"class":1028},[1022,1462,1463],{"class":1049}," '..\u002Fserver\u002Ftypesense-schema'",[1022,1465,1188],{"class":1039},[1022,1467,1468],{"class":1024,"line":1081},[1022,1469,1194],{"emptyLinePlaceholder":1193},[1022,1471,1472,1474,1476,1479],{"class":1024,"line":1092},[1022,1473,1029],{"class":1028},[1022,1475,1032],{"class":1028},[1022,1477,1478],{"class":1035}," defineNuxtModule",[1022,1480,1040],{"class":1039},[1022,1482,1483,1486,1489],{"class":1024,"line":1103},[1022,1484,1485],{"class":1039},"  meta: { name: ",[1022,1487,1488],{"class":1049},"'typesense-sync'",[1022,1490,1247],{"class":1039},[1022,1492,1493,1496,1499,1503,1505,1508],{"class":1024,"line":1112},[1022,1494,1495],{"class":1035},"  setup",[1022,1497,1498],{"class":1039},"(",[1022,1500,1502],{"class":1501},"s4XuR","_options",[1022,1504,1053],{"class":1039},[1022,1506,1507],{"class":1501},"nuxt",[1022,1509,1510],{"class":1039},") {\n",[1022,1512,1513,1516,1519,1521,1524,1526],{"class":1024,"line":1118},[1022,1514,1515],{"class":1028},"    const",[1022,1517,1518],{"class":1074}," key",[1022,1520,1213],{"class":1028},[1022,1522,1523],{"class":1039}," process.env.",[1022,1525,1098],{"class":1074},[1022,1527,1188],{"class":1039},[1022,1529,1530],{"class":1024,"line":1295},[1022,1531,1533],{"class":1532},"sJ8bj","    \u002F\u002F No key is a local build, not a failure: skip rather than break it.\n",[1022,1535,1536,1539,1542,1545,1548,1551],{"class":1024,"line":1318},[1022,1537,1538],{"class":1028},"    if",[1022,1540,1541],{"class":1039}," (",[1022,1543,1544],{"class":1028},"!",[1022,1546,1547],{"class":1039},"key) ",[1022,1549,1550],{"class":1028},"return",[1022,1552,1188],{"class":1039},[1022,1554,1555],{"class":1024,"line":1337},[1022,1556,1194],{"emptyLinePlaceholder":1193},[1022,1558,1559,1562,1565,1567,1570,1572,1575,1577,1580,1583,1586],{"class":1024,"line":1343},[1022,1560,1561],{"class":1039},"    nuxt.",[1022,1563,1564],{"class":1035},"hook",[1022,1566,1498],{"class":1039},[1022,1568,1569],{"class":1049},"'duxt:search:records'",[1022,1571,1053],{"class":1039},[1022,1573,1574],{"class":1028},"async",[1022,1576,1541],{"class":1039},[1022,1578,1579],{"class":1501},"records",[1022,1581,1582],{"class":1039},") ",[1022,1584,1585],{"class":1028},"=>",[1022,1587,1216],{"class":1039},[1022,1589,1591,1594,1597,1599,1602,1605],{"class":1024,"line":1590},14,[1022,1592,1593],{"class":1028},"      const",[1022,1595,1596],{"class":1074}," client",[1022,1598,1213],{"class":1028},[1022,1600,1601],{"class":1028}," new",[1022,1603,1604],{"class":1035}," Client",[1022,1606,1040],{"class":1039},[1022,1608,1610,1613,1616,1618],{"class":1024,"line":1609},15,[1022,1611,1612],{"class":1039},"        nodes: [{ url: process.env.",[1022,1614,1615],{"class":1074},"TYPESENSE_URL",[1022,1617,1544],{"class":1028},[1022,1619,1620],{"class":1039}," }],\n",[1022,1622,1624],{"class":1024,"line":1623},16,[1022,1625,1626],{"class":1039},"        apiKey: key\n",[1022,1628,1630],{"class":1024,"line":1629},17,[1022,1631,1632],{"class":1039},"      });\n",[1022,1634,1636],{"class":1024,"line":1635},18,[1022,1637,1194],{"emptyLinePlaceholder":1193},[1022,1639,1641,1644,1647],{"class":1024,"line":1640},19,[1022,1642,1643],{"class":1028},"      await",[1022,1645,1646],{"class":1035}," sync",[1022,1648,1649],{"class":1039},"(client, records);\n",[1022,1651,1653],{"class":1024,"line":1652},20,[1022,1654,1655],{"class":1039},"    });\n",[1022,1657,1659],{"class":1024,"line":1658},21,[1022,1660,1115],{"class":1039},[1022,1662,1664],{"class":1024,"line":1663},22,[1022,1665,1666],{"class":1039},"});\n",[970,1668,1669,1670,1673],{},"The payload is ",[979,1671,1672],{},"frozen",". Map it into documents of your own — never rewrite\na record or sort the array in place, because every other listener is handed\nthe same objects.",[1139,1675,1676],{"start":1068},[1142,1677,1678,1681,1682,1686],{},[979,1679,1680],{},"Synchronise the whole set, and remove what is gone."," The hook hands over\nthe ",[1683,1684,1685],"em",{},"complete"," current record set on every build, so the set itself is the\ninstruction — anything the collection holds that is not in it has been\ndeleted, moved or renamed:",[1012,1688,1690],{"className":1014,"code":1689,"filename":1406,"language":1017,"meta":1018,"style":1018},"async function sync(client: Client, records: readonly DuxtSearchRecord[]) {\n  const collection = client.collections(docs.name);\n\n  \u002F\u002F Typesense creates nothing implicitly: importing into a collection\n  \u002F\u002F that does not exist fails outright, so the first build makes it.\n  if (!(await collection.exists())) await client.collections().create(docs);\n\n  await collection.documents().import(\n    records.map((record) => ({ ...record })),\n    { action: 'upsert' }\n  );\n\n  \u002F\u002F Everything the build did not hand over is no longer on the site.\n  const kept = new Set(records.map((record) => record.id));\n  const live = await collection.documents().export();\n\n  const stale = live\n    .split('\\n')\n    .filter(Boolean)\n    .map((line) => JSON.parse(line).id as string)\n    .filter((id) => !kept.has(id));\n\n  \u002F\u002F Delete in batches: every id goes into the filter string, and one\n  \u002F\u002F large rename would build one long enough for Typesense to reject.\n  for (let index = 0; index \u003C stale.length; index += 100) {\n    const batch = stale.slice(index, index + 100).join(',');\n    await collection.documents().delete({ filter_by: `id:[${batch}]` });\n  }\n}\n",[1003,1691,1692,1725,1744,1748,1753,1758,1796,1800,1817,1844,1854,1859,1863,1868,1898,1921,1925,1937,1958,1968,2001,2027,2031,2037,2042,2084,2121,2151,2156],{"__ignoreMap":1018},[1022,1693,1694,1696,1699,1701,1703,1706,1708,1710,1712,1714,1716,1719,1722],{"class":1024,"line":1025},[1022,1695,1574],{"class":1028},[1022,1697,1698],{"class":1028}," function",[1022,1700,1646],{"class":1035},[1022,1702,1498],{"class":1039},[1022,1704,1705],{"class":1501},"client",[1022,1707,1207],{"class":1028},[1022,1709,1604],{"class":1035},[1022,1711,1053],{"class":1039},[1022,1713,1579],{"class":1501},[1022,1715,1207],{"class":1028},[1022,1717,1718],{"class":1028}," readonly",[1022,1720,1721],{"class":1035}," DuxtSearchRecord",[1022,1723,1724],{"class":1039},"[]) {\n",[1022,1726,1727,1730,1733,1735,1738,1741],{"class":1024,"line":1043},[1022,1728,1729],{"class":1028},"  const",[1022,1731,1732],{"class":1074}," collection",[1022,1734,1213],{"class":1028},[1022,1736,1737],{"class":1039}," client.",[1022,1739,1740],{"class":1035},"collections",[1022,1742,1743],{"class":1039},"(docs.name);\n",[1022,1745,1746],{"class":1024,"line":1062},[1022,1747,1194],{"emptyLinePlaceholder":1193},[1022,1749,1750],{"class":1024,"line":1068},[1022,1751,1752],{"class":1532},"  \u002F\u002F Typesense creates nothing implicitly: importing into a collection\n",[1022,1754,1755],{"class":1024,"line":1081},[1022,1756,1757],{"class":1532},"  \u002F\u002F that does not exist fails outright, so the first build makes it.\n",[1022,1759,1760,1763,1765,1767,1769,1772,1775,1778,1781,1783,1785,1787,1790,1793],{"class":1024,"line":1092},[1022,1761,1762],{"class":1028},"  if",[1022,1764,1541],{"class":1039},[1022,1766,1544],{"class":1028},[1022,1768,1498],{"class":1039},[1022,1770,1771],{"class":1028},"await",[1022,1773,1774],{"class":1039}," collection.",[1022,1776,1777],{"class":1035},"exists",[1022,1779,1780],{"class":1039},"())) ",[1022,1782,1771],{"class":1028},[1022,1784,1737],{"class":1039},[1022,1786,1740],{"class":1035},[1022,1788,1789],{"class":1039},"().",[1022,1791,1792],{"class":1035},"create",[1022,1794,1795],{"class":1039},"(docs);\n",[1022,1797,1798],{"class":1024,"line":1103},[1022,1799,1194],{"emptyLinePlaceholder":1193},[1022,1801,1802,1805,1807,1810,1812,1814],{"class":1024,"line":1112},[1022,1803,1804],{"class":1028},"  await",[1022,1806,1774],{"class":1039},[1022,1808,1809],{"class":1035},"documents",[1022,1811,1789],{"class":1039},[1022,1813,1173],{"class":1035},[1022,1815,1816],{"class":1039},"(\n",[1022,1818,1819,1822,1825,1828,1831,1833,1835,1838,1841],{"class":1024,"line":1118},[1022,1820,1821],{"class":1039},"    records.",[1022,1823,1824],{"class":1035},"map",[1022,1826,1827],{"class":1039},"((",[1022,1829,1830],{"class":1501},"record",[1022,1832,1582],{"class":1039},[1022,1834,1585],{"class":1028},[1022,1836,1837],{"class":1039}," ({ ",[1022,1839,1840],{"class":1028},"...",[1022,1842,1843],{"class":1039},"record })),\n",[1022,1845,1846,1849,1852],{"class":1024,"line":1295},[1022,1847,1848],{"class":1039},"    { action: ",[1022,1850,1851],{"class":1049},"'upsert'",[1022,1853,1334],{"class":1039},[1022,1855,1856],{"class":1024,"line":1318},[1022,1857,1858],{"class":1039},"  );\n",[1022,1860,1861],{"class":1024,"line":1337},[1022,1862,1194],{"emptyLinePlaceholder":1193},[1022,1864,1865],{"class":1024,"line":1343},[1022,1866,1867],{"class":1532},"  \u002F\u002F Everything the build did not hand over is no longer on the site.\n",[1022,1869,1870,1872,1875,1877,1879,1882,1885,1887,1889,1891,1893,1895],{"class":1024,"line":1590},[1022,1871,1729],{"class":1028},[1022,1873,1874],{"class":1074}," kept",[1022,1876,1213],{"class":1028},[1022,1878,1601],{"class":1028},[1022,1880,1881],{"class":1035}," Set",[1022,1883,1884],{"class":1039},"(records.",[1022,1886,1824],{"class":1035},[1022,1888,1827],{"class":1039},[1022,1890,1830],{"class":1501},[1022,1892,1582],{"class":1039},[1022,1894,1585],{"class":1028},[1022,1896,1897],{"class":1039}," record.id));\n",[1022,1899,1900,1902,1905,1907,1910,1912,1914,1916,1918],{"class":1024,"line":1609},[1022,1901,1729],{"class":1028},[1022,1903,1904],{"class":1074}," live",[1022,1906,1213],{"class":1028},[1022,1908,1909],{"class":1028}," await",[1022,1911,1774],{"class":1039},[1022,1913,1809],{"class":1035},[1022,1915,1789],{"class":1039},[1022,1917,1029],{"class":1035},[1022,1919,1920],{"class":1039},"();\n",[1022,1922,1923],{"class":1024,"line":1623},[1022,1924,1194],{"emptyLinePlaceholder":1193},[1022,1926,1927,1929,1932,1934],{"class":1024,"line":1629},[1022,1928,1729],{"class":1028},[1022,1930,1931],{"class":1074}," stale",[1022,1933,1213],{"class":1028},[1022,1935,1936],{"class":1039}," live\n",[1022,1938,1939,1942,1945,1947,1950,1953,1955],{"class":1024,"line":1635},[1022,1940,1941],{"class":1039},"    .",[1022,1943,1944],{"class":1035},"split",[1022,1946,1498],{"class":1039},[1022,1948,1949],{"class":1049},"'",[1022,1951,1952],{"class":1074},"\\n",[1022,1954,1949],{"class":1049},[1022,1956,1957],{"class":1039},")\n",[1022,1959,1960,1962,1965],{"class":1024,"line":1640},[1022,1961,1941],{"class":1039},[1022,1963,1964],{"class":1035},"filter",[1022,1966,1967],{"class":1039},"(Boolean)\n",[1022,1969,1970,1972,1974,1976,1978,1980,1982,1985,1987,1990,1993,1996,1999],{"class":1024,"line":1652},[1022,1971,1941],{"class":1039},[1022,1973,1824],{"class":1035},[1022,1975,1827],{"class":1039},[1022,1977,1024],{"class":1501},[1022,1979,1582],{"class":1039},[1022,1981,1585],{"class":1028},[1022,1983,1984],{"class":1074}," JSON",[1022,1986,993],{"class":1039},[1022,1988,1989],{"class":1035},"parse",[1022,1991,1992],{"class":1039},"(line).id ",[1022,1994,1995],{"class":1028},"as",[1022,1997,1998],{"class":1074}," string",[1022,2000,1957],{"class":1039},[1022,2002,2003,2005,2007,2009,2011,2013,2015,2018,2021,2024],{"class":1024,"line":1658},[1022,2004,1941],{"class":1039},[1022,2006,1964],{"class":1035},[1022,2008,1827],{"class":1039},[1022,2010,1358],{"class":1501},[1022,2012,1582],{"class":1039},[1022,2014,1585],{"class":1028},[1022,2016,2017],{"class":1028}," !",[1022,2019,2020],{"class":1039},"kept.",[1022,2022,2023],{"class":1035},"has",[1022,2025,2026],{"class":1039},"(id));\n",[1022,2028,2029],{"class":1024,"line":1663},[1022,2030,1194],{"emptyLinePlaceholder":1193},[1022,2032,2034],{"class":1024,"line":2033},23,[1022,2035,2036],{"class":1532},"  \u002F\u002F Delete in batches: every id goes into the filter string, and one\n",[1022,2038,2039],{"class":1024,"line":944},[1022,2040,2041],{"class":1532},"  \u002F\u002F large rename would build one long enough for Typesense to reject.\n",[1022,2043,2045,2048,2050,2053,2056,2059,2062,2065,2068,2071,2074,2076,2079,2082],{"class":1024,"line":2044},25,[1022,2046,2047],{"class":1028},"  for",[1022,2049,1541],{"class":1039},[1022,2051,2052],{"class":1028},"let",[1022,2054,2055],{"class":1039}," index ",[1022,2057,2058],{"class":1028},"=",[1022,2060,2061],{"class":1074}," 0",[1022,2063,2064],{"class":1039},"; index ",[1022,2066,2067],{"class":1028},"\u003C",[1022,2069,2070],{"class":1039}," stale.",[1022,2072,2073],{"class":1074},"length",[1022,2075,2064],{"class":1039},[1022,2077,2078],{"class":1028},"+=",[1022,2080,2081],{"class":1074}," 100",[1022,2083,1510],{"class":1039},[1022,2085,2087,2089,2092,2094,2096,2099,2102,2105,2107,2110,2113,2115,2118],{"class":1024,"line":2086},26,[1022,2088,1515],{"class":1028},[1022,2090,2091],{"class":1074}," batch",[1022,2093,1213],{"class":1028},[1022,2095,2070],{"class":1039},[1022,2097,2098],{"class":1035},"slice",[1022,2100,2101],{"class":1039},"(index, index ",[1022,2103,2104],{"class":1028},"+",[1022,2106,2081],{"class":1074},[1022,2108,2109],{"class":1039},").",[1022,2111,2112],{"class":1035},"join",[1022,2114,1498],{"class":1039},[1022,2116,2117],{"class":1049},"','",[1022,2119,2120],{"class":1039},");\n",[1022,2122,2124,2127,2129,2131,2133,2136,2139,2142,2145,2148],{"class":1024,"line":2123},27,[1022,2125,2126],{"class":1028},"    await",[1022,2128,1774],{"class":1039},[1022,2130,1809],{"class":1035},[1022,2132,1789],{"class":1039},[1022,2134,2135],{"class":1035},"delete",[1022,2137,2138],{"class":1039},"({ filter_by: ",[1022,2140,2141],{"class":1049},"`id:[${",[1022,2143,2144],{"class":1039},"batch",[1022,2146,2147],{"class":1049},"}]`",[1022,2149,2150],{"class":1039}," });\n",[1022,2152,2154],{"class":1024,"line":2153},28,[1022,2155,1115],{"class":1039},[1022,2157,2159],{"class":1024,"line":2158},29,[1022,2160,2161],{"class":1039},"}\n",[970,2163,2164,2165,2168],{},"The collection is created on the first run and left alone afterwards, and\nthe stale ids are deleted ",[979,2166,2167],{},"in batches"," — Typesense takes the filter as one\nstring, so a rename that moves a whole source would otherwise build one it\nrejects.",[983,2170,2173],{"title":2171,"type":2172},"Or swap an alias instead","tip",[970,2174,2175,2176,2179],{},"Import into a collection named for the build, then point a Typesense\n",[979,2177,2178],{},"alias"," at it and drop the previous one. Each build creates its own\ncollection, so neither the existence check nor the batched delete is needed,\nand readers never see a half-written index — at the cost of reindexing\neverything on every build rather than only what moved.",[1139,2181,2182],{"start":1081},[1142,2183,2184,2187,2188,2191],{},[979,2185,2186],{},"Search from the browser with a search-only key."," The admin key above signs\nwrites and must never reach a page. Issue a ",[979,2189,2190],{},"scoped, search-only"," key for\nthe client, and filter on the facets the schema declared:",[1012,2193,2195],{"className":1014,"code":2194,"language":1017,"meta":1018,"style":1018},"\u002F\u002F `locale` is the language the CONTENT is in, not the interface language.\n\u002F\u002F `version` is absent on an unversioned source, so the clause is added\n\u002F\u002F only when there is one — pasted in flat, it filters on `undefined`.\nconst filters = [`locale:${locale}`];\nif (version) filters.push(`version:${version}`);\n\nconst results = await client.collections('docs').documents().search({\n  q: query,\n  query_by: 'title,content',\n  filter_by: filters.join(' && ')\n});\n",[1003,2196,2197,2202,2207,2212,2237,2259,2263,2293,2298,2308,2322],{"__ignoreMap":1018},[1022,2198,2199],{"class":1024,"line":1025},[1022,2200,2201],{"class":1532},"\u002F\u002F `locale` is the language the CONTENT is in, not the interface language.\n",[1022,2203,2204],{"class":1024,"line":1043},[1022,2205,2206],{"class":1532},"\u002F\u002F `version` is absent on an unversioned source, so the clause is added\n",[1022,2208,2209],{"class":1024,"line":1062},[1022,2210,2211],{"class":1532},"\u002F\u002F only when there is one — pasted in flat, it filters on `undefined`.\n",[1022,2213,2214,2217,2220,2222,2225,2228,2231,2234],{"class":1024,"line":1068},[1022,2215,2216],{"class":1028},"const",[1022,2218,2219],{"class":1074}," filters",[1022,2221,1213],{"class":1028},[1022,2223,2224],{"class":1039}," [",[1022,2226,2227],{"class":1049},"`locale:${",[1022,2229,2230],{"class":1039},"locale",[1022,2232,2233],{"class":1049},"}`",[1022,2235,2236],{"class":1039},"];\n",[1022,2238,2239,2242,2245,2248,2250,2253,2255,2257],{"class":1024,"line":1081},[1022,2240,2241],{"class":1028},"if",[1022,2243,2244],{"class":1039}," (version) filters.",[1022,2246,2247],{"class":1035},"push",[1022,2249,1498],{"class":1039},[1022,2251,2252],{"class":1049},"`version:${",[1022,2254,1378],{"class":1039},[1022,2256,2233],{"class":1049},[1022,2258,2120],{"class":1039},[1022,2260,2261],{"class":1024,"line":1092},[1022,2262,1194],{"emptyLinePlaceholder":1193},[1022,2264,2265,2267,2270,2272,2274,2276,2278,2280,2282,2284,2286,2288,2291],{"class":1024,"line":1103},[1022,2266,2216],{"class":1028},[1022,2268,2269],{"class":1074}," results",[1022,2271,1213],{"class":1028},[1022,2273,1909],{"class":1028},[1022,2275,1737],{"class":1039},[1022,2277,1740],{"class":1035},[1022,2279,1498],{"class":1039},[1022,2281,1087],{"class":1049},[1022,2283,2109],{"class":1039},[1022,2285,1809],{"class":1035},[1022,2287,1789],{"class":1039},[1022,2289,2290],{"class":1035},"search",[1022,2292,1040],{"class":1039},[1022,2294,2295],{"class":1024,"line":1112},[1022,2296,2297],{"class":1039},"  q: query,\n",[1022,2299,2300,2303,2306],{"class":1024,"line":1118},[1022,2301,2302],{"class":1039},"  query_by: ",[1022,2304,2305],{"class":1049},"'title,content'",[1022,2307,1078],{"class":1039},[1022,2309,2310,2313,2315,2317,2320],{"class":1024,"line":1295},[1022,2311,2312],{"class":1039},"  filter_by: filters.",[1022,2314,2112],{"class":1035},[1022,2316,1498],{"class":1039},[1022,2318,2319],{"class":1049},"' && '",[1022,2321,1957],{"class":1039},[1022,2323,2324],{"class":1024,"line":1318},[1022,2325,1666],{"class":1039},[1139,2327,2328],{"start":1092},[1142,2329,2330,2333,2334,2337],{},[979,2331,2332],{},"Check one build end to end."," Run a build with the key set, and confirm the\ncollection holds a record for a page in ",[979,2335,2336],{},"every"," source, version and\nlanguage the site serves — not only the default one. The first build creates\nthe collection; every build after it upserts into the same one.",[995,2339,2341],{"id":2340},"what-the-records-already-settle-for-you","What the records already settle for you",[970,2343,2344,2345,2348],{},"Four properties of the payload are what make a sync this short correct at all,\nand all four are ",[974,2346,2347],{"href":260},"the hook's contract"," rather than this\nguide's advice:",[2350,2351,2352,2366],"table",{},[2353,2354,2355],"thead",{},[2356,2357,2358,2363],"tr",{},[2359,2360,2362],"th",{"align":2361},"left","Property",[2359,2364,2365],{"align":2361},"What it buys the sync",[2367,2368,2369,2386,2397,2405],"tbody",{},[2356,2370,2371,2380],{},[2372,2373,2374,2376,2377],"td",{"align":2361},[1003,2375,1358],{}," is derived from ",[1003,2378,2379],{},"url",[2372,2381,2382,2383,2385],{"align":2361},"A stable primary key, so ",[1003,2384,1372],{}," is enough and a rebuild is never needed",[2356,2387,2388,2394],{},[2372,2389,2390,2391,2393],{"align":2361},"The payload is the ",[979,2392,1685],{}," set",[2372,2395,2396],{"align":2361},"Removal is a diff against one build, with no crawl and no bookkeeping",[2356,2398,2399,2402],{},[2372,2400,2401],{"align":2361},"duxt does not fire on an empty parse",[2372,2403,2404],{"align":2361},"A build that parsed nothing can never tell you to empty the index",[2356,2406,2407,2410],{},[2372,2408,2409],{"align":2361},"Order is deterministic",[2372,2411,2412],{"align":2361},"Two builds differ exactly where the site did",[970,2414,2415,2416,2419],{},"A page that wrote ",[1003,2417,2418],{},"search: false",", and a translation in a language the site does\nnot route, produce no records — so neither reaches Typesense.",[995,2421,2423],{"id":2422},"making-it-a-package","Making it a package",[970,2425,2426,2427,2430,2431,2434],{},"The module above is ~40 lines and belongs to one site. Once a second site needs\nit, the way to share it is ",[979,2428,2429],{},"a Nuxt layer",", not a plugin: a layer carries the\nmodule, its ",[1003,2432,2433],{},"app.config"," defaults and its components in one versioned package,\nand a consumer adds it beside duxt.",[1012,2436,2438],{"className":1014,"code":2437,"filename":1016,"language":1017,"meta":1018,"style":1018},"export default defineNuxtConfig({\n  extends: ['@kirchdev\u002Fduxt', 'duxt-typesense']\n});\n",[1003,2439,2440,2450,2464],{"__ignoreMap":1018},[1022,2441,2442,2444,2446,2448],{"class":1024,"line":1025},[1022,2443,1029],{"class":1028},[1022,2445,1032],{"class":1028},[1022,2447,1036],{"class":1035},[1022,2449,1040],{"class":1039},[1022,2451,2452,2454,2456,2458,2461],{"class":1024,"line":1043},[1022,2453,1046],{"class":1039},[1022,2455,1050],{"class":1049},[1022,2457,1053],{"class":1039},[1022,2459,2460],{"class":1049},"'duxt-typesense'",[1022,2462,2463],{"class":1039},"]\n",[1022,2465,2466],{"class":1024,"line":1062},[1022,2467,1666],{"class":1039},[970,2469,2470,2471,993],{},"That layer owns the credentials, the service configuration, the sync policy and\nthe browser-side search UI. duxt itself gains none of them —\n",[974,2472,2473],{"href":260},"which is the whole reason the hook is shaped the way it is",[995,2475,2477],{"id":2476},"checklist","Checklist",[2479,2480,2483,2496,2502,2515,2525,2531],"ul",{"className":2481},[2482],"contains-task-list",[1142,2484,2487,2491,2492,2495],{"className":2485},[2486],"task-list-item",[2488,2489],"input",{"disabled":1193,"type":2490},"checkbox"," The client is a dependency of ",[979,2493,2494],{},"your"," site, not of the layer",[1142,2497,2499,2501],{"className":2498},[2486],[2488,2500],{"disabled":1193,"type":2490}," The admin key lives in the build environment and never reaches a page",[1142,2503,2505,2507,2508,1053,2510,2512,2513],{"className":2504},[2486],[2488,2506],{"disabled":1193,"type":2490}," The collection is created on the first build, and facets ",[1003,2509,1386],{},[1003,2511,1378],{}," and ",[1003,2514,2230],{},[1142,2516,2518,2520,2521,2524],{"className":2517},[2486],[2488,2519],{"disabled":1193,"type":2490}," Records no longer handed over are removed — by a ",[979,2522,2523],{},"batched"," diff, or by an alias swap",[1142,2526,2528,2530],{"className":2527},[2486],[2488,2529],{"disabled":1193,"type":2490}," A build without the key skips the sync instead of failing",[1142,2532,2534,2536],{"className":2533},[2486],[2488,2535],{"disabled":1193,"type":2490}," Every source, version and language is represented in the collection",[2538,2539,2540],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":1018,"searchDepth":1043,"depth":1081,"links":2542},[2543,2544,2545,2546,2547],{"id":997,"depth":1043,"text":998},{"id":1135,"depth":1043,"text":368},{"id":2340,"depth":1043,"text":2341},{"id":2422,"depth":1043,"text":2423},{"id":2476,"depth":1043,"text":2477},"md",{},"---\ntitle: Typesense\ndescription: Consume duxt's one build hook into a Typesense collection — every source, version and language, upserted by a stable id.\nicon: lucide:search\nredirectFrom:\n  - \u002Fguides\u002Fsend-your-pages-to-typesense\n---\n\nduxt emits [one build-time hook](\u002Freference\u002Fhooks), and it hands over every page\nof every source, version and language as flat records. A site that already runs\n**Typesense** turns those records into a collection of its own — without\nre-crawling the rendered site, and without reimplementing duxt's source, version\nand locale logic.\n\n::callout{type=\"info\" title=\"The service is yours, not duxt's\"}\nduxt ships no Typesense SDK, credentials or service configuration. The optional companion layer owns that integration; you own the service and its keys. Without a provider or a custom listener, duxt [builds no payload at all](\u002Freference\u002Fhooks).\n::\n\n## Use the companion layer\n\nFor the packaged integration, install `@kirchdev\u002Fduxt-typesense` and extend it after duxt. It synchronizes the complete set through a staging collection and alias swap, removes the previous managed collection, and connects the existing search dialog with a search-only key. The steps below remain a recipe for custom synchronization.\n\n::package-managers{command=\"add @kirchdev\u002Fduxt-typesense\"}\n::\n\n```ts [nuxt.config.ts]\nexport default defineNuxtConfig({\n  extends: ['@kirchdev\u002Fduxt', '@kirchdev\u002Fduxt-typesense'],\n  duxtTypesense: {\n    endpoint: process.env.TYPESENSE_ENDPOINT,\n    collection: 'docs',\n    adminKey: process.env.TYPESENSE_ADMIN_KEY,\n    searchKey: process.env.TYPESENSE_SEARCH_KEY\n  }\n})\n```\n\nKeep the admin key in build-only configuration. `searchKey` must have only `documents:search` for this alias, and Typesense must allow browser requests from your site.\n\n## Steps\n\n::steps\n\n1. **Install the client in your site.** It is a build-time dependency: the sync\n   runs in Node during `nuxt build`, never in the browser.\n\n   ::package-managers{command=\"add -D typesense\"}\n   ::\n\n2. **Declare the collection.** Every field a duxt record carries maps onto one\n   Typesense field, and the two provenance fields are what a reader filters by:\n\n   ```ts [server\u002Ftypesense-schema.ts]\n   import type { CollectionCreateSchema } from 'typesense';\n\n   export const docs: CollectionCreateSchema = {\n     name: 'docs',\n     fields: [\n       { name: 'url', type: 'string' },\n       { name: 'title', type: 'string' },\n       { name: 'content', type: 'string' },\n       { name: 'source', type: 'string', facet: true },\n       { name: 'version', type: 'string', facet: true, optional: true },\n       { name: 'locale', type: 'string', facet: true }\n     ]\n   };\n   ```\n\n   Typed as `CollectionCreateSchema`, because step 4 hands this very object to\n   Typesense to create the collection with.\n\n   `id` is not in the list on purpose: Typesense already treats `id` as the\n   document's primary key, and duxt's `id` is\n   [a hex digest of the URL](\u002Freference\u002Fhooks) — valid as a key, identical on\n   every machine, and unchanged for as long as the page stays where it is. That\n   is what lets the sync **upsert** instead of rebuild.\n\n   `version` is `optional`, because a source with only one version carries none.\n   `source` deliberately has the version stripped out of it, so a facet built on\n   it survives a release and `version` beside it is what narrows to one.\n\n3. **Write the module that listens.** A Nuxt module in your own site is the\n   whole integration — `defineNuxtModule`, one hook, one import:\n\n   ```ts [modules\u002Ftypesense.ts]\n   import { defineNuxtModule } from '@nuxt\u002Fkit';\n   import { Client } from 'typesense';\n   import type { DuxtSearchRecord } from '@kirchdev\u002Fduxt\u002Fsearch-records';\n   import { docs } from '..\u002Fserver\u002Ftypesense-schema';\n\n   export default defineNuxtModule({\n     meta: { name: 'typesense-sync' },\n     setup(_options, nuxt) {\n       const key = process.env.TYPESENSE_ADMIN_KEY;\n       \u002F\u002F No key is a local build, not a failure: skip rather than break it.\n       if (!key) return;\n\n       nuxt.hook('duxt:search:records', async (records) => {\n         const client = new Client({\n           nodes: [{ url: process.env.TYPESENSE_URL! }],\n           apiKey: key\n         });\n\n         await sync(client, records);\n       });\n     }\n   });\n   ```\n\n   The payload is **frozen**. Map it into documents of your own — never rewrite\n   a record or sort the array in place, because every other listener is handed\n   the same objects.\n\n4. **Synchronise the whole set, and remove what is gone.** The hook hands over\n   the *complete* current record set on every build, so the set itself is the\n   instruction — anything the collection holds that is not in it has been\n   deleted, moved or renamed:\n\n   ```ts [modules\u002Ftypesense.ts]\n   async function sync(client: Client, records: readonly DuxtSearchRecord[]) {\n     const collection = client.collections(docs.name);\n\n     \u002F\u002F Typesense creates nothing implicitly: importing into a collection\n     \u002F\u002F that does not exist fails outright, so the first build makes it.\n     if (!(await collection.exists())) await client.collections().create(docs);\n\n     await collection.documents().import(\n       records.map((record) => ({ ...record })),\n       { action: 'upsert' }\n     );\n\n     \u002F\u002F Everything the build did not hand over is no longer on the site.\n     const kept = new Set(records.map((record) => record.id));\n     const live = await collection.documents().export();\n\n     const stale = live\n       .split('\\n')\n       .filter(Boolean)\n       .map((line) => JSON.parse(line).id as string)\n       .filter((id) => !kept.has(id));\n\n     \u002F\u002F Delete in batches: every id goes into the filter string, and one\n     \u002F\u002F large rename would build one long enough for Typesense to reject.\n     for (let index = 0; index \u003C stale.length; index += 100) {\n       const batch = stale.slice(index, index + 100).join(',');\n       await collection.documents().delete({ filter_by: `id:[${batch}]` });\n     }\n   }\n   ```\n\n   The collection is created on the first run and left alone afterwards, and\n   the stale ids are deleted **in batches** — Typesense takes the filter as one\n   string, so a rename that moves a whole source would otherwise build one it\n   rejects.\n\n   ::callout{type=\"tip\" title=\"Or swap an alias instead\"}\n   Import into a collection named for the build, then point a Typesense\n   **alias** at it and drop the previous one. Each build creates its own\n   collection, so neither the existence check nor the batched delete is needed,\n   and readers never see a half-written index — at the cost of reindexing\n   everything on every build rather than only what moved.\n   ::\n\n5. **Search from the browser with a search-only key.** The admin key above signs\n   writes and must never reach a page. Issue a **scoped, search-only** key for\n   the client, and filter on the facets the schema declared:\n\n   ```ts\n   \u002F\u002F `locale` is the language the CONTENT is in, not the interface language.\n   \u002F\u002F `version` is absent on an unversioned source, so the clause is added\n   \u002F\u002F only when there is one — pasted in flat, it filters on `undefined`.\n   const filters = [`locale:${locale}`];\n   if (version) filters.push(`version:${version}`);\n\n   const results = await client.collections('docs').documents().search({\n     q: query,\n     query_by: 'title,content',\n     filter_by: filters.join(' && ')\n   });\n   ```\n\n6. **Check one build end to end.** Run a build with the key set, and confirm the\n   collection holds a record for a page in **every** source, version and\n   language the site serves — not only the default one. The first build creates\n   the collection; every build after it upserts into the same one.\n\n::\n\n## What the records already settle for you\n\nFour properties of the payload are what make a sync this short correct at all,\nand all four are [the hook's contract](\u002Freference\u002Fhooks) rather than this\nguide's advice:\n\n| Property | What it buys the sync |\n| :--- | :--- |\n| `id` is derived from `url` | A stable primary key, so `upsert` is enough and a rebuild is never needed |\n| The payload is the **complete** set | Removal is a diff against one build, with no crawl and no bookkeeping |\n| duxt does not fire on an empty parse | A build that parsed nothing can never tell you to empty the index |\n| Order is deterministic | Two builds differ exactly where the site did |\n\nA page that wrote `search: false`, and a translation in a language the site does\nnot route, produce no records — so neither reaches Typesense.\n\n## Making it a package\n\nThe module above is ~40 lines and belongs to one site. Once a second site needs\nit, the way to share it is **a Nuxt layer**, not a plugin: a layer carries the\nmodule, its `app.config` defaults and its components in one versioned package,\nand a consumer adds it beside duxt.\n\n```ts [nuxt.config.ts]\nexport default defineNuxtConfig({\n  extends: ['@kirchdev\u002Fduxt', 'duxt-typesense']\n});\n```\n\nThat layer owns the credentials, the service configuration, the sync policy and\nthe browser-side search UI. duxt itself gains none of them —\n[which is the whole reason the hook is shaped the way it is](\u002Freference\u002Fhooks).\n\n## Checklist\n\n- [ ] The client is a dependency of **your** site, not of the layer\n- [ ] The admin key lives in the build environment and never reaches a page\n- [ ] The collection is created on the first build, and facets `source`, `version` and `locale`\n- [ ] Records no longer handed over are removed — by a **batched** diff, or by an alias swap\n- [ ] A build without the key skips the sync instead of failing\n- [ ] Every source, version and language is represented in the collection\n",[2552],"\u002Fguides\u002Fsend-your-pages-to-typesense",{"title":835,"description":838},{"loc":836},"tjZA3XNjnfeTwksvrFa7v-J137dUWumYFDVYI17ILEc","en-GB","en-US",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2559},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Crect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"\u002F>\u003Cpath d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"\u002F>\u003C\u002Fg>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2561},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m6 9l6 6l6-6\"\u002F>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2563},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 5.88L14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88M7 10v12\"\u002F>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2565},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M9 18.12L10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22a3.13 3.13 0 0 1-3-3.88M17 14V2\"\u002F>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2567},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.12 2.12 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.12 2.12 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.12 2.12 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.12 2.12 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.12 2.12 0 0 0 1.597-1.16z\"\u002F>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2569},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cpath d=\"M12 8v4m0 4h.01\"\u002F>\u003C\u002Fg>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2571},"\u003Cpath fill=\"currentColor\" d=\"M20.317 4.37a19.8 19.8 0 0 0-4.885-1.515a.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.3 18.3 0 0 0-5.487 0a13 13 0 0 0-.617-1.25a.08.08 0 0 0-.079-.037A19.7 19.7 0 0 0 3.677 4.37a.1.1 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.08.08 0 0 0 .031.057a19.9 19.9 0 0 0 5.993 3.03a.08.08 0 0 0 .084-.028a14 14 0 0 0 1.226-1.994a.076.076 0 0 0-.041-.106a13 13 0 0 1-1.872-.892a.077.077 0 0 1-.008-.128a10 10 0 0 0 .372-.292a.07.07 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.07.07 0 0 1 .078.01q.181.149.373.292a.077.077 0 0 1-.006.127a12.3 12.3 0 0 1-1.873.892a.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.08.08 0 0 0 .084.028a19.8 19.8 0 0 0 6.002-3.03a.08.08 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.06.06 0 0 0-.031-.03M8.02 15.33c-1.182 0-2.157-1.085-2.157-2.419c0-1.333.956-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.956 2.418-2.157 2.418m7.975 0c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.955-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.946 2.418-2.157 2.418\"\u002F>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2573},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 5v16m4-8h2m-2-4h2m2.001 10A2 2 0 0 0 22 17V5a2 2 0 0 0-1.999-2L16 3.002A5 5 0 0 0 12 5a5 5 0 0 0-4-2H4a2 2 0 0 0-2 2v12a2 2 0 0 0 1.999 2H8a5 5 0 0 1 4 2a5 5 0 0 1 4-2zM6 13h2M6 9h2\"\u002F>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2575},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M7 7h10v10M7 17L17 7\"\u002F>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2577,"hidden":1193},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4\"\u002F>\u003Cpath d=\"M14 2v4a2 2 0 0 0 2 2h4M5 12l-3 3l3 3m4 0l3-3l-3-3\"\u002F>\u003C\u002Fg>",[2579,2580,2581,2582,2583,2584,2585,2586],"\u002Fv0.8.1\u002Fadd-ons\u002Ftypesense","\u002Fv0.7.0\u002Fadd-ons\u002Ftypesense","\u002Fv0.6.0\u002Fadd-ons\u002Ftypesense","\u002Fv0.5.0\u002Fadd-ons\u002Ftypesense","\u002Fv0.4.0\u002Fadd-ons\u002Ftypesense","\u002Fv0.3.4\u002Fadd-ons\u002Ftypesense","\u002Fv0.2.0\u002Fadd-ons\u002Ftypesense","\u002Fv0.1.0\u002Fadd-ons\u002Ftypesense",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2588},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 5h16M4 12h16M4 19h16\"\u002F>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2590},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M10 8h.01M12 12h.01M14 8h.01M16 12h.01M18 8h.01M6 8h.01M7 16h10m-9-4h.01\"\u002F>\u003Crect width=\"20\" height=\"16\" x=\"2\" y=\"4\" rx=\"2\"\u002F>\u003C\u002Fg>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2592},"\u003Cpath fill=\"currentColor\" d=\"M12 .297c-6.63 0-12 5.373-12 12c0 5.303 3.438 9.8 8.205 11.385c.6.113.82-.258.82-.577c0-.285-.01-1.04-.015-2.04c-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729c1.205.084 1.838 1.236 1.838 1.236c1.07 1.835 2.809 1.305 3.495.998c.108-.776.417-1.305.76-1.605c-2.665-.3-5.466-1.332-5.466-5.93c0-1.31.465-2.38 1.235-3.22c-.135-.303-.54-1.523.105-3.176c0 0 1.005-.322 3.3 1.23c.96-.267 1.98-.399 3-.405c1.02.006 2.04.138 3 .405c2.28-1.552 3.285-1.23 3.285-1.23c.645 1.653.24 2.873.12 3.176c.765.84 1.23 1.91 1.23 3.22c0 4.61-2.805 5.625-5.475 5.92c.42.36.81 1.096.81 2.22c0 1.606-.015 2.896-.015 3.286c0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12\"\u002F>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2594},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\"\u002F>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2596},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cpath d=\"M12 16v-4m0-4h.01\"\u002F>\u003C\u002Fg>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2598},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15 14c.2-1 .7-1.7 1.5-2.5c1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5c.7.7 1.3 1.5 1.5 2.5m0 4h6m-5 4h4\"\u002F>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2600},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m12 19l-7-7l7-7m7 7H5\"\u002F>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2602},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 12h14m-7-7l7 7l-7 7\"\u002F>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2604},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m9 18l6-6l-6-6\"\u002F>",{"left":943,"top":943,"width":2606,"height":2607,"rotate":943,"vFlip":945,"hFlip":945,"body":2608},640,480,"\u003Cpath fill=\"#bd3d44\" d=\"M0 0h640v480H0\"\u002F>\u003Cpath stroke=\"#fff\" stroke-width=\"37\" d=\"M0 55.3h640M0 129h640M0 203h640M0 277h640M0 351h640M0 425h640\"\u002F>\u003Cpath fill=\"#192f5d\" d=\"M0 0h364.8v258.5H0\"\u002F>\u003Cmarker id=\"SVGEq3dreKJ\" markerHeight=\"30\" markerWidth=\"30\">\u003Cpath fill=\"#fff\" d=\"m14 0l9 27L0 10h28L5 27z\"\u002F>\u003C\u002Fmarker>\u003Cpath fill=\"none\" marker-mid=\"url(#SVGEq3dreKJ)\" d=\"m0 0l16 11h61h61h61h61h60L47 37h61h61h60h61L16 63h61h61h61h61h60L47 89h61h61h60h61L16 115h61h61h61h61h60L47 141h61h61h60h61L16 166h61h61h61h61h60L47 192h61h61h60h61L16 218h61h61h61h61h60z\"\u002F>",{"pnpm":2610,"npm":2611,"yarn":2612,"bun":2613},"\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">pnpm\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> add\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> @kirchdev\u002Fduxt-typesense\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">npm\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> install\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> @kirchdev\u002Fduxt-typesense\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">yarn\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> add\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> @kirchdev\u002Fduxt-typesense\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">bun\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> add\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> @kirchdev\u002Fduxt-typesense\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",{"left":943,"top":943,"width":2615,"height":2615,"rotate":943,"vFlip":945,"hFlip":945,"body":2616},32,"\u003Cpath fill=\"#f9ad00\" d=\"M30 10.75h-8.749V2H30Zm-9.626 0h-8.75V2h8.75Zm-9.625 0H2V2h8.749ZM30 20.375h-8.749v-8.75H30Z\"\u002F>\u003Cpath fill=\"#4e4e4e\" d=\"M20.374 20.375h-8.75v-8.75h8.75Zm0 9.625h-8.75v-8.75h8.75ZM30 30h-8.749v-8.75H30Zm-19.251 0H2v-8.75h8.749Z\"\u002F>",{"left":943,"top":943,"width":2615,"height":2615,"rotate":943,"vFlip":945,"hFlip":945,"body":2618},"\u003Cpath fill=\"#f9ad00\" d=\"M30 10.75h-8.749V2H30Zm-9.626 0h-8.75V2h8.75Zm-9.625 0H2V2h8.749ZM30 20.375h-8.749v-8.75H30Z\"\u002F>\u003Cpath fill=\"#fff\" d=\"M20.374 20.375h-8.75v-8.75h8.75Zm0 9.625h-8.75v-8.75h8.75ZM30 30h-8.749v-8.75H30Zm-19.251 0H2v-8.75h8.749Z\"\u002F>",{"left":943,"top":943,"width":2615,"height":2615,"rotate":943,"vFlip":945,"hFlip":945,"body":2620},"\u003Cpath fill=\"#c12127\" d=\"M2 2h28v28H2\"\u002F>\u003Cpath fill=\"#fff\" d=\"M7.25 7.25h17.5v17.5h-3.5v-14H16v14H7.25\"\u002F>",{"left":943,"top":943,"width":2615,"height":2615,"rotate":943,"vFlip":945,"hFlip":945,"body":2622},"\u003Cpath fill=\"#2188b6\" d=\"M28.208 24.409a10.5 10.5 0 0 0-3.959 1.822a23.7 23.7 0 0 1-5.835 2.642a1.63 1.63 0 0 1-.983.55a62 62 0 0 1-6.447.577c-1.163.009-1.876-.3-2.074-.776a1.573 1.573 0 0 1 .866-2.074a4 4 0 0 1-.514-.379c-.171-.171-.352-.514-.406-.388c-.225.55-.343 1.894-.947 2.5c-.83.839-2.4.559-3.328.072c-1.019-.541.072-1.813.072-1.813a.73.73 0 0 1-.992-.343a4.85 4.85 0 0 1-.667-2.949a5.37 5.37 0 0 1 1.749-2.895a9.3 9.3 0 0 1 .658-4.4a10.45 10.45 0 0 1 3.165-3.661S6.628 10.747 7.35 8.817c.469-1.262.658-1.253.812-1.308a3.6 3.6 0 0 0 1.452-.857a5.27 5.27 0 0 1 4.41-1.7S15.2 1.4 16.277 2.09a18.4 18.4 0 0 1 1.533 2.886s1.281-.748 1.425-.469a11.33 11.33 0 0 1 .523 6.132a14 14 0 0 1-2.6 5.411c-.135.225 1.551.938 2.615 3.887c.983 2.7.108 4.96.262 5.212c.027.045.036.063.036.063s1.127.09 3.391-1.308a8.5 8.5 0 0 1 4.277-1.604a1.081 1.081 0 0 1 .469 2.11Z\"\u002F>",{"left":943,"top":943,"width":2615,"height":2615,"rotate":943,"vFlip":945,"hFlip":945,"body":2624},"\u003Cpath fill=\"#fbf0df\" d=\"M29 17c0 5.65-5.82 10.23-13 10.23S3 22.61 3 17c0-3.5 2.24-6.6 5.66-8.44S14.21 4.81 16 4.81s3.32 1.54 7.34 3.71C26.76 10.36 29 13.46 29 17\"\u002F>\u003Cpath fill=\"none\" stroke=\"#000\" d=\"M16 27.65c7.32 0 13.46-4.65 13.46-10.65c0-3.72-2.37-7-5.89-8.85c-1.39-.75-2.46-1.41-3.37-2l-1.13-.69A6.14 6.14 0 0 0 16 4.35a6.9 6.9 0 0 0-3.3 1.23c-.42.24-.86.51-1.32.8c-.87.54-1.83 1.13-3 1.73C4.91 10 2.54 13.24 2.54 17c0 6 6.14 10.65 13.46 10.65Z\"\u002F>\u003Cellipse cx=\"21.65\" cy=\"18.62\" fill=\"#febbd0\" rx=\"2.17\" ry=\"1.28\"\u002F>\u003Cellipse cx=\"10.41\" cy=\"18.62\" fill=\"#febbd0\" rx=\"2.17\" ry=\"1.28\"\u002F>\u003Cpath fill-rule=\"evenodd\" d=\"M11.43 18.11a2 2 0 1 0-2-2.05a2.05 2.05 0 0 0 2 2.05m9.2 0a2 2 0 1 0-2-2.05a2 2 0 0 0 2 2.05\"\u002F>\u003Cpath fill=\"#fff\" fill-rule=\"evenodd\" d=\"M10.79 16.19a.77.77 0 1 0-.76-.77a.76.76 0 0 0 .76.77m9.2 0a.77.77 0 1 0 0-1.53a.77.77 0 0 0 0 1.53\"\u002F>\u003Cpath fill=\"#b71422\" stroke=\"#000\" stroke-width=\".75\" d=\"M18.62 19.67a3.3 3.3 0 0 1-1.09 1.75a2.48 2.48 0 0 1-1.5.69a2.53 2.53 0 0 1-1.5-.69a3.28 3.28 0 0 1-1.08-1.75a.26.26 0 0 1 .29-.3h4.58a.27.27 0 0 1 .3.3Z\"\u002F>\u003Cpath fill=\"#ccbea7\" fill-rule=\"evenodd\" d=\"M14.93 5.75a6.1 6.1 0 0 1-2.09 4.62c-.1.09 0 .27.11.22c1.25-.49 2.94-1.94 2.23-4.88c-.03-.15-.25-.11-.25.04m.85 0a6 6 0 0 1 .57 5c0 .13.12.24.21.13c.83-1 1.54-3.11-.59-5.31c-.1-.11-.27.04-.19.17Zm1-.06a6.1 6.1 0 0 1 2.53 4.38c0 .14.21.17.24 0c.34-1.3.15-3.51-2.66-4.66c-.12-.02-.21.18-.09.27ZM9.94 9.55a6.27 6.27 0 0 0 3.89-3.33c.07-.13.28-.08.25.07c-.64 3-2.79 3.59-4.13 3.51c-.14-.01-.14-.21-.01-.25\"\u002F>",{"pnpm":2626,"npm":2627,"yarn":2628,"bun":2629},"\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">pnpm\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> add\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> -D\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> typesense\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">npm\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> install\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> -D\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> typesense\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">yarn\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> add\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> -D\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> typesense\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>","\u003Cpre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">bun\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> add\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> -D\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> typesense\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",1792683286181]