[{"data":1,"prerenderedAt":2638},["ShallowReactive",2],{"duxt-navigation-docs-docs_de":3,"i-lucide:puzzle":942,"i-lucide:search":947,"i-simple-icons:meilisearch":949,"docs-de-DE-\u002Fadd-ons\u002Ftypesense":951,"duxt-preferred-missing-\u002Fadd-ons\u002Ftypesense":945,"i-lucide:rocket":2554,"i-lucide:compass":2556,"i-lucide:book-open":2558,"i-lucide:list":2560,"i-lucide:ruler":2562,"i-lucide:gavel":2564,"i-lucide:copy":2566,"i-lucide:chevron-down":2568,"i-lucide:thumbs-up":2570,"i-lucide:thumbs-down":2572,"i-lucide:star":2574,"i-lucide:circle-alert":2576,"i-simple-icons:discord":2578,"i-lucide:book-open-text":2580,"i-lucide:arrow-up-right":2582,"i-lucide:file-code-2":2584,"duxt-code-ts-export default defineNuxtConfig({\n  extends: ['@kirchdev\u002Fduxt', 'duxt-typesense']\n});\n":13,"i-lucide:info":2586,"i-lucide:lightbulb":2588,"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 Kein Schlüssel ist ein lokaler Build, kein Fehler: überspringen,\n    \u002F\u002F statt ihn zu brechen.\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 legt nichts von selbst an: ein Import in eine Collection,\n  \u002F\u002F die es nicht gibt, schlägt fehl — der erste Build legt sie also an.\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 Alles, was der Build nicht übergeben hat, steht nicht mehr auf der Seite.\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 Stapelweise löschen: jede id landet im Filter-String, und eine\n  \u002F\u002F einzige große Umbenennung baute einen, den Typesense ablehnt.\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` ist die Sprache des INHALTS, nicht die Oberflächensprache.\n\u002F\u002F `version` fehlt bei einer Quelle ohne Versionen — die Klausel kommt nur\n\u002F\u002F dann dazu; fest eingebaut filterte sie auf `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,"i-lucide:arrow-left":2590,"i-lucide:arrow-right":2592,"i-lucide:chevron-right":2594,"duxt-version-missing-\u002Fadd-ons\u002Ftypesense":2596,"i-lucide:menu":2605,"i-lucide:keyboard":2607,"i-simple-icons:github":2609,"i-lucide:moon":2611,"package-managers-add @kirchdev\u002Fduxt-typesense":2613,"i-vscode-icons:file-type-light-pnpm":2618,"i-vscode-icons:file-type-pnpm":2621,"i-vscode-icons:file-type-npm":2623,"i-vscode-icons:file-type-yarn":2625,"i-vscode-icons:file-type-bun":2627,"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":2629,"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,"i-flag:de-4x3":2634},[4,31,111,183,826,845,853,878],{"title":5,"path":6,"stem":7,"children":8,"description":12},"Einführung","\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","Was duxt ist, und was mit einer einzigen Konfigurationszeile ankommt.",null,{"title":15,"path":16,"stem":17,"icon":18,"description":19,"subcategory":13},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F1.installation","lucide:download","Ebene einbinden, erweitern, Markdown schreiben.",{"title":21,"path":22,"stem":23,"icon":24,"description":25,"subcategory":13},"Konfiguration","\u002Fgetting-started\u002Fconfiguration","1.getting-started\u002F2.configuration","lucide:settings","Eine Datei konfiguriert die ganze Seite — was hineingehört, und wie sie zusammengeführt wird.",{"title":27,"path":28,"stem":29,"icon":11,"description":30,"subcategory":13},"Mit dem Starter beginnen","\u002Fgetting-started\u002Ffrom-starter","1.getting-started\u002F3.from-starter","Erstelle mit Nuxi eine sofort lauffähige duxt-Dokumentationsseite.",{"title":32,"path":33,"stem":34,"children":35,"description":39},"Konzepte","\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","Wie die Ebene funktioniert — das Quellenmodell, das URL-Schema, die Collections und die Prüfungen.",{"title":41,"path":42,"stem":43,"icon":44,"description":45,"subcategory":13},"Ebenen und Überschreiben","\u002Fconcepts\u002Flayers","2.concepts\u002F1.layers","lucide:layers","Was eine Nuxt-Ebene dir gibt, was sie dir nimmt, und welche Pfade nicht so auflösen, wie sie sich lesen.",{"title":47,"path":48,"stem":49,"icon":50,"description":51,"subcategory":13},"Theming","\u002Fconcepts\u002Ftheming","2.concepts\u002F10.theming","lucide:palette","Wie das Theme gebaut ist — eigene Komponenten, eine Token-Ebene und ein Dark Mode, der über eine Klasse schaltet.",{"title":53,"path":54,"stem":55,"icon":56,"description":57,"subcategory":13},"Datenbanken","\u002Fconcepts\u002Fdatabases","2.concepts\u002F11.databases","lucide:database","Auf welchen Content-Datenbank-Adaptern eine duxt-Website laufen kann, welche davon geprüft sind und die eine Regel, die die Ebene aus dem Weg hält.",{"title":59,"path":60,"stem":61,"icon":62,"description":63,"subcategory":13},"Tastenkürzel","\u002Fconcepts\u002Fkeyboard-shortcuts","2.concepts\u002F12.keyboard-shortcuts","lucide:keyboard","Die vier Tasten, die das Theme belegt, wo jede davon gilt, und wo die Lesende davon erfährt.",{"title":65,"path":66,"stem":67,"icon":68,"description":69,"subcategory":13},"Quellen","\u002Fconcepts\u002Fsources","2.concepts\u002F2.sources","lucide:git-branch","Eine Liste von Quellen wird zu jeder Collection, jedem Präfix und jeder Version, die die Seite ausliefert.",{"title":71,"path":72,"stem":73,"icon":74,"description":75,"subcategory":13},"URLs und Versionen","\u002Fconcepts\u002Furls-and-versions","2.concepts\u002F3.urls-and-versions","lucide:git-compare","Wie die Repository- und Versionssegmente erscheinen, und was einem Leser in einer alten Version gesagt wird.",{"title":77,"path":78,"stem":79,"icon":56,"description":80,"subcategory":13},"Collections","\u002Fconcepts\u002Fcollections","2.concepts\u002F4.collections","Was Content aus den Quellen baut, und die vier Dinge, die das Schema hinzufügt.",{"title":82,"path":83,"stem":84,"icon":85,"description":86,"subcategory":13},"Generierte Sektionen","\u002Fconcepts\u002Fgenerated-sections","2.concepts\u002F5.generated-sections","lucide:file-cog","Ein Artefakt plus ein Typ, als Seiten veröffentlicht — was die Registry ist, und welche zwei Richtlinien ein Typ beantwortet.",{"title":88,"path":89,"stem":90,"icon":91,"description":92,"subcategory":13},"Was der Build prüft","\u002Fconcepts\u002Fbuild-checks","2.concepts\u002F6.build-checks","lucide:shield-check","Die stillen Fehlschläge dieser Ebene, in Meldungen verwandelt.",{"title":94,"path":95,"stem":96,"icon":97,"description":98,"subcategory":13},"Maschinelle Leser","\u002Fconcepts\u002Fmachine-readers","2.concepts\u002F7.machine-readers","lucide:bot","Was ein Modell bekommt — llms.txt, das rohe Markdown jeder Seite und ein echter MCP-Server.",{"title":100,"path":101,"stem":102,"icon":103,"description":104,"subcategory":13},"SEO","\u002Fconcepts\u002Fseo","2.concepts\u002F8.seo","lucide:search","Was jede Seite für Crawler und Social Cards ausgibt, welches Modul es schreibt, und der eine Wert, den die Ebene nicht erraten kann.",{"title":106,"path":107,"stem":108,"icon":109,"description":110,"subcategory":13},"Lokalisierung","\u002Fconcepts\u002Flocalisation","2.concepts\u002F9.localisation","lucide:languages","Sieben Locales bringt die Ebene mit, und jede konfigurierte Zeichenkette hat drei Formen.",{"title":112,"path":113,"stem":114,"children":115,"description":119},"Anleitungen","\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","Eine Aufgabe je Seite, von vorn bis hinten — mehrere Repositories, mehrere Versionen, mehrere Sprachen und ein Deployment.",{"title":121,"path":122,"stem":123,"icon":124,"description":125,"subcategory":13},"Mehrere Repositories","\u002Fguides\u002Fseveral-repositories","3.guides\u002F1.several-repositories","lucide:folder-git","Die Dokumentation mehrerer Projekte von einer Seite ausliefern.",{"title":127,"path":128,"stem":129,"icon":130,"description":131,"subcategory":13},"Terraform-Provider-Dokumentation veröffentlichen","\u002Fguides\u002Fpublish-terraform-provider-docs","3.guides\u002F10.publish-terraform-provider-docs","simple-icons:terraform","Einen tfplugindocs-Markdown-Baum als versionierte Provider-Referenz mit passender Navigation veröffentlichen.",{"title":133,"path":134,"stem":135,"icon":136,"description":137,"subcategory":13},"Remote-Quellen und OG-Bilder cachen","\u002Fguides\u002Fcache-build-work","3.guides\u002F11.cache-build-work","lucide:database-zap","Öffentliche Repository-Downloads und gerenderte Social Cards sicher zwischen CI-Builds wiederverwenden.",{"title":139,"path":140,"stem":141,"icon":74,"description":142,"subcategory":13},"Mehrere Versionen","\u002Fguides\u002Fseveral-versions","3.guides\u002F2.several-versions","Dieselbe Dokumentation an mehreren Refs ausliefern, mit Umschalter und Banner.",{"title":144,"path":145,"stem":146,"icon":109,"description":147,"subcategory":13},"Mehrere Sprachen","\u002Fguides\u002Fseveral-languages","3.guides\u002F3.several-languages","Die Oberfläche in mehreren Sprachen ausliefern — und die Seiten selbst übersetzen.",{"title":149,"path":150,"stem":151,"icon":50,"description":152,"subcategory":13},"Das Theme überschreiben","\u002Fguides\u002Foverride-the-theme","3.guides\u002F4.override-the-theme","Eine Farbe ändern, eine Komponente ersetzen, ein shadcn-vue-Primitiv hinzufügen.",{"title":154,"path":155,"stem":156,"icon":157,"description":158,"subcategory":13},"Eine Seite verschieben","\u002Fguides\u002Fmove-a-page","3.guides\u002F5.move-a-page","lucide:signpost","redirectFrom im Frontmatter, in Routenregeln unter jedem Präfix übersetzt.",{"title":160,"path":161,"stem":162,"icon":163,"description":164,"subcategory":13},"Eine Seite ausliefern","\u002Fguides\u002Fdeploy-a-site","3.guides\u002F6.deploy-a-site","lucide:cloud-upload","Wo eine duxt-Seite laufen kann, was sie dort braucht, und warum Inhalte nicht zur Laufzeit aufgefrischt werden.",{"title":166,"path":167,"stem":168,"icon":169,"description":170,"subcategory":13},"Seiten-Feedback sammeln","\u002Fguides\u002Fcollect-page-feedback","3.guides\u002F7.collect-page-feedback","lucide:thumbs-up","DuxtPageFeedback umhüllen und die Antwort dort behalten, wo deine Analytik ohnehin liegt.",{"title":172,"path":173,"stem":174,"icon":175,"description":176,"subcategory":13},"Deiner Website eine Marke geben","\u002Fguides\u002Fbrand-your-site","3.guides\u002F8.brand-your-site","lucide:badge-check","Name, Wortmarke und Icons setzen, damit die Website als deine gelesen wird und nicht als die der Ebene.",{"title":178,"path":179,"stem":180,"icon":181,"description":182,"subcategory":13},"Analytik-Ereignisse senden","\u002Fguides\u002Fsend-analytics-events","3.guides\u002F9.send-analytics-events","lucide:chart-line","Ein Callback, fünf Ereignisse, kein Anbieter — verdrahte duxts Leserinteraktionen mit der Analytik, die du ohnehin betreibst.",{"title":184,"path":185,"stem":186,"children":187,"description":191},"Referenz","\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","Die öffentliche Oberfläche der Ebene — Konfigurationsschlüssel, Frontmatter, Komponenten, Composables und Endpunkte.",{"title":21,"path":193,"stem":194,"icon":24,"description":195,"subcategory":13},"\u002Freference\u002Fconfiguration","4.reference\u002F1.configuration","Jeder Schlüssel unter duxt in app.config.ts — was er steuert, und wann er gelesen wird.",{"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","Ein Release-Log, als Seiten veröffentlicht — eine Zeitleiste, eine Seite pro Release, und ein Feed.",{"title":205,"path":206,"stem":207,"icon":208,"description":209,"subcategory":13},"Die Sektion deklarieren","\u002Freference\u002Fchangelog\u002Fsection","4.reference\u002F10.changelog\u002F1.section","lucide:file-clock","Der Sektionstyp `changelog` — wo die Datei liegt, und welche zwei Richtlinien er beantwortet.",{"title":211,"path":212,"stem":213,"icon":214,"description":215,"subcategory":13},"Granularität","\u002Freference\u002Fchangelog\u002Fgranularity","4.reference\u002F10.changelog\u002F2.granularity","lucide:split","Eine Seite pro Release, oder die Datei als die eine Seite, als die sie geschrieben wurde.",{"title":217,"path":218,"stem":219,"icon":220,"description":221,"subcategory":13},"Was gelesen wird","\u002Freference\u002Fchangelog\u002Fwhat-is-read","4.reference\u002F10.changelog\u002F3.what-is-read","lucide:scan-text","Welche Überschriften zu Releases werden, welche zu Gruppen, und was mit dem Rest passiert.",{"title":223,"path":224,"stem":225,"icon":226,"description":227,"subcategory":13},"Layout und Komponenten","\u002Freference\u002Fchangelog\u002Fcomponents","4.reference\u002F10.changelog\u002F4.components","lucide:box","Das Layout, in dem eine getrennte Historie rendert, und die zwei MDC-Komponenten, aus denen ihre Seiten bestehen.",{"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","Eine Bruno-Collection als request-zentrierte Referenz mit herunterladbarem Archiv.",{"title":205,"path":237,"stem":238,"icon":239,"description":240,"subcategory":13},"\u002Freference\u002Fbruno\u002Fsection","4.reference\u002F11.bruno\u002F1.section","lucide:file-code","Wo eine Bruno-Collection liegt, welche Seiten sie erzeugt und welche Optionen gelten.",{"title":242,"path":243,"stem":244,"icon":245,"description":246,"subcategory":13},"Was veröffentlicht wird","\u002Freference\u002Fbruno\u002Fwhat-is-published","4.reference\u002F11.bruno\u002F2.what-is-published","lucide:shield","Environments, Zugangsdaten, Scripts und Tests erreichen keine Seite.",{"title":248,"path":249,"stem":250,"icon":251,"description":252,"subcategory":13},"Der Request-Client","\u002Freference\u002Fbruno\u002Ftry-it","4.reference\u002F11.bruno\u002F3.try-it","lucide:send-horizontal","Standardmäßig aus und nur auf ausdrücklich öffentliche Ziele gerichtet.",{"title":254,"path":255,"stem":256,"icon":18,"description":257,"subcategory":13},"Die Collection beziehen","\u002Freference\u002Fbruno\u002Fgetting-the-collection","4.reference\u002F11.bruno\u002F4.getting-the-collection","Das Archiv ist an Version und Sprache der Seite gebunden; der Bruno-Link nicht.",{"title":259,"path":260,"stem":261,"icon":262,"description":263,"subcategory":13},"Hooks","\u002Freference\u002Fhooks","4.reference\u002F12.hooks","lucide:plug","Der eine Build-Hook, den duxt aussendet, was er übergibt und warum es nur einen gibt.",{"title":65,"path":265,"stem":266,"icon":68,"description":267,"subcategory":13},"\u002Freference\u002Fsources","4.reference\u002F2.sources","Die Felder eines Quelleneintrags, seine Refs, und die Optionen, die die URLs formen.",{"title":269,"path":270,"stem":271,"icon":239,"description":272,"subcategory":13},"Frontmatter","\u002Freference\u002Ffrontmatter","4.reference\u002F3.frontmatter","Die Felder, die eine Seite über Titel und Beschreibung hinaus tragen darf, und die zwei, die der Build füllt.",{"title":274,"path":275,"stem":276,"children":277,"icon":279,"description":280,"subcategory":13},"MDC-Komponenten","\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","Die Blöcke, die eine Markdown-Seite aufrufen kann, je eine Seite, mit ihren 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","Ein Einschub, an dem der Leser innehalten soll — ein Tipp, eine Warnung, eine Gefahr.",{"title":288,"path":289,"stem":290,"icon":291,"description":292,"subcategory":13},"Paketmanager","\u002Freference\u002Fmdc-components\u002Fpackage-managers","4.reference\u002F4.mdc-components\u002F10.package-managers","lucide:package","Ein Befehl, ein Tab je Paketmanager, über Seiten hinweg gemerkt.",{"title":294,"path":295,"stem":296,"icon":297,"description":298,"subcategory":13},"Dateibaum","\u002Freference\u002Fmdc-components\u002Ffile-tree","4.reference\u002F4.mdc-components\u002F11.file-tree","lucide:folder-tree","Eine Ordnerstruktur, mit Icons je Dateityp.",{"title":300,"path":301,"stem":302,"icon":303,"description":304,"subcategory":13},"Vorschau","\u002Freference\u002Fmdc-components\u002Fpreview","4.reference\u002F4.mdc-components\u002F12.preview","lucide:eye","Eine Komponente, so gerendert, wie die Seite sie rendert, mit ihrem Quelltext daneben.",{"title":306,"path":307,"stem":308,"icon":309,"description":310,"subcategory":13},"Seitenkarten","\u002Freference\u002Fmdc-components\u002Fpage-cards","4.reference\u002F4.mdc-components\u002F13.page-cards","lucide:layout-grid","Die Kinder einer Sektion, als Karten.",{"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","Ein Block, einmal geschrieben und in jeder Quelle gerendert, die ihn braucht.",{"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","Die Version, in der etwas kam, neben einer Überschrift.",{"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","Ein Diagramm aus einem Fence oder einem 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","Was die Ebene an schlichtem Markdown ändert — Links, Überschriften, Bilder, Code und Tabellen.",{"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","Ein Link, aufgelöst gegen die Quelle, in der er geschrieben wurde.",{"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","Überschriften, jede mit einem Permalink-Anker.",{"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","Ein Bild: Theme-bewusst, responsiv und zoombar.",{"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","Der Code-Block: Dateiname, Sprach-Icon, Kopier-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","Eine Tabelle, die scrollt statt der Seite.",{"title":368,"path":369,"stem":370,"icon":371,"description":372,"subcategory":13},"Schritte","\u002Freference\u002Fmdc-components\u002Fsteps","4.reference\u002F4.mdc-components\u002F2.steps","lucide:list-ordered","Eine geordnete Liste, gezeichnet als nummerierte Schritte an einer Schiene.",{"title":374,"path":375,"stem":376,"icon":239,"description":377,"subcategory":13},"Code-Gruppe","\u002Freference\u002Fmdc-components\u002Fcode-group","4.reference\u002F4.mdc-components\u002F3.code-group","Mehrere Fences als ein Block mit Tabs, beschriftet mit dem Dateinamen.",{"title":379,"path":380,"stem":381,"icon":382,"description":383,"subcategory":13},"Tab-Gruppe","\u002Freference\u002Fmdc-components\u002Ftab-group","4.reference\u002F4.mdc-components\u002F4.tab-group","lucide:panels-top-left","Tabs für alles, was kein Code ist.",{"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","Ein Panel einer Tab-Gruppe.",{"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","Aufklappbare Abschnitte — eine FAQ, oder Antworten, aus denen ein Leser wählt.",{"title":397,"path":398,"stem":399,"icon":400,"description":401,"subcategory":13},"Accordion-Element","\u002Freference\u002Fmdc-components\u002Faccordion-item","4.reference\u002F4.mdc-components\u002F7.accordion-item","lucide:chevron-down","Ein aufklappbarer Abschnitt.",{"title":403,"path":404,"stem":405,"icon":406,"description":407,"subcategory":13},"Feldgruppe","\u002Freference\u002Fmdc-components\u002Ffield-group","4.reference\u002F4.mdc-components\u002F8.field-group","lucide:list-tree","Eine Liste von Feldern als ein Block.",{"title":409,"path":410,"stem":411,"icon":202,"description":412,"subcategory":13},"Feld","\u002Freference\u002Fmdc-components\u002Ffield","4.reference\u002F4.mdc-components\u002F9.field","Ein Parameter, eine Eigenschaft oder eine Option, mit Typ und Standard.",{"title":414,"path":415,"stem":416,"children":417,"icon":419,"description":420,"subcategory":13},"Komponenten","\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","Die eigenen Komponenten der Ebene, je eine Seite — wofür jede da ist, und was sie nimmt.",{"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","Die zwei Komponenten, die eine Seite rahmen — die Navigationsleiste und der Fußbereich.",{"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","Die Navbar: Titel, Navigation, Suche und die 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","Der Fußbereich: der Name der Seite, ihre rechtlichen Links und die eigene Zeile der Ebene.",{"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","Site-eigene Hinweise, je Platzierung nur gezeichnet, wenn es etwas zu sagen gibt.",{"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},"Sich zurechtfinden — die Sektionszeile, die Seitenleiste, die Spur, das Inhaltsverzeichnis und vor\u002Fzurück.",{"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","Die zweite Navigationszeile — die obersten Teile der Dokumentation.",{"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","Der Baum der Seitenleiste.",{"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","Ein Eintrag der Seitenleiste.",{"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","Die Spur über dem Seitentitel.",{"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","Das Inhaltsverzeichnis und der Nebenbereich darunter.",{"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","Zurück und weiter, begrenzt durch die Sektion.",{"title":489,"path":490,"stem":491,"children":492,"icon":494,"description":495,"subcategory":13},"Bedienelemente","\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","Was ein Leser bedient — die Suche, die Umschalter, die Tastenkürzel-Übersicht und zwei Anzeigen.",{"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","Jede aktive Quelle durchsuchen und ihre lokal bewerteten Ergebnisse verschränken.",{"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","Das Versions-Abzeichen, und der Umschalter, wenn es mehr als eine gibt.",{"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","Der Balken, der einem Leser sagt, dass diese Version nicht die aktuelle ist.",{"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","Der Sprachumschalter.",{"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","Wie weit unten auf der Seite der Leser ist.",{"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","Die Übersicht der Tastenkürzel, auf ?.",{"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","Das erste fokussierbare Element auf der Seite.",{"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","Der Button, der die Übersicht der Tastenkürzel öffnet.",{"title":540,"path":541,"stem":542,"children":543,"icon":545,"description":546,"subcategory":13},"Seite","\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","Die Komponenten, die zur Seite selbst gehören.",{"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","Woher die Seite kommt: Bearbeiten-Link, letzte Änderung, Mitwirkende.",{"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","Diese Seite an ein Modell übergeben — oder ihre Quelle lesen.",{"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","„War diese Seite hilfreich?“ — ein Ereignis, und kein Backend.",{"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","Die Karte um einen Codeblock.",{"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","Die Funktionen, die die Ebene deinen eigenen Komponenten offenlegt, je eine Seite.",{"title":579,"path":580,"stem":581,"children":582,"icon":56,"description":584,"subcategory":13},"Konfiguration und Inhalt","\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},"Die zusammengeführte Konfiguration, und welche Collection die gerade gelesene Seite ausliefert.",{"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","Die zusammengeführte Konfiguration, jedes Textfeld bereits aufgelöst.",{"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","Welche Collection diese Route bedient.",{"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","Der Navigationsbaum der Collection, die diese Route bedient.",{"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","Der Teil der Dokumentation, in dem diese Seite liegt.",{"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","Die Spur von der Sektion hinunter zu einer Seite.",{"title":613,"path":614,"stem":615,"children":616,"icon":618,"description":619,"subcategory":13},"Pfade und Versionen","\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","Eine URL lesen, eine zurückschreiben, und wissen, welche Version gerade gelesen wird.",{"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","Der Pfad, unter dem die Dokumentation liegt, ohne Locale-Segment.",{"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","Ein Dokumentationspfad, wieder als Link ausgeschrieben.",{"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","Was der Umschalter zeigt, was das Banner sagt, ob indexiert wird.",{"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","Der konfigurierte Ursprung, und Pfade absolut gemacht.",{"title":642,"path":643,"stem":644,"children":645,"icon":118,"description":647,"subcategory":13},"Leseerlebnis","\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},"Suche, Überschriften, Fokus, Verlauf und die Entscheidungen, die ein Leser trifft.",{"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","Tippfehlertoleranz neben dem exakten 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","Die Überschrift, die gerade im Blick ist.",{"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","Setzt den Fokus nach einer clientseitigen Navigation auf die Überschrift.",{"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","Die zuletzt geöffneten Seiten bis zum konfigurierten 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","Der Paketmanager, den ein Leser gewählt hat.",{"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","Benachrichtigungen, gekapselt, damit keine Komponente die Bibliothek importiert.",{"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","Die Tasten, auf die das Theme hört.",{"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","Eine Leserinteraktion an das eigene Callback der Seite melden — oder an niemanden.",{"title":697,"path":698,"stem":699,"children":700,"icon":618,"description":702,"subcategory":13},"Endpunkte","\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},"Alles, was die Seite außer Seiten ausliefert, je eine Seite.",{"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","Die Dokumentation als Markdown-Index, nach 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","Eine duxt-Erweiterung mit denselben Seiten in einer Markdown-Datei.",{"title":715,"path":716,"stem":717,"icon":239,"description":718,"subcategory":13},"\u003Cseite>.md","\u002Freference\u002Fendpoints\u002Fpage-markdown","4.reference\u002F7.endpoints\u002F3.page-markdown","Der Quelltext jeder Seite, unter ihrer eigenen 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","Ein MCP-Server über denselben Inhalten.",{"title":725,"path":726,"stem":727,"icon":103,"description":728,"subcategory":13},"\u002Fsitemap.xml und \u002Frobots.txt","\u002Freference\u002Fendpoints\u002Fsitemap-and-robots","4.reference\u002F7.endpoints\u002F5.sitemap-and-robots","Worauf ein Crawler gezeigt wird, und wovon er ferngehalten wird.",{"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","Der Feed, sobald eine Sektion benannt ist.",{"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","Die Route, unter der das Nuxt-Devtools-Panel ausgeliefert wird. Nur im Dev-Server.",{"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},"Zehn Panels, die zeigen, was aus deinen Quellen geworden ist. Nur im Dev-Modus.",{"title":65,"path":749,"stem":750,"icon":594,"description":751,"subcategory":13},"\u002Freference\u002Fdevtools\u002Fsources","4.reference\u002F8.devtools\u002F1.sources","Was aus `duxt.sources` geworden ist — eine Collection je Quelle, Version und Sprache.",{"title":753,"path":754,"stem":755,"icon":157,"description":756,"subcategory":13},"Weiterleitungen","\u002Freference\u002Fdevtools\u002Fredirects","4.reference\u002F8.devtools\u002F10.redirects","Jeder Redirect, den der Server ausliefert, und welche davon die Ebene geschrieben hat.",{"title":758,"path":759,"stem":760,"icon":618,"description":761,"subcategory":13},"Pfade","\u002Freference\u002Fdevtools\u002Fpaths","4.reference\u002F8.devtools\u002F2.paths","URL einfügen und sehen, welche Quelle sie beansprucht und was sie dort findet.",{"title":763,"path":764,"stem":765,"icon":766,"description":767,"subcategory":13},"Seiten","\u002Freference\u002Fdevtools\u002Fpages","4.reference\u002F8.devtools\u002F3.pages","lucide:files","Jede Seite jeder Collection, mit ihrem Frontmatter und ihren Git-Metadaten.",{"title":769,"path":770,"stem":771,"icon":772,"description":773,"subcategory":13},"Versionen","\u002Freference\u002Fdevtools\u002Fversions","4.reference\u002F8.devtools\u002F4.versions","lucide:columns-3","Welche Version — und welche Sprache — trägt welche Seite.",{"title":775,"path":776,"stem":777,"icon":778,"description":779,"subcategory":13},"Prüfungen","\u002Freference\u002Fdevtools\u002Fchecks","4.reference\u002F8.devtools\u002F5.checks","lucide:check-check","Der Build-Validator, ausgeführt gegen das, was die Seite gerade ausliefert.",{"title":781,"path":782,"stem":783,"icon":103,"description":784,"subcategory":13},"Suche","\u002Freference\u002Fdevtools\u002Fsearch","4.reference\u002F8.devtools\u002F6.search","Was der Suchindex hält, durch dieselbe Abfrage, die der Dialog ausführt.",{"title":786,"path":787,"stem":788,"icon":494,"description":789,"subcategory":13},"Config","\u002Freference\u002Fdevtools\u002Fconfig","4.reference\u002F8.devtools\u002F7.config","Die zusammengeführte `duxt`-Config, und von welcher Seite der Zusammenführung jeder Wert kam.",{"title":791,"path":792,"stem":793,"icon":109,"description":794,"subcategory":13},"i18n","\u002Freference\u002Fdevtools\u002Fi18n","4.reference\u002F8.devtools\u002F8.i18n","Message-Keys pro Locale, gegen die Basissprache.",{"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","Der Download-Cache von Content und ein Weg, einen Eintrag zu verwerfen.",{"title":802,"path":803,"stem":804,"children":805,"icon":262,"description":807,"subcategory":13},"API-Referenz","\u002Freference\u002Fopenapi","4.reference\u002F9.openapi\u002Findex",[806,808,812,816,821],{"title":802,"path":803,"stem":804,"icon":262,"description":807,"subcategory":13},"Ein OpenAPI-Dokument, veröffentlicht als Referenzseiten mit einem Client, der echte Anfragen sendet.",{"title":205,"path":809,"stem":810,"icon":239,"description":811,"subcategory":13},"\u002Freference\u002Fopenapi\u002Fsection","4.reference\u002F9.openapi\u002F1.section","Der Sektionstyp `openapi` — wo das Dokument liegt, und was daraus wird.",{"title":414,"path":813,"stem":814,"icon":226,"description":815,"subcategory":13},"\u002Freference\u002Fopenapi\u002Fcomponents","4.reference\u002F9.openapi\u002F2.components","Die drei MDC-Komponenten, aus denen eine generierte Referenzseite besteht.",{"title":817,"path":818,"stem":819,"icon":234,"description":820,"subcategory":13},"Der Try-it-Client","\u002Freference\u002Fopenapi\u002Ftry-it","4.reference\u002F9.openapi\u002F3.try-it","Eine echte Anfrage, gesendet vom Browser des Lesers.",{"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","Dieselbe Anfrage in zwölf Clients, und wie du eigene hinzufügst.",{"title":827,"path":828,"stem":829,"children":830,"description":833},"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","Begleit-Layer, die eine duxt-Site erweitern — jede ein eigenes Paket, eingebunden mit einem weiteren Eintrag in extends.",{"title":835,"path":836,"stem":837,"icon":103,"description":838,"subcategory":13},"Typesense","\u002Fadd-ons\u002Ftypesense","5.add-ons\u002F1.typesense","duxts einen Build-Hook in eine Typesense-Collection überführen — jede Quelle, jede Version und jede Sprache, per stabiler ID aktualisiert.",{"title":840,"path":841,"stem":842,"icon":843,"description":844,"subcategory":13},"Meilisearch","\u002Fadd-ons\u002Fmeilisearch","5.add-ons\u002F2.meilisearch","simple-icons:meilisearch","Ergänze die offizielle Companion-Layer für atomare Indizierung beim Build und optionale Browsersuche.",{"title":846,"path":847,"stem":848,"children":849,"icon":851,"description":852,"subcategory":13},"Danksagungen","\u002Fcredits","6.credits\u002Findex",[850],{"title":846,"path":847,"stem":848,"icon":851,"description":852,"subcategory":13},"lucide:heart","Worauf duxt aufbaut, und wem es nachempfunden ist.",{"title":854,"path":855,"stem":856,"children":857,"description":861},"Konventionen","\u002Fconventions","7.conventions",[858,862,868,873],{"title":854,"path":855,"stem":859,"icon":860,"description":861,"subcategory":13},"7.conventions\u002Findex","lucide:ruler","Projektspezifische Regeln — die, die sich aus dem Code nicht erschließen lassen.",{"title":863,"path":864,"stem":865,"icon":866,"description":867,"subcategory":13},"Branding","\u002Fconventions\u002Fbranding","7.conventions\u002F1.branding","lucide:shapes","Die Marke [d]uxt — wo welches Asset verwendet wird, warum die Klammern des Icons neu gezeichnet sind, und welche Farben feststehen.",{"title":869,"path":870,"stem":871,"icon":353,"description":872,"subcategory":13},"Icons","\u002Fconventions\u002Ficons","7.conventions\u002F2.icons","Vier Icon-Sätze, und die eine Frage, die entscheidet, welcher davon ein Zeichen malt.",{"title":874,"path":875,"stem":876,"icon":91,"description":877,"subcategory":13},"Abhängigkeitssicherheit","\u002Fconventions\u002Fdependency-security","7.conventions\u002F3.dependency-security","Sicherheitshinweise prüfen, ohne betroffene Pfade zu verbergen.",{"title":879,"path":880,"stem":881,"children":882,"description":886},"Architekturentscheidungen","\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","Das Entscheidungsprotokoll — jede Architekturentscheidung, die für duxt festgehalten wurde.",{"title":888,"path":889,"stem":890,"icon":13,"description":891,"subcategory":13},"duxt als Ebene bauen, die ein Modul trägt","\u002Fadr\u002F0001-build-duxt-as-a-layer-carrying-a-module","99.adr\u002F0001-build-duxt-as-a-layer-carrying-a-module","Das Theme als Nuxt-Ebene ausliefern, deren Wurzel das Paket ist, statt als Starter-Vorlage.",{"title":893,"path":894,"stem":895,"icon":13,"description":896,"subcategory":13},"Die Collections aus einer Quellenliste erzeugen","\u002Fadr\u002F0002-generate-the-collections-from-one-source-list","99.adr\u002F0002-generate-the-collections-from-one-source-list","Content-Collections zur Ladezeit der Konfiguration aus einer kompakten Quellenliste berechnen, statt Konsumenten sie deklarieren zu lassen.",{"title":898,"path":899,"stem":900,"icon":13,"description":901,"subcategory":13},"Die URL-Präfixe zur Build-Zeit entscheiden","\u002Fadr\u002F0003-decide-the-url-prefixes-at-build-time","99.adr\u002F0003-decide-the-url-prefixes-at-build-time","Ob ein Repository- oder Versionssegment erscheint, entscheidet die Quellenliste vor der ersten Anfrage, nie pro Anfrage.",{"title":903,"path":904,"stem":905,"icon":13,"description":906,"subcategory":13},"Markdown-Komponenten mit MDC rendern","\u002Fadr\u002F0004-render-markdown-components-with-mdc","99.adr\u002F0004-render-markdown-components-with-mdc","Für Komponenten in Markdown Contents eigene MDC-Syntax nutzen, statt MDX einzuführen.",{"title":908,"path":909,"stem":910,"icon":13,"description":911,"subcategory":13},"Die Ebene ohne betreiberspezifische Links ausliefern","\u002Fadr\u002F0005-ship-the-layer-without-owner-specific-links","99.adr\u002F0005-ship-the-layer-without-owner-specific-links","Jeder Standard, der ein bestimmtes Projekt benennen würde — Repository, Issue-Tracker, Community, Impressum —, wird leer ausgeliefert.",{"title":913,"path":914,"stem":915,"icon":13,"description":916,"subcategory":13},"Nach Zeitplan neu bauen statt zur Laufzeit aktualisieren","\u002Fadr\u002F0006-rebuild-on-a-schedule-rather-than-refresh-at-runtime","99.adr\u002F0006-rebuild-on-a-schedule-rather-than-refresh-at-runtime","Eine Seite, die ein anderes Repository liest, übernimmt dessen Änderungen beim Bauen, und eine Aktualisierung zur Laufzeit wird nicht angeboten.",{"title":918,"path":919,"stem":920,"icon":13,"description":921,"subcategory":13},"Übersetzungen als eigene Collections ausliefern","\u002Fadr\u002F0007-serve-translations-as-collections-of-their-own","99.adr\u002F0007-serve-translations-as-collections-of-their-own","Einer Quelle eine Locale-Dimension hinzufügen statt dem Content-Pfad ein Locale-Segment.",{"title":923,"path":924,"stem":925,"icon":13,"description":926,"subcategory":13},"Das Theme auf eigenen shadcn-vue-Komponenten bauen","\u002Fadr\u002F0008-build-the-theme-on-owned-shadcn-vue-components","99.adr\u002F0008-build-the-theme-on-owned-shadcn-vue-components","Die Ebene hält den Quelltext ihrer Interface-Komponenten selbst, statt sie aus einer Komponentenbibliothek oder einem fertigen Dokumentations-Theme zu importieren.",{"title":928,"path":929,"stem":930,"icon":13,"description":931,"subcategory":13},"Den SEO-Unterbau aus dem Nuxt-SEO-Bündel nehmen","\u002Fadr\u002F0009-take-the-seo-stack-from-the-nuxt-seo-bundle","99.adr\u002F0009-take-the-seo-stack-from-the-nuxt-seo-bundle","Die Ebene installiert @nuxtjs\u002Fseo und übergibt ihm die Head-Tags und strukturierten Daten, die sie bislang von Hand schrieb — behalten werden nur die Regeln, die von Versionen und Übersetzungen abhängen.",{"title":933,"path":934,"stem":935,"icon":13,"description":936,"subcategory":13},"Die Suche pro Collection von Content als Standard behalten","\u002Fadr\u002F0010-keep-contents-per-collection-search-as-the-default","99.adr\u002F0010-keep-contents-per-collection-search-as-the-default","Ein einziger Index über alle Quellen wurde gegen Contents Suche mit einem Index pro Collection gemessen und ist nicht der Standard der Ebene; der Build-Hook macht ihn stattdessen zu einer Provider-Ebene.",{"title":938,"path":939,"stem":940,"icon":13,"description":941,"subcategory":13},"Die Provider-Ebenen in einem Turborepo-Monorepo führen","\u002Fadr\u002F0011-host-the-provider-layers-in-a-turborepo-monorepo","99.adr\u002F0011-host-the-provider-layers-in-a-turborepo-monorepo","Die Ebene zieht nach packages\u002Fduxt und die Website nach apps\u002Fwww, jedes veröffentlichte Paket versioniert und taggt für sich als \u003Cname>@vX.Y.Z, und die 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>",{"page":952,"from":2552,"asked":2553},{"id":953,"title":835,"body":954,"breadcrumb":1182,"category":13,"compare":13,"contributors":13,"copyPage":1182,"date":13,"description":838,"extension":2544,"feedback":1182,"fullWidth":945,"icon":103,"lastUpdated":13,"layout":13,"meta":2545,"navigation":1182,"pageInfo":1182,"page_title":13,"path":836,"prevNext":1182,"rawbody":2546,"redirectFrom":2547,"release":13,"search":1182,"seo":2549,"sitemap":2550,"stem":837,"subcategory":13,"toc":13,"__hash__":2551},"docs_de\u002F5.add-ons\u002F1.typesense.md",{"type":955,"value":956,"toc":2537},"minimark",[957,970,982,987,995,999,1110,1121,1124,2332,2336,2343,2409,2416,2420,2431,2464,2470,2474,2533],[958,959,960,961,965,966,969],"p",{},"duxt gibt ",[962,963,964],"a",{"href":260},"einen einzigen Build-Hook"," aus, und der übergibt\njede Seite jeder Quelle, jeder Version und jeder Sprache als flache Records.\nEine Seite, die ohnehin ",[967,968,835],"strong",{}," betreibt, macht daraus eine eigene\nCollection — ohne die gerenderte Seite erneut zu crawlen und ohne duxts Quell-,\nVersions- und Locale-Logik nachzubauen.",[971,972,975],"callout",{"title":973,"type":974},"Der Dienst gehört dir, nicht duxt","info",[958,976,977,978,981],{},"duxt liefert kein Typesense-SDK, keine Zugangsdaten und keine Dienstkonfiguration aus. Die optionale Companion-Layer übernimmt die Integration; der Dienst und seine Schlüssel gehören dir. Ohne Provider oder eigenen Listener ",[962,979,980],{"href":260},"baut duxt überhaupt keine Payload",".",[983,984,986],"h2",{"id":985},"die-companion-layer-verwenden","Die Companion-Layer verwenden",[958,988,989,990,994],{},"Für die fertige Integration installierst du ",[991,992,993],"code",{},"@kirchdev\u002Fduxt-typesense"," und erweiterst es nach duxt. Es synchronisiert den vollständigen Satz über eine Staging-Collection und einen Aliaswechsel, entfernt die vorherige verwaltete Collection und verbindet den bestehenden Suchdialog mit einem reinen Suchschlüssel. Die folgenden Schritte bleiben ein Rezept für eine eigene Synchronisation.",[996,997],"package-managers",{"command":998},"add @kirchdev\u002Fduxt-typesense",[1000,1001,1007],"pre",{"className":1002,"code":1003,"filename":1004,"language":1005,"meta":1006,"style":1006},"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","",[991,1008,1009,1029,1048,1054,1067,1078,1089,1098,1104],{"__ignoreMap":1006},[1010,1011,1014,1018,1021,1025],"span",{"class":1012,"line":1013},"line",1,[1010,1015,1017],{"class":1016},"szBVR","export",[1010,1019,1020],{"class":1016}," default",[1010,1022,1024],{"class":1023},"sScJk"," defineNuxtConfig",[1010,1026,1028],{"class":1027},"sVt8B","({\n",[1010,1030,1032,1035,1039,1042,1045],{"class":1012,"line":1031},2,[1010,1033,1034],{"class":1027},"  extends: [",[1010,1036,1038],{"class":1037},"sZZnC","'@kirchdev\u002Fduxt'",[1010,1040,1041],{"class":1027},", ",[1010,1043,1044],{"class":1037},"'@kirchdev\u002Fduxt-typesense'",[1010,1046,1047],{"class":1027},"],\n",[1010,1049,1051],{"class":1012,"line":1050},3,[1010,1052,1053],{"class":1027},"  duxtTypesense: {\n",[1010,1055,1057,1060,1064],{"class":1012,"line":1056},4,[1010,1058,1059],{"class":1027},"    endpoint: process.env.",[1010,1061,1063],{"class":1062},"sj4cs","TYPESENSE_ENDPOINT",[1010,1065,1066],{"class":1027},",\n",[1010,1068,1070,1073,1076],{"class":1012,"line":1069},5,[1010,1071,1072],{"class":1027},"    collection: ",[1010,1074,1075],{"class":1037},"'docs'",[1010,1077,1066],{"class":1027},[1010,1079,1081,1084,1087],{"class":1012,"line":1080},6,[1010,1082,1083],{"class":1027},"    adminKey: process.env.",[1010,1085,1086],{"class":1062},"TYPESENSE_ADMIN_KEY",[1010,1088,1066],{"class":1027},[1010,1090,1092,1095],{"class":1012,"line":1091},7,[1010,1093,1094],{"class":1027},"    searchKey: process.env.",[1010,1096,1097],{"class":1062},"TYPESENSE_SEARCH_KEY\n",[1010,1099,1101],{"class":1012,"line":1100},8,[1010,1102,1103],{"class":1027},"  }\n",[1010,1105,1107],{"class":1012,"line":1106},9,[1010,1108,1109],{"class":1027},"})\n",[958,1111,1112,1113,1116,1117,1120],{},"Der Admin-Schlüssel gehört ausschließlich in die Build-Konfiguration. ",[991,1114,1115],{},"searchKey"," darf nur ",[991,1118,1119],{},"documents:search"," für diesen Alias erlauben, und Typesense muss Browseranfragen deiner Seite zulassen.",[983,1122,368],{"id":1123},"schritte",[1125,1126,1127,1141,1144,1152,1336,1343,1363,1380,1392,1662,1669,1682,2156,2163,2174,2186,2320],"steps",{},[1128,1129,1130],"ol",{},[1131,1132,1133,1136,1137,1140],"li",{},[967,1134,1135],{},"Installiere den Client in deiner Seite."," Er ist eine Abhängigkeit zur\nBuild-Zeit: die Synchronisation läuft in Node während ",[991,1138,1139],{},"nuxt build",", nie im\nBrowser.",[996,1142],{"command":1143},"add -D typesense",[1128,1145,1146],{"start":1031},[1131,1147,1148,1151],{},[967,1149,1150],{},"Deklariere die Collection."," Jedes Feld eines duxt-Records bildet auf ein\nTypesense-Feld ab, und die beiden Herkunftsfelder sind das, wonach ein Leser\nfiltert:",[1000,1153,1156],{"className":1002,"code":1154,"filename":1155,"language":1005,"meta":1006,"style":1006},"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",[991,1157,1158,1178,1184,1206,1215,1220,1237,1250,1263,1282,1305,1324,1330],{"__ignoreMap":1006},[1010,1159,1160,1163,1166,1169,1172,1175],{"class":1012,"line":1013},[1010,1161,1162],{"class":1016},"import",[1010,1164,1165],{"class":1016}," type",[1010,1167,1168],{"class":1027}," { CollectionCreateSchema } ",[1010,1170,1171],{"class":1016},"from",[1010,1173,1174],{"class":1037}," 'typesense'",[1010,1176,1177],{"class":1027},";\n",[1010,1179,1180],{"class":1012,"line":1031},[1010,1181,1183],{"emptyLinePlaceholder":1182},true,"\n",[1010,1185,1186,1188,1191,1194,1197,1200,1203],{"class":1012,"line":1050},[1010,1187,1017],{"class":1016},[1010,1189,1190],{"class":1016}," const",[1010,1192,1193],{"class":1062}," docs",[1010,1195,1196],{"class":1016},":",[1010,1198,1199],{"class":1023}," CollectionCreateSchema",[1010,1201,1202],{"class":1016}," =",[1010,1204,1205],{"class":1027}," {\n",[1010,1207,1208,1211,1213],{"class":1012,"line":1056},[1010,1209,1210],{"class":1027},"  name: ",[1010,1212,1075],{"class":1037},[1010,1214,1066],{"class":1027},[1010,1216,1217],{"class":1012,"line":1069},[1010,1218,1219],{"class":1027},"  fields: [\n",[1010,1221,1222,1225,1228,1231,1234],{"class":1012,"line":1080},[1010,1223,1224],{"class":1027},"    { name: ",[1010,1226,1227],{"class":1037},"'url'",[1010,1229,1230],{"class":1027},", type: ",[1010,1232,1233],{"class":1037},"'string'",[1010,1235,1236],{"class":1027}," },\n",[1010,1238,1239,1241,1244,1246,1248],{"class":1012,"line":1091},[1010,1240,1224],{"class":1027},[1010,1242,1243],{"class":1037},"'title'",[1010,1245,1230],{"class":1027},[1010,1247,1233],{"class":1037},[1010,1249,1236],{"class":1027},[1010,1251,1252,1254,1257,1259,1261],{"class":1012,"line":1100},[1010,1253,1224],{"class":1027},[1010,1255,1256],{"class":1037},"'content'",[1010,1258,1230],{"class":1027},[1010,1260,1233],{"class":1037},[1010,1262,1236],{"class":1027},[1010,1264,1265,1267,1270,1272,1274,1277,1280],{"class":1012,"line":1106},[1010,1266,1224],{"class":1027},[1010,1268,1269],{"class":1037},"'source'",[1010,1271,1230],{"class":1027},[1010,1273,1233],{"class":1037},[1010,1275,1276],{"class":1027},", facet: ",[1010,1278,1279],{"class":1062},"true",[1010,1281,1236],{"class":1027},[1010,1283,1285,1287,1290,1292,1294,1296,1298,1301,1303],{"class":1012,"line":1284},10,[1010,1286,1224],{"class":1027},[1010,1288,1289],{"class":1037},"'version'",[1010,1291,1230],{"class":1027},[1010,1293,1233],{"class":1037},[1010,1295,1276],{"class":1027},[1010,1297,1279],{"class":1062},[1010,1299,1300],{"class":1027},", optional: ",[1010,1302,1279],{"class":1062},[1010,1304,1236],{"class":1027},[1010,1306,1308,1310,1313,1315,1317,1319,1321],{"class":1012,"line":1307},11,[1010,1309,1224],{"class":1027},[1010,1311,1312],{"class":1037},"'locale'",[1010,1314,1230],{"class":1027},[1010,1316,1233],{"class":1037},[1010,1318,1276],{"class":1027},[1010,1320,1279],{"class":1062},[1010,1322,1323],{"class":1027}," }\n",[1010,1325,1327],{"class":1012,"line":1326},12,[1010,1328,1329],{"class":1027},"  ]\n",[1010,1331,1333],{"class":1012,"line":1332},13,[1010,1334,1335],{"class":1027},"};\n",[958,1337,1338,1339,1342],{},"Als ",[991,1340,1341],{},"CollectionCreateSchema"," typisiert, denn Schritt 4 übergibt genau\ndieses Objekt an Typesense, um die Collection damit anzulegen.",[958,1344,1345,1348,1349,1351,1352,1354,1355,1358,1359,1362],{},[991,1346,1347],{},"id"," fehlt in der Liste mit Absicht: Typesense behandelt ",[991,1350,1347],{}," bereits als\nPrimärschlüssel des Dokuments, und duxts ",[991,1353,1347],{}," ist\n",[962,1356,1357],{"href":260},"ein Hex-Digest der URL"," — als Schlüssel gültig, auf jeder\nMaschine identisch und unverändert, solange die Seite bleibt, wo sie ist. Das\nist es, was der Synchronisation ein ",[967,1360,1361],{},"Upsert"," statt eines Neuaufbaus\nerlaubt.",[958,1364,1365,1368,1369,1372,1373,1376,1377,1379],{},[991,1366,1367],{},"version"," ist ",[991,1370,1371],{},"optional",", denn eine Quelle mit nur einer Version trägt keine.\nAus ",[991,1374,1375],{},"source"," ist die Version bewusst herausgenommen, damit eine Facette\ndarauf ein Release überlebt und ",[991,1378,1367],{}," daneben das ist, was auf eine\neinzelne eingrenzt.",[1128,1381,1382],{"start":1050},[1131,1383,1384,1387,1388,1391],{},[967,1385,1386],{},"Schreibe das Modul, das zuhört."," Ein Nuxt-Modul in deiner eigenen Seite\nist die ganze Integration — ",[991,1389,1390],{},"defineNuxtModule",", ein Hook, ein Import:",[1000,1393,1396],{"className":1002,"code":1394,"filename":1395,"language":1005,"meta":1006,"style":1006},"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 Kein Schlüssel ist ein lokaler Build, kein Fehler: überspringen,\n    \u002F\u002F statt ihn zu brechen.\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",[991,1397,1398,1412,1425,1441,1455,1459,1470,1480,1500,1517,1523,1528,1547,1551,1583,1602,1616,1622,1628,1633,1645,1651,1656],{"__ignoreMap":1006},[1010,1399,1400,1402,1405,1407,1410],{"class":1012,"line":1013},[1010,1401,1162],{"class":1016},[1010,1403,1404],{"class":1027}," { defineNuxtModule } ",[1010,1406,1171],{"class":1016},[1010,1408,1409],{"class":1037}," '@nuxt\u002Fkit'",[1010,1411,1177],{"class":1027},[1010,1413,1414,1416,1419,1421,1423],{"class":1012,"line":1031},[1010,1415,1162],{"class":1016},[1010,1417,1418],{"class":1027}," { Client } ",[1010,1420,1171],{"class":1016},[1010,1422,1174],{"class":1037},[1010,1424,1177],{"class":1027},[1010,1426,1427,1429,1431,1434,1436,1439],{"class":1012,"line":1050},[1010,1428,1162],{"class":1016},[1010,1430,1165],{"class":1016},[1010,1432,1433],{"class":1027}," { DuxtSearchRecord } ",[1010,1435,1171],{"class":1016},[1010,1437,1438],{"class":1037}," '@kirchdev\u002Fduxt\u002Fsearch-records'",[1010,1440,1177],{"class":1027},[1010,1442,1443,1445,1448,1450,1453],{"class":1012,"line":1056},[1010,1444,1162],{"class":1016},[1010,1446,1447],{"class":1027}," { docs } ",[1010,1449,1171],{"class":1016},[1010,1451,1452],{"class":1037}," '..\u002Fserver\u002Ftypesense-schema'",[1010,1454,1177],{"class":1027},[1010,1456,1457],{"class":1012,"line":1069},[1010,1458,1183],{"emptyLinePlaceholder":1182},[1010,1460,1461,1463,1465,1468],{"class":1012,"line":1080},[1010,1462,1017],{"class":1016},[1010,1464,1020],{"class":1016},[1010,1466,1467],{"class":1023}," defineNuxtModule",[1010,1469,1028],{"class":1027},[1010,1471,1472,1475,1478],{"class":1012,"line":1091},[1010,1473,1474],{"class":1027},"  meta: { name: ",[1010,1476,1477],{"class":1037},"'typesense-sync'",[1010,1479,1236],{"class":1027},[1010,1481,1482,1485,1488,1492,1494,1497],{"class":1012,"line":1100},[1010,1483,1484],{"class":1023},"  setup",[1010,1486,1487],{"class":1027},"(",[1010,1489,1491],{"class":1490},"s4XuR","_options",[1010,1493,1041],{"class":1027},[1010,1495,1496],{"class":1490},"nuxt",[1010,1498,1499],{"class":1027},") {\n",[1010,1501,1502,1505,1508,1510,1513,1515],{"class":1012,"line":1106},[1010,1503,1504],{"class":1016},"    const",[1010,1506,1507],{"class":1062}," key",[1010,1509,1202],{"class":1016},[1010,1511,1512],{"class":1027}," process.env.",[1010,1514,1086],{"class":1062},[1010,1516,1177],{"class":1027},[1010,1518,1519],{"class":1012,"line":1284},[1010,1520,1522],{"class":1521},"sJ8bj","    \u002F\u002F Kein Schlüssel ist ein lokaler Build, kein Fehler: überspringen,\n",[1010,1524,1525],{"class":1012,"line":1307},[1010,1526,1527],{"class":1521},"    \u002F\u002F statt ihn zu brechen.\n",[1010,1529,1530,1533,1536,1539,1542,1545],{"class":1012,"line":1326},[1010,1531,1532],{"class":1016},"    if",[1010,1534,1535],{"class":1027}," (",[1010,1537,1538],{"class":1016},"!",[1010,1540,1541],{"class":1027},"key) ",[1010,1543,1544],{"class":1016},"return",[1010,1546,1177],{"class":1027},[1010,1548,1549],{"class":1012,"line":1332},[1010,1550,1183],{"emptyLinePlaceholder":1182},[1010,1552,1554,1557,1560,1562,1565,1567,1570,1572,1575,1578,1581],{"class":1012,"line":1553},14,[1010,1555,1556],{"class":1027},"    nuxt.",[1010,1558,1559],{"class":1023},"hook",[1010,1561,1487],{"class":1027},[1010,1563,1564],{"class":1037},"'duxt:search:records'",[1010,1566,1041],{"class":1027},[1010,1568,1569],{"class":1016},"async",[1010,1571,1535],{"class":1027},[1010,1573,1574],{"class":1490},"records",[1010,1576,1577],{"class":1027},") ",[1010,1579,1580],{"class":1016},"=>",[1010,1582,1205],{"class":1027},[1010,1584,1586,1589,1592,1594,1597,1600],{"class":1012,"line":1585},15,[1010,1587,1588],{"class":1016},"      const",[1010,1590,1591],{"class":1062}," client",[1010,1593,1202],{"class":1016},[1010,1595,1596],{"class":1016}," new",[1010,1598,1599],{"class":1023}," Client",[1010,1601,1028],{"class":1027},[1010,1603,1605,1608,1611,1613],{"class":1012,"line":1604},16,[1010,1606,1607],{"class":1027},"        nodes: [{ url: process.env.",[1010,1609,1610],{"class":1062},"TYPESENSE_URL",[1010,1612,1538],{"class":1016},[1010,1614,1615],{"class":1027}," }],\n",[1010,1617,1619],{"class":1012,"line":1618},17,[1010,1620,1621],{"class":1027},"        apiKey: key\n",[1010,1623,1625],{"class":1012,"line":1624},18,[1010,1626,1627],{"class":1027},"      });\n",[1010,1629,1631],{"class":1012,"line":1630},19,[1010,1632,1183],{"emptyLinePlaceholder":1182},[1010,1634,1636,1639,1642],{"class":1012,"line":1635},20,[1010,1637,1638],{"class":1016},"      await",[1010,1640,1641],{"class":1023}," sync",[1010,1643,1644],{"class":1027},"(client, records);\n",[1010,1646,1648],{"class":1012,"line":1647},21,[1010,1649,1650],{"class":1027},"    });\n",[1010,1652,1654],{"class":1012,"line":1653},22,[1010,1655,1103],{"class":1027},[1010,1657,1659],{"class":1012,"line":1658},23,[1010,1660,1661],{"class":1027},"});\n",[958,1663,1664,1665,1668],{},"Die Payload ist ",[967,1666,1667],{},"eingefroren",". Bilde sie auf eigene Dokumente ab —\nüberschreibe niemals einen Record und sortiere das Array nicht an Ort und\nStelle, denn jeder andere Listener bekommt dieselben Objekte.",[1128,1670,1671],{"start":1056},[1131,1672,1673,1676,1677,1681],{},[967,1674,1675],{},"Synchronisiere die ganze Menge und entferne, was fort ist."," Der Hook\nübergibt bei jedem Build die ",[1678,1679,1680],"em",{},"vollständige"," aktuelle Record-Menge, also ist\ndie Menge selbst die Anweisung — alles, was die Collection hält und was nicht\ndarin vorkommt, wurde gelöscht, verschoben oder umbenannt:",[1000,1683,1685],{"className":1002,"code":1684,"filename":1395,"language":1005,"meta":1006,"style":1006},"async function sync(client: Client, records: readonly DuxtSearchRecord[]) {\n  const collection = client.collections(docs.name);\n\n  \u002F\u002F Typesense legt nichts von selbst an: ein Import in eine Collection,\n  \u002F\u002F die es nicht gibt, schlägt fehl — der erste Build legt sie also an.\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 Alles, was der Build nicht übergeben hat, steht nicht mehr auf der Seite.\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 Stapelweise löschen: jede id landet im Filter-String, und eine\n  \u002F\u002F einzige große Umbenennung baute einen, den Typesense ablehnt.\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",[991,1686,1687,1720,1739,1743,1748,1753,1791,1795,1812,1839,1849,1854,1858,1863,1893,1916,1920,1932,1953,1963,1996,2022,2026,2031,2036,2078,2115,2145,2150],{"__ignoreMap":1006},[1010,1688,1689,1691,1694,1696,1698,1701,1703,1705,1707,1709,1711,1714,1717],{"class":1012,"line":1013},[1010,1690,1569],{"class":1016},[1010,1692,1693],{"class":1016}," function",[1010,1695,1641],{"class":1023},[1010,1697,1487],{"class":1027},[1010,1699,1700],{"class":1490},"client",[1010,1702,1196],{"class":1016},[1010,1704,1599],{"class":1023},[1010,1706,1041],{"class":1027},[1010,1708,1574],{"class":1490},[1010,1710,1196],{"class":1016},[1010,1712,1713],{"class":1016}," readonly",[1010,1715,1716],{"class":1023}," DuxtSearchRecord",[1010,1718,1719],{"class":1027},"[]) {\n",[1010,1721,1722,1725,1728,1730,1733,1736],{"class":1012,"line":1031},[1010,1723,1724],{"class":1016},"  const",[1010,1726,1727],{"class":1062}," collection",[1010,1729,1202],{"class":1016},[1010,1731,1732],{"class":1027}," client.",[1010,1734,1735],{"class":1023},"collections",[1010,1737,1738],{"class":1027},"(docs.name);\n",[1010,1740,1741],{"class":1012,"line":1050},[1010,1742,1183],{"emptyLinePlaceholder":1182},[1010,1744,1745],{"class":1012,"line":1056},[1010,1746,1747],{"class":1521},"  \u002F\u002F Typesense legt nichts von selbst an: ein Import in eine Collection,\n",[1010,1749,1750],{"class":1012,"line":1069},[1010,1751,1752],{"class":1521},"  \u002F\u002F die es nicht gibt, schlägt fehl — der erste Build legt sie also an.\n",[1010,1754,1755,1758,1760,1762,1764,1767,1770,1773,1776,1778,1780,1782,1785,1788],{"class":1012,"line":1080},[1010,1756,1757],{"class":1016},"  if",[1010,1759,1535],{"class":1027},[1010,1761,1538],{"class":1016},[1010,1763,1487],{"class":1027},[1010,1765,1766],{"class":1016},"await",[1010,1768,1769],{"class":1027}," collection.",[1010,1771,1772],{"class":1023},"exists",[1010,1774,1775],{"class":1027},"())) ",[1010,1777,1766],{"class":1016},[1010,1779,1732],{"class":1027},[1010,1781,1735],{"class":1023},[1010,1783,1784],{"class":1027},"().",[1010,1786,1787],{"class":1023},"create",[1010,1789,1790],{"class":1027},"(docs);\n",[1010,1792,1793],{"class":1012,"line":1091},[1010,1794,1183],{"emptyLinePlaceholder":1182},[1010,1796,1797,1800,1802,1805,1807,1809],{"class":1012,"line":1100},[1010,1798,1799],{"class":1016},"  await",[1010,1801,1769],{"class":1027},[1010,1803,1804],{"class":1023},"documents",[1010,1806,1784],{"class":1027},[1010,1808,1162],{"class":1023},[1010,1810,1811],{"class":1027},"(\n",[1010,1813,1814,1817,1820,1823,1826,1828,1830,1833,1836],{"class":1012,"line":1106},[1010,1815,1816],{"class":1027},"    records.",[1010,1818,1819],{"class":1023},"map",[1010,1821,1822],{"class":1027},"((",[1010,1824,1825],{"class":1490},"record",[1010,1827,1577],{"class":1027},[1010,1829,1580],{"class":1016},[1010,1831,1832],{"class":1027}," ({ ",[1010,1834,1835],{"class":1016},"...",[1010,1837,1838],{"class":1027},"record })),\n",[1010,1840,1841,1844,1847],{"class":1012,"line":1284},[1010,1842,1843],{"class":1027},"    { action: ",[1010,1845,1846],{"class":1037},"'upsert'",[1010,1848,1323],{"class":1027},[1010,1850,1851],{"class":1012,"line":1307},[1010,1852,1853],{"class":1027},"  );\n",[1010,1855,1856],{"class":1012,"line":1326},[1010,1857,1183],{"emptyLinePlaceholder":1182},[1010,1859,1860],{"class":1012,"line":1332},[1010,1861,1862],{"class":1521},"  \u002F\u002F Alles, was der Build nicht übergeben hat, steht nicht mehr auf der Seite.\n",[1010,1864,1865,1867,1870,1872,1874,1877,1880,1882,1884,1886,1888,1890],{"class":1012,"line":1553},[1010,1866,1724],{"class":1016},[1010,1868,1869],{"class":1062}," kept",[1010,1871,1202],{"class":1016},[1010,1873,1596],{"class":1016},[1010,1875,1876],{"class":1023}," Set",[1010,1878,1879],{"class":1027},"(records.",[1010,1881,1819],{"class":1023},[1010,1883,1822],{"class":1027},[1010,1885,1825],{"class":1490},[1010,1887,1577],{"class":1027},[1010,1889,1580],{"class":1016},[1010,1891,1892],{"class":1027}," record.id));\n",[1010,1894,1895,1897,1900,1902,1905,1907,1909,1911,1913],{"class":1012,"line":1585},[1010,1896,1724],{"class":1016},[1010,1898,1899],{"class":1062}," live",[1010,1901,1202],{"class":1016},[1010,1903,1904],{"class":1016}," await",[1010,1906,1769],{"class":1027},[1010,1908,1804],{"class":1023},[1010,1910,1784],{"class":1027},[1010,1912,1017],{"class":1023},[1010,1914,1915],{"class":1027},"();\n",[1010,1917,1918],{"class":1012,"line":1604},[1010,1919,1183],{"emptyLinePlaceholder":1182},[1010,1921,1922,1924,1927,1929],{"class":1012,"line":1618},[1010,1923,1724],{"class":1016},[1010,1925,1926],{"class":1062}," stale",[1010,1928,1202],{"class":1016},[1010,1930,1931],{"class":1027}," live\n",[1010,1933,1934,1937,1940,1942,1945,1948,1950],{"class":1012,"line":1624},[1010,1935,1936],{"class":1027},"    .",[1010,1938,1939],{"class":1023},"split",[1010,1941,1487],{"class":1027},[1010,1943,1944],{"class":1037},"'",[1010,1946,1947],{"class":1062},"\\n",[1010,1949,1944],{"class":1037},[1010,1951,1952],{"class":1027},")\n",[1010,1954,1955,1957,1960],{"class":1012,"line":1630},[1010,1956,1936],{"class":1027},[1010,1958,1959],{"class":1023},"filter",[1010,1961,1962],{"class":1027},"(Boolean)\n",[1010,1964,1965,1967,1969,1971,1973,1975,1977,1980,1982,1985,1988,1991,1994],{"class":1012,"line":1635},[1010,1966,1936],{"class":1027},[1010,1968,1819],{"class":1023},[1010,1970,1822],{"class":1027},[1010,1972,1012],{"class":1490},[1010,1974,1577],{"class":1027},[1010,1976,1580],{"class":1016},[1010,1978,1979],{"class":1062}," JSON",[1010,1981,981],{"class":1027},[1010,1983,1984],{"class":1023},"parse",[1010,1986,1987],{"class":1027},"(line).id ",[1010,1989,1990],{"class":1016},"as",[1010,1992,1993],{"class":1062}," string",[1010,1995,1952],{"class":1027},[1010,1997,1998,2000,2002,2004,2006,2008,2010,2013,2016,2019],{"class":1012,"line":1647},[1010,1999,1936],{"class":1027},[1010,2001,1959],{"class":1023},[1010,2003,1822],{"class":1027},[1010,2005,1347],{"class":1490},[1010,2007,1577],{"class":1027},[1010,2009,1580],{"class":1016},[1010,2011,2012],{"class":1016}," !",[1010,2014,2015],{"class":1027},"kept.",[1010,2017,2018],{"class":1023},"has",[1010,2020,2021],{"class":1027},"(id));\n",[1010,2023,2024],{"class":1012,"line":1653},[1010,2025,1183],{"emptyLinePlaceholder":1182},[1010,2027,2028],{"class":1012,"line":1658},[1010,2029,2030],{"class":1521},"  \u002F\u002F Stapelweise löschen: jede id landet im Filter-String, und eine\n",[1010,2032,2033],{"class":1012,"line":944},[1010,2034,2035],{"class":1521},"  \u002F\u002F einzige große Umbenennung baute einen, den Typesense ablehnt.\n",[1010,2037,2039,2042,2044,2047,2050,2053,2056,2059,2062,2065,2068,2070,2073,2076],{"class":1012,"line":2038},25,[1010,2040,2041],{"class":1016},"  for",[1010,2043,1535],{"class":1027},[1010,2045,2046],{"class":1016},"let",[1010,2048,2049],{"class":1027}," index ",[1010,2051,2052],{"class":1016},"=",[1010,2054,2055],{"class":1062}," 0",[1010,2057,2058],{"class":1027},"; index ",[1010,2060,2061],{"class":1016},"\u003C",[1010,2063,2064],{"class":1027}," stale.",[1010,2066,2067],{"class":1062},"length",[1010,2069,2058],{"class":1027},[1010,2071,2072],{"class":1016},"+=",[1010,2074,2075],{"class":1062}," 100",[1010,2077,1499],{"class":1027},[1010,2079,2081,2083,2086,2088,2090,2093,2096,2099,2101,2104,2107,2109,2112],{"class":1012,"line":2080},26,[1010,2082,1504],{"class":1016},[1010,2084,2085],{"class":1062}," batch",[1010,2087,1202],{"class":1016},[1010,2089,2064],{"class":1027},[1010,2091,2092],{"class":1023},"slice",[1010,2094,2095],{"class":1027},"(index, index ",[1010,2097,2098],{"class":1016},"+",[1010,2100,2075],{"class":1062},[1010,2102,2103],{"class":1027},").",[1010,2105,2106],{"class":1023},"join",[1010,2108,1487],{"class":1027},[1010,2110,2111],{"class":1037},"','",[1010,2113,2114],{"class":1027},");\n",[1010,2116,2118,2121,2123,2125,2127,2130,2133,2136,2139,2142],{"class":1012,"line":2117},27,[1010,2119,2120],{"class":1016},"    await",[1010,2122,1769],{"class":1027},[1010,2124,1804],{"class":1023},[1010,2126,1784],{"class":1027},[1010,2128,2129],{"class":1023},"delete",[1010,2131,2132],{"class":1027},"({ filter_by: ",[1010,2134,2135],{"class":1037},"`id:[${",[1010,2137,2138],{"class":1027},"batch",[1010,2140,2141],{"class":1037},"}]`",[1010,2143,2144],{"class":1027}," });\n",[1010,2146,2148],{"class":1012,"line":2147},28,[1010,2149,1103],{"class":1027},[1010,2151,2153],{"class":1012,"line":2152},29,[1010,2154,2155],{"class":1027},"}\n",[958,2157,2158,2159,2162],{},"Die Collection wird beim ersten Lauf angelegt und danach in Ruhe gelassen,\nund die veralteten ids werden ",[967,2160,2161],{},"stapelweise"," gelöscht — Typesense nimmt den\nFilter als einen String, und eine Umbenennung, die eine ganze Quelle\nverschiebt, baute sonst einen, den er ablehnt.",[971,2164,2167],{"title":2165,"type":2166},"Oder tausche stattdessen einen Alias","tip",[958,2168,2169,2170,2173],{},"Importiere in eine nach dem Build benannte Collection, richte dann einen\nTypesense-",[967,2171,2172],{},"Alias"," darauf und wirf die vorherige weg. Jeder Build legt seine\neigene Collection an, also braucht es weder die Existenzprüfung noch das\nstapelweise Löschen, und Leser sehen nie einen halb geschriebenen Index — zum\nPreis, bei jedem Build alles neu zu indizieren statt nur das Bewegte.",[1128,2175,2176],{"start":1069},[1131,2177,2178,2181,2182,2185],{},[967,2179,2180],{},"Suche aus dem Browser mit einem reinen Suchschlüssel."," Der Admin-Schlüssel\noben signiert Schreibvorgänge und darf nie eine Seite erreichen. Stelle einen\n",[967,2183,2184],{},"scoped, nur suchenden"," Schlüssel für den Client aus und filtere über die\nFacetten, die das Schema deklariert hat:",[1000,2187,2189],{"className":1002,"code":2188,"language":1005,"meta":1006,"style":1006},"\u002F\u002F `locale` ist die Sprache des INHALTS, nicht die Oberflächensprache.\n\u002F\u002F `version` fehlt bei einer Quelle ohne Versionen — die Klausel kommt nur\n\u002F\u002F dann dazu; fest eingebaut filterte sie auf `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",[991,2190,2191,2196,2201,2206,2231,2253,2257,2287,2292,2302,2316],{"__ignoreMap":1006},[1010,2192,2193],{"class":1012,"line":1013},[1010,2194,2195],{"class":1521},"\u002F\u002F `locale` ist die Sprache des INHALTS, nicht die Oberflächensprache.\n",[1010,2197,2198],{"class":1012,"line":1031},[1010,2199,2200],{"class":1521},"\u002F\u002F `version` fehlt bei einer Quelle ohne Versionen — die Klausel kommt nur\n",[1010,2202,2203],{"class":1012,"line":1050},[1010,2204,2205],{"class":1521},"\u002F\u002F dann dazu; fest eingebaut filterte sie auf `undefined`.\n",[1010,2207,2208,2211,2214,2216,2219,2222,2225,2228],{"class":1012,"line":1056},[1010,2209,2210],{"class":1016},"const",[1010,2212,2213],{"class":1062}," filters",[1010,2215,1202],{"class":1016},[1010,2217,2218],{"class":1027}," [",[1010,2220,2221],{"class":1037},"`locale:${",[1010,2223,2224],{"class":1027},"locale",[1010,2226,2227],{"class":1037},"}`",[1010,2229,2230],{"class":1027},"];\n",[1010,2232,2233,2236,2239,2242,2244,2247,2249,2251],{"class":1012,"line":1069},[1010,2234,2235],{"class":1016},"if",[1010,2237,2238],{"class":1027}," (version) filters.",[1010,2240,2241],{"class":1023},"push",[1010,2243,1487],{"class":1027},[1010,2245,2246],{"class":1037},"`version:${",[1010,2248,1367],{"class":1027},[1010,2250,2227],{"class":1037},[1010,2252,2114],{"class":1027},[1010,2254,2255],{"class":1012,"line":1080},[1010,2256,1183],{"emptyLinePlaceholder":1182},[1010,2258,2259,2261,2264,2266,2268,2270,2272,2274,2276,2278,2280,2282,2285],{"class":1012,"line":1091},[1010,2260,2210],{"class":1016},[1010,2262,2263],{"class":1062}," results",[1010,2265,1202],{"class":1016},[1010,2267,1904],{"class":1016},[1010,2269,1732],{"class":1027},[1010,2271,1735],{"class":1023},[1010,2273,1487],{"class":1027},[1010,2275,1075],{"class":1037},[1010,2277,2103],{"class":1027},[1010,2279,1804],{"class":1023},[1010,2281,1784],{"class":1027},[1010,2283,2284],{"class":1023},"search",[1010,2286,1028],{"class":1027},[1010,2288,2289],{"class":1012,"line":1100},[1010,2290,2291],{"class":1027},"  q: query,\n",[1010,2293,2294,2297,2300],{"class":1012,"line":1106},[1010,2295,2296],{"class":1027},"  query_by: ",[1010,2298,2299],{"class":1037},"'title,content'",[1010,2301,1066],{"class":1027},[1010,2303,2304,2307,2309,2311,2314],{"class":1012,"line":1284},[1010,2305,2306],{"class":1027},"  filter_by: filters.",[1010,2308,2106],{"class":1023},[1010,2310,1487],{"class":1027},[1010,2312,2313],{"class":1037},"' && '",[1010,2315,1952],{"class":1027},[1010,2317,2318],{"class":1012,"line":1307},[1010,2319,1661],{"class":1027},[1128,2321,2322],{"start":1080},[1131,2323,2324,2327,2328,2331],{},[967,2325,2326],{},"Prüfe einen Build von Anfang bis Ende."," Lass einen Build mit gesetztem\nSchlüssel laufen und bestätige, dass die Collection einen Record für eine\nSeite in ",[967,2329,2330],{},"jeder"," Quelle, Version und Sprache hält, die die Seite ausliefert\n— nicht nur in der Standardsprache. Der erste Build legt die Collection an;\njeder folgende schreibt per Upsert in dieselbe.",[983,2333,2335],{"id":2334},"was-die-records-dir-schon-abnehmen","Was die Records dir schon abnehmen",[958,2337,2338,2339,2342],{},"Vier Eigenschaften der Payload machen eine so kurze Synchronisation überhaupt\nerst korrekt, und alle vier sind ",[962,2340,2341],{"href":260},"der Vertrag des Hooks"," und\nnicht der Rat dieser Anleitung:",[2344,2345,2346,2360],"table",{},[2347,2348,2349],"thead",{},[2350,2351,2352,2357],"tr",{},[2353,2354,2356],"th",{"align":2355},"left","Eigenschaft",[2353,2358,2359],{"align":2355},"Was sie der Synchronisation bringt",[2361,2362,2363,2382,2393,2401],"tbody",{},[2350,2364,2365,2375],{},[2366,2367,2368,2370,2371,2374],"td",{"align":2355},[991,2369,1347],{}," leitet sich aus ",[991,2372,2373],{},"url"," ab",[2366,2376,2377,2378,2381],{"align":2355},"Ein stabiler Primärschlüssel, also genügt ",[991,2379,2380],{},"upsert"," und ein Neuaufbau ist nie nötig",[2350,2383,2384,2390],{},[2366,2385,2386,2387,2389],{"align":2355},"Die Payload ist die ",[967,2388,1680],{}," Menge",[2366,2391,2392],{"align":2355},"Löschen ist ein Vergleich gegen einen Build, ohne Crawl und ohne Buchführung",[2350,2394,2395,2398],{},[2366,2396,2397],{"align":2355},"duxt feuert nicht bei leerem Parse",[2366,2399,2400],{"align":2355},"Ein Build, der nichts geparst hat, kann dir nie sagen, den Index zu leeren",[2350,2402,2403,2406],{},[2366,2404,2405],{"align":2355},"Die Reihenfolge ist deterministisch",[2366,2407,2408],{"align":2355},"Zwei Builds unterscheiden sich genau dort, wo die Seite sich unterschied",[958,2410,2411,2412,2415],{},"Eine Seite, die ",[991,2413,2414],{},"search: false"," geschrieben hat, und eine Übersetzung in einer\nSprache, die die Seite nicht routet, erzeugen keine Records — also erreicht\nkeine von beiden Typesense.",[983,2417,2419],{"id":2418},"daraus-ein-paket-machen","Daraus ein Paket machen",[958,2421,2422,2423,2426,2427,2430],{},"Das Modul oben hat ~40 Zeilen und gehört zu einer Seite. Sobald eine zweite\nSeite es braucht, ist der Weg zum Teilen ",[967,2424,2425],{},"eine Nuxt-Ebene",", kein Plugin: eine\nEbene trägt das Modul, seine ",[991,2428,2429],{},"app.config","-Vorgaben und seine Komponenten in\neinem versionierten Paket, und ein Konsument fügt sie neben duxt hinzu.",[1000,2432,2434],{"className":1002,"code":2433,"filename":1004,"language":1005,"meta":1006,"style":1006},"export default defineNuxtConfig({\n  extends: ['@kirchdev\u002Fduxt', 'duxt-typesense']\n});\n",[991,2435,2436,2446,2460],{"__ignoreMap":1006},[1010,2437,2438,2440,2442,2444],{"class":1012,"line":1013},[1010,2439,1017],{"class":1016},[1010,2441,1020],{"class":1016},[1010,2443,1024],{"class":1023},[1010,2445,1028],{"class":1027},[1010,2447,2448,2450,2452,2454,2457],{"class":1012,"line":1031},[1010,2449,1034],{"class":1027},[1010,2451,1038],{"class":1037},[1010,2453,1041],{"class":1027},[1010,2455,2456],{"class":1037},"'duxt-typesense'",[1010,2458,2459],{"class":1027},"]\n",[1010,2461,2462],{"class":1012,"line":1050},[1010,2463,1661],{"class":1027},[958,2465,2466,2467,981],{},"Diese Ebene besitzt die Zugangsdaten, die Dienstkonfiguration, die\nSynchronisationspolitik und die Such-Oberfläche im Browser. duxt selbst bekommt\nnichts davon —\n",[962,2468,2469],{"href":260},"und genau darum ist der Hook so geschnitten, wie er ist",[983,2471,2473],{"id":2472},"checkliste","Checkliste",[2475,2476,2479,2492,2498,2511,2521,2527],"ul",{"className":2477},[2478],"contains-task-list",[1131,2480,2483,2487,2488,2491],{"className":2481},[2482],"task-list-item",[2484,2485],"input",{"disabled":1182,"type":2486},"checkbox"," Der Client ist eine Abhängigkeit ",[967,2489,2490],{},"deiner"," Seite, nicht der Ebene",[1131,2493,2495,2497],{"className":2494},[2482],[2484,2496],{"disabled":1182,"type":2486}," Der Admin-Schlüssel lebt in der Build-Umgebung und erreicht nie eine Seite",[1131,2499,2501,2503,2504,1041,2506,2508,2509],{"className":2500},[2482],[2484,2502],{"disabled":1182,"type":2486}," Die Collection wird beim ersten Build angelegt und facettiert ",[991,2505,1375],{},[991,2507,1367],{}," und ",[991,2510,2224],{},[1131,2512,2514,2516,2517,2520],{"className":2513},[2482],[2484,2515],{"disabled":1182,"type":2486}," Nicht mehr übergebene Records werden entfernt — per ",[967,2518,2519],{},"stapelweisem"," Vergleich oder per Alias-Tausch",[1131,2522,2524,2526],{"className":2523},[2482],[2484,2525],{"disabled":1182,"type":2486}," Ein Build ohne Schlüssel überspringt die Synchronisation, statt zu scheitern",[1131,2528,2530,2532],{"className":2529},[2482],[2484,2531],{"disabled":1182,"type":2486}," Jede Quelle, Version und Sprache ist in der Collection vertreten",[2534,2535,2536],"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":1006,"searchDepth":1031,"depth":1069,"links":2538},[2539,2540,2541,2542,2543],{"id":985,"depth":1031,"text":986},{"id":1123,"depth":1031,"text":368},{"id":2334,"depth":1031,"text":2335},{"id":2418,"depth":1031,"text":2419},{"id":2472,"depth":1031,"text":2473},"md",{},"---\ntitle: Typesense\ndescription: duxts einen Build-Hook in eine Typesense-Collection überführen — jede Quelle, jede Version und jede Sprache, per stabiler ID aktualisiert.\nicon: lucide:search\nredirectFrom:\n  - \u002Fguides\u002Fsend-your-pages-to-typesense\n---\n\nduxt gibt [einen einzigen Build-Hook](\u002Freference\u002Fhooks) aus, und der übergibt\njede Seite jeder Quelle, jeder Version und jeder Sprache als flache Records.\nEine Seite, die ohnehin **Typesense** betreibt, macht daraus eine eigene\nCollection — ohne die gerenderte Seite erneut zu crawlen und ohne duxts Quell-,\nVersions- und Locale-Logik nachzubauen.\n\n::callout{type=\"info\" title=\"Der Dienst gehört dir, nicht duxt\"}\nduxt liefert kein Typesense-SDK, keine Zugangsdaten und keine Dienstkonfiguration aus. Die optionale Companion-Layer übernimmt die Integration; der Dienst und seine Schlüssel gehören dir. Ohne Provider oder eigenen Listener [baut duxt überhaupt keine Payload](\u002Freference\u002Fhooks).\n::\n\n## Die Companion-Layer verwenden\n\nFür die fertige Integration installierst du `@kirchdev\u002Fduxt-typesense` und erweiterst es nach duxt. Es synchronisiert den vollständigen Satz über eine Staging-Collection und einen Aliaswechsel, entfernt die vorherige verwaltete Collection und verbindet den bestehenden Suchdialog mit einem reinen Suchschlüssel. Die folgenden Schritte bleiben ein Rezept für eine eigene Synchronisation.\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\nDer Admin-Schlüssel gehört ausschließlich in die Build-Konfiguration. `searchKey` darf nur `documents:search` für diesen Alias erlauben, und Typesense muss Browseranfragen deiner Seite zulassen.\n\n## Schritte\n\n::steps\n\n1. **Installiere den Client in deiner Seite.** Er ist eine Abhängigkeit zur\n   Build-Zeit: die Synchronisation läuft in Node während `nuxt build`, nie im\n   Browser.\n\n   ::package-managers{command=\"add -D typesense\"}\n   ::\n\n2. **Deklariere die Collection.** Jedes Feld eines duxt-Records bildet auf ein\n   Typesense-Feld ab, und die beiden Herkunftsfelder sind das, wonach ein Leser\n   filtert:\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   Als `CollectionCreateSchema` typisiert, denn Schritt 4 übergibt genau\n   dieses Objekt an Typesense, um die Collection damit anzulegen.\n\n   `id` fehlt in der Liste mit Absicht: Typesense behandelt `id` bereits als\n   Primärschlüssel des Dokuments, und duxts `id` ist\n   [ein Hex-Digest der URL](\u002Freference\u002Fhooks) — als Schlüssel gültig, auf jeder\n   Maschine identisch und unverändert, solange die Seite bleibt, wo sie ist. Das\n   ist es, was der Synchronisation ein **Upsert** statt eines Neuaufbaus\n   erlaubt.\n\n   `version` ist `optional`, denn eine Quelle mit nur einer Version trägt keine.\n   Aus `source` ist die Version bewusst herausgenommen, damit eine Facette\n   darauf ein Release überlebt und `version` daneben das ist, was auf eine\n   einzelne eingrenzt.\n\n3. **Schreibe das Modul, das zuhört.** Ein Nuxt-Modul in deiner eigenen Seite\n   ist die ganze Integration — `defineNuxtModule`, ein Hook, ein 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 Kein Schlüssel ist ein lokaler Build, kein Fehler: überspringen,\n       \u002F\u002F statt ihn zu brechen.\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   Die Payload ist **eingefroren**. Bilde sie auf eigene Dokumente ab —\n   überschreibe niemals einen Record und sortiere das Array nicht an Ort und\n   Stelle, denn jeder andere Listener bekommt dieselben Objekte.\n\n4. **Synchronisiere die ganze Menge und entferne, was fort ist.** Der Hook\n   übergibt bei jedem Build die *vollständige* aktuelle Record-Menge, also ist\n   die Menge selbst die Anweisung — alles, was die Collection hält und was nicht\n   darin vorkommt, wurde gelöscht, verschoben oder umbenannt:\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 legt nichts von selbst an: ein Import in eine Collection,\n     \u002F\u002F die es nicht gibt, schlägt fehl — der erste Build legt sie also an.\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 Alles, was der Build nicht übergeben hat, steht nicht mehr auf der Seite.\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 Stapelweise löschen: jede id landet im Filter-String, und eine\n     \u002F\u002F einzige große Umbenennung baute einen, den Typesense ablehnt.\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   Die Collection wird beim ersten Lauf angelegt und danach in Ruhe gelassen,\n   und die veralteten ids werden **stapelweise** gelöscht — Typesense nimmt den\n   Filter als einen String, und eine Umbenennung, die eine ganze Quelle\n   verschiebt, baute sonst einen, den er ablehnt.\n\n   ::callout{type=\"tip\" title=\"Oder tausche stattdessen einen Alias\"}\n   Importiere in eine nach dem Build benannte Collection, richte dann einen\n   Typesense-**Alias** darauf und wirf die vorherige weg. Jeder Build legt seine\n   eigene Collection an, also braucht es weder die Existenzprüfung noch das\n   stapelweise Löschen, und Leser sehen nie einen halb geschriebenen Index — zum\n   Preis, bei jedem Build alles neu zu indizieren statt nur das Bewegte.\n   ::\n\n5. **Suche aus dem Browser mit einem reinen Suchschlüssel.** Der Admin-Schlüssel\n   oben signiert Schreibvorgänge und darf nie eine Seite erreichen. Stelle einen\n   **scoped, nur suchenden** Schlüssel für den Client aus und filtere über die\n   Facetten, die das Schema deklariert hat:\n\n   ```ts\n   \u002F\u002F `locale` ist die Sprache des INHALTS, nicht die Oberflächensprache.\n   \u002F\u002F `version` fehlt bei einer Quelle ohne Versionen — die Klausel kommt nur\n   \u002F\u002F dann dazu; fest eingebaut filterte sie auf `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. **Prüfe einen Build von Anfang bis Ende.** Lass einen Build mit gesetztem\n   Schlüssel laufen und bestätige, dass die Collection einen Record für eine\n   Seite in **jeder** Quelle, Version und Sprache hält, die die Seite ausliefert\n   — nicht nur in der Standardsprache. Der erste Build legt die Collection an;\n   jeder folgende schreibt per Upsert in dieselbe.\n\n::\n\n## Was die Records dir schon abnehmen\n\nVier Eigenschaften der Payload machen eine so kurze Synchronisation überhaupt\nerst korrekt, und alle vier sind [der Vertrag des Hooks](\u002Freference\u002Fhooks) und\nnicht der Rat dieser Anleitung:\n\n| Eigenschaft | Was sie der Synchronisation bringt |\n| :--- | :--- |\n| `id` leitet sich aus `url` ab | Ein stabiler Primärschlüssel, also genügt `upsert` und ein Neuaufbau ist nie nötig |\n| Die Payload ist die **vollständige** Menge | Löschen ist ein Vergleich gegen einen Build, ohne Crawl und ohne Buchführung |\n| duxt feuert nicht bei leerem Parse | Ein Build, der nichts geparst hat, kann dir nie sagen, den Index zu leeren |\n| Die Reihenfolge ist deterministisch | Zwei Builds unterscheiden sich genau dort, wo die Seite sich unterschied |\n\nEine Seite, die `search: false` geschrieben hat, und eine Übersetzung in einer\nSprache, die die Seite nicht routet, erzeugen keine Records — also erreicht\nkeine von beiden Typesense.\n\n## Daraus ein Paket machen\n\nDas Modul oben hat ~40 Zeilen und gehört zu einer Seite. Sobald eine zweite\nSeite es braucht, ist der Weg zum Teilen **eine Nuxt-Ebene**, kein Plugin: eine\nEbene trägt das Modul, seine `app.config`-Vorgaben und seine Komponenten in\neinem versionierten Paket, und ein Konsument fügt sie neben duxt hinzu.\n\n```ts [nuxt.config.ts]\nexport default defineNuxtConfig({\n  extends: ['@kirchdev\u002Fduxt', 'duxt-typesense']\n});\n```\n\nDiese Ebene besitzt die Zugangsdaten, die Dienstkonfiguration, die\nSynchronisationspolitik und die Such-Oberfläche im Browser. duxt selbst bekommt\nnichts davon —\n[und genau darum ist der Hook so geschnitten, wie er ist](\u002Freference\u002Fhooks).\n\n## Checkliste\n\n- [ ] Der Client ist eine Abhängigkeit **deiner** Seite, nicht der Ebene\n- [ ] Der Admin-Schlüssel lebt in der Build-Umgebung und erreicht nie eine Seite\n- [ ] Die Collection wird beim ersten Build angelegt und facettiert `source`, `version` und `locale`\n- [ ] Nicht mehr übergebene Records werden entfernt — per **stapelweisem** Vergleich oder per Alias-Tausch\n- [ ] Ein Build ohne Schlüssel überspringt die Synchronisation, statt zu scheitern\n- [ ] Jede Quelle, Version und Sprache ist in der Collection vertreten\n",[2548],"\u002Fguides\u002Fsend-your-pages-to-typesense",{"title":835,"description":838},{"loc":836},"YCE5m33b2CufOZpUuQ11hIYLhiTW8DRB1-e1PhqdhuY","de","de-DE",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2555},"\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":2557},"\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":2559},"\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":2561},"\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":2563},"\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":2565},"\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>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2567},"\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":2569},"\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":2571},"\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":2573},"\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":2575},"\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":2577},"\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":2579},"\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":2581},"\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":2583},"\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":2585,"hidden":1182},"\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>",{"left":943,"top":943,"width":944,"height":944,"rotate":943,"vFlip":945,"hFlip":945,"body":2587},"\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":2589},"\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":2591},"\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":2593},"\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":2595},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m9 18l6-6l-6-6\"\u002F>",[2597,2598,2599,2600,2601,2602,2603,2604],"\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":2606},"\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":2608},"\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":2610},"\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":2612},"\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>",{"pnpm":2614,"npm":2615,"yarn":2616,"bun":2617},"\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":2619,"height":2619,"rotate":943,"vFlip":945,"hFlip":945,"body":2620},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":2619,"height":2619,"rotate":943,"vFlip":945,"hFlip":945,"body":2622},"\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":2619,"height":2619,"rotate":943,"vFlip":945,"hFlip":945,"body":2624},"\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":2619,"height":2619,"rotate":943,"vFlip":945,"hFlip":945,"body":2626},"\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":2619,"height":2619,"rotate":943,"vFlip":945,"hFlip":945,"body":2628},"\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":2630,"npm":2631,"yarn":2632,"bun":2633},"\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>",{"left":943,"top":943,"width":2635,"height":2636,"rotate":943,"vFlip":945,"hFlip":945,"body":2637},640,480,"\u003Cpath fill=\"#fc0\" d=\"M0 320h640v160H0z\"\u002F>\u003Cpath fill=\"#000001\" d=\"M0 0h640v160H0z\"\u002F>\u003Cpath fill=\"red\" d=\"M0 160h640v160H0z\"\u002F>",1792683315770]