[{"data":1,"prerenderedAt":1459},["ShallowReactive",2],{"navigation_docs":3,"-guides-routes-and-auth":412,"-guides-routes-and-auth-surround":1454},[4,38,84,326,386],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":37},"Getting started","i-lucide-rocket","\u002Fgetting-started","1.getting-started",[10,15,20,24,28,32],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F1.introduction","i-lucide-book-open",{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":6},"Quick start: Nuxt","\u002Fgetting-started\u002Fquick-start-nuxt","1.getting-started\u002F3.quick-start-nuxt",{"title":25,"path":26,"stem":27,"icon":6},"Quick start: plain Vue","\u002Fgetting-started\u002Fquick-start-vue","1.getting-started\u002F4.quick-start-vue",{"title":29,"path":30,"stem":31,"icon":6},"Quick start: React","\u002Fgetting-started\u002Fquick-start-react","1.getting-started\u002F5.quick-start-react",{"title":33,"path":34,"stem":35,"icon":36},"Glossary","\u002Fgetting-started\u002Fglossary","1.getting-started\u002F6.glossary","i-lucide-book-a",false,{"title":39,"icon":40,"path":41,"stem":42,"children":43,"page":37},"Tutorial","i-lucide-graduation-cap","\u002Ftutorial","2.tutorial",[44,49,54,59,64,69,74,79],{"title":45,"path":46,"stem":47,"icon":48},"Tutorial: overview","\u002Ftutorial\u002Foverview","2.tutorial\u002F1.overview","i-lucide-map",{"title":50,"path":51,"stem":52,"icon":53},"Chapter 2: A simple editor","\u002Ftutorial\u002Fsimple-editor","2.tutorial\u002F2.simple-editor","i-lucide-pencil",{"title":55,"path":56,"stem":57,"icon":58},"Chapter 3: Compose features","\u002Ftutorial\u002Fcompose-features","2.tutorial\u002F3.compose-features","i-lucide-blocks",{"title":60,"path":61,"stem":62,"icon":63},"Chapter 4: Your own block, path A","\u002Ftutorial\u002Fown-block-path-a","2.tutorial\u002F4.own-block-path-a","i-lucide-square-plus",{"title":65,"path":66,"stem":67,"icon":68},"Chapter 5: Your own feature, path B","\u002Ftutorial\u002Fown-feature-path-b","2.tutorial\u002F5.own-feature-path-b","i-lucide-puzzle",{"title":70,"path":71,"stem":72,"icon":73},"Chapter 6: Backend and collaboration","\u002Ftutorial\u002Fbackend-and-collaboration","2.tutorial\u002F6.backend-and-collaboration","i-lucide-users",{"title":75,"path":76,"stem":77,"icon":78},"Chapter 7: AI","\u002Ftutorial\u002Fai","2.tutorial\u002F7.ai","i-lucide-sparkles",{"title":80,"path":81,"stem":82,"icon":83},"Chapter 8: The React surface","\u002Ftutorial\u002Freact-surface","2.tutorial\u002F8.react-surface","i-lucide-atom",{"title":85,"icon":14,"path":86,"stem":87,"children":88,"page":37},"Guides","\u002Fguides","3.guides",[89,93,98,103,108,112,116,121,126,130,134,139,144,149,154,159,164,169,174,179,184,189,194,199,204,209,213,218,223,228,233,237,242,247,251,256,261,266,271,276,281,286,291,295,302,307,311,316,321],{"title":90,"path":91,"stem":92,"icon":58},"Feature composition and entries","\u002Fguides\u002Fcomposition","3.guides\u002F1.composition",{"title":94,"path":95,"stem":96,"icon":97},"Media, mentions and transcript features","\u002Fguides\u002Fmedia-mentions-transcript","3.guides\u002F10.media-mentions-transcript","i-lucide-image",{"title":99,"path":100,"stem":101,"icon":102},"Authors and comments","\u002Fguides\u002Fauthors-and-comments","3.guides\u002F11.authors-and-comments","i-lucide-message-square-text",{"title":104,"path":105,"stem":106,"icon":107},"Themes (Obsidian)","\u002Fguides\u002Fthemes","3.guides\u002F12.themes","i-lucide-palette",{"title":109,"path":110,"stem":111,"icon":58},"Composites and the settings UI","\u002Fguides\u002Fcomposites","3.guides\u002F13.composites",{"title":113,"path":114,"stem":115,"icon":78},"AI","\u002Fguides\u002Fai","3.guides\u002F14.ai",{"title":117,"path":118,"stem":119,"icon":120},"Document tree","\u002Fguides\u002Fdocument-tree","3.guides\u002F15.document-tree","i-lucide-folder-tree",{"title":122,"path":123,"stem":124,"icon":125},"Markdown and code","\u002Fguides\u002Fmarkdown-and-code","3.guides\u002F16.markdown-and-code","i-lucide-file-code",{"title":127,"path":128,"stem":129,"icon":83},"Advanced editor in React","\u002Fguides\u002Fadvanced-react","3.guides\u002F17.advanced-react",{"title":131,"path":132,"stem":133,"icon":6},"Kitchen sink: learning path","\u002Fguides\u002Fadvanced-nuxt-example","3.guides\u002F18.advanced-nuxt-example",{"title":135,"path":136,"stem":137,"icon":138},"Production","\u002Fguides\u002Fproduction","3.guides\u002F19.production","i-lucide-server",{"title":140,"path":141,"stem":142,"icon":143},"Register the Nuxt module","\u002Fguides\u002Fnuxt-module","3.guides\u002F2.nuxt-module","i-lucide-package",{"title":145,"path":146,"stem":147,"icon":148},"Storage adapters, comment stores, Nitro host","\u002Fguides\u002Fstorage-adapters","3.guides\u002F20.storage-adapters","i-lucide-database",{"title":150,"path":151,"stem":152,"icon":153},"Migrating from #tiptap-editor","\u002Fguides\u002Fmigration","3.guides\u002F21.migration","i-lucide-arrow-right-left",{"title":155,"path":156,"stem":157,"icon":158},"Content tree mechanics","\u002Fguides\u002Fcontent-tree","3.guides\u002F22.content-tree","i-lucide-git-fork",{"title":160,"path":161,"stem":162,"icon":163},"Block capabilities, abilities and actions","\u002Fguides\u002Fblock-capabilities","3.guides\u002F23.block-capabilities","i-lucide-shield-check",{"title":165,"path":166,"stem":167,"icon":168},"Block types in code and JSON","\u002Fguides\u002Fblock-types","3.guides\u002F24.block-types","i-lucide-shapes",{"title":170,"path":171,"stem":172,"icon":173},"Derive methods and the Derivation index","\u002Fguides\u002Fderive-methods","3.guides\u002F25.derive-methods","i-lucide-git-branch-plus",{"title":175,"path":176,"stem":177,"icon":178},"Block properties and Property definitions","\u002Fguides\u002Fblock-properties","3.guides\u002F26.block-properties","i-lucide-sliders-horizontal",{"title":180,"path":181,"stem":182,"icon":183},"Image studio","\u002Fguides\u002Fimage-studio","3.guides\u002F27.image-studio","i-lucide-image-plus",{"title":185,"path":186,"stem":187,"icon":188},"Prüfung and Freigabestatus","\u002Fguides\u002Fpruefung","3.guides\u002F28.pruefung","i-lucide-stamp",{"title":190,"path":191,"stem":192,"icon":193},"Workspace: find, read, reference and embed Blocks across Documents","\u002Fguides\u002Fworkspace","3.guides\u002F29.workspace","i-lucide-network",{"title":195,"path":196,"stem":197,"icon":198},"EditorPorts: auth and storage","\u002Fguides\u002Feditor-ports","3.guides\u002F3.editor-ports","i-lucide-plug",{"title":200,"path":201,"stem":202,"icon":203},"Collections: an ordered list of Blocks","\u002Fguides\u002Fcollections","3.guides\u002F30.collections","i-lucide-list-checks",{"title":205,"path":206,"stem":207,"icon":208},"Data views: a query shown as table, list or board","\u002Fguides\u002Fdata-views","3.guides\u002F31.data-views","i-lucide-table-properties",{"title":210,"path":211,"stem":212,"icon":193},"Explore: backlinks, related Blocks and the trail","\u002Fguides\u002Fexplore","3.guides\u002F32.explore",{"title":214,"path":215,"stem":216,"icon":217},"Render: export a Block or a Document to a file","\u002Fguides\u002Frender","3.guides\u002F33.render","i-lucide-file-output",{"title":219,"path":220,"stem":221,"icon":222},"Importers: what a dropped file becomes","\u002Fguides\u002Fimporters","3.guides\u002F34.importers","i-lucide-file-input",{"title":224,"path":225,"stem":226,"icon":227},"Templates: start a Document from a Dokumentvorlage","\u002Fguides\u002Ftemplates","3.guides\u002F35.templates","i-lucide-file-stack",{"title":229,"path":230,"stem":231,"icon":232},"Citations","\u002Fguides\u002Fcitations","3.guides\u002F36.citations","i-lucide-quote",{"title":234,"path":235,"stem":236,"icon":163},"AI proposals and the export check","\u002Fguides\u002Fexport-check","3.guides\u002F37.export-check",{"title":238,"path":239,"stem":240,"icon":241},"Query: filter, sort, group and total Blocks","\u002Fguides\u002Fquery","3.guides\u002F38.query","i-lucide-list-filter",{"title":243,"path":244,"stem":245,"icon":246},"Edges: backlinks and authored connections","\u002Fguides\u002Fedges","3.guides\u002F39.edges","i-lucide-link-2",{"title":248,"path":249,"stem":250,"icon":163},"Server routes and authentication","\u002Fguides\u002Froutes-and-auth","3.guides\u002F4.routes-and-auth",{"title":252,"path":253,"stem":254,"icon":255},"Speech: text to audio, and subtitle files","\u002Fguides\u002Fspeech","3.guides\u002F41.speech","i-lucide-audio-lines",{"title":257,"path":258,"stem":259,"icon":260},"Graph: the Edges around a Block","\u002Fguides\u002Fgraph","3.guides\u002F42.graph","i-lucide-waypoints",{"title":262,"path":263,"stem":264,"icon":265},"PDF viewer: passages, anchors and quotes","\u002Fguides\u002Fpdf-viewer","3.guides\u002F43.pdf-viewer","i-lucide-file-search",{"title":267,"path":268,"stem":269,"icon":270},"Obsidian: import and export a vault","\u002Fguides\u002Fobsidian","3.guides\u002F44.obsidian","i-lucide-folder-input",{"title":272,"path":273,"stem":274,"icon":275},"Typst: render a Document as a PDF with citations","\u002Fguides\u002Ftypst","3.guides\u002F45.typst","i-lucide-file-text",{"title":277,"path":278,"stem":279,"icon":280},"Audio: read aloud, mixdown and ElevenLabs","\u002Fguides\u002Faudio","3.guides\u002F46.audio","i-lucide-audio-waveform",{"title":282,"path":283,"stem":284,"icon":285},"Slides: decks, slide layouts and exports","\u002Fguides\u002Fslides","3.guides\u002F47.slides","i-lucide-presentation",{"title":287,"path":288,"stem":289,"icon":290},"Knowledge graph: sources and concepts beside the Documents","\u002Fguides\u002Fknowledge-graph","3.guides\u002F49.knowledge-graph","i-lucide-share-2",{"title":292,"path":293,"stem":294,"icon":78},"AI configuration and secrets","\u002Fguides\u002Fai-configuration","3.guides\u002F5.ai-configuration",{"title":296,"path":297,"stem":298,"children":299,"icon":301},"Index on Postgres: typos, meaning and SQL pushdown","\u002Fguides\u002Findex-pg","3.guides\u002F50.index-pg",[300],{"title":296,"path":297,"stem":298,"icon":301},"i-lucide-database-zap",{"title":303,"path":304,"stem":305,"icon":306},"Charts: bar, line, pie and scatter over a query","\u002Fguides\u002Fcharts","3.guides\u002F51.charts","i-lucide-chart-column",{"title":308,"path":309,"stem":310,"icon":73},"Collaboration on the client","\u002Fguides\u002Fcollaboration","3.guides\u002F6.collaboration",{"title":312,"path":313,"stem":314,"icon":315},"Block UI (drag handle, hover actions)","\u002Fguides\u002Fblock-ui","3.guides\u002F7.block-ui","i-lucide-grip-vertical",{"title":317,"path":318,"stem":319,"icon":320},"Settings and app lifetime","\u002Fguides\u002Fsettings","3.guides\u002F8.settings","i-lucide-settings",{"title":322,"path":323,"stem":324,"icon":325},"Language","\u002Fguides\u002Flanguage","3.guides\u002F9.language","i-lucide-languages",{"title":327,"icon":14,"path":328,"stem":329,"children":330,"page":37},"Reference","\u002Freference","4.reference",[331,335,339,344,348,352,356,360,364,368,373,378,382],{"title":332,"path":333,"stem":334,"icon":143},"Public exports","\u002Freference\u002Fexports","4.reference\u002F1.exports",{"title":336,"path":337,"stem":338,"icon":173},"Derive method contract","\u002Freference\u002Fderive-methods","4.reference\u002F10.derive-methods",{"title":340,"path":341,"stem":342,"icon":343},"Changelog","\u002Freference\u002Fchangelog","4.reference\u002F11.changelog","i-lucide-history",{"title":345,"path":346,"stem":347,"icon":217},"Renderer port","\u002Freference\u002Frenderer-port","4.reference\u002F12.renderer-port",{"title":349,"path":350,"stem":351,"icon":255},"Speech port","\u002Freference\u002Fspeech-port","4.reference\u002F13.speech-port",{"title":353,"path":354,"stem":355,"icon":58},"Presets and features","\u002Freference\u002Fpresets-and-features","4.reference\u002F2.presets-and-features",{"title":357,"path":358,"stem":359,"icon":68},"Feature contract","\u002Freference\u002Ffeature-contract","4.reference\u002F3.feature-contract",{"title":361,"path":362,"stem":363,"icon":107},"CSS and UI-provider requirements","\u002Freference\u002Fcss-and-ui","4.reference\u002F4.css-and-ui",{"title":365,"path":366,"stem":367,"icon":148},"Vue-free advanced schema","\u002Freference\u002Fadvanced-schema","4.reference\u002F5.advanced-schema",{"title":369,"path":370,"stem":371,"icon":372},"Dependency rules","\u002Freference\u002Fdependency-rules","4.reference\u002F6.dependency-rules","i-lucide-git-branch",{"title":374,"path":375,"stem":376,"icon":377},"Commands","\u002Freference\u002Fcommands","4.reference\u002F7.commands","i-lucide-terminal",{"title":379,"path":380,"stem":381,"icon":163},"Block capability contract","\u002Freference\u002Fblock-capabilities","4.reference\u002F8.block-capabilities",{"title":383,"path":384,"stem":385,"icon":168},"Block type contract","\u002Freference\u002Fblock-types","4.reference\u002F9.block-types",{"title":387,"path":388,"stem":389,"children":390,"icon":393},"AI agents","\u002Fai-agents","5.ai-agents\u002F1.index",[391,394,398,402,407],{"title":392,"path":388,"stem":389,"icon":393},"Overview","i-lucide-bot",{"title":395,"path":396,"stem":397,"icon":198},"Integrate the editor","\u002Fai-agents\u002Fintegrate","5.ai-agents\u002F2.integrate",{"title":399,"path":400,"stem":401,"icon":68},"Add a block or feature","\u002Fai-agents\u002Fextend","5.ai-agents\u002F3.extend",{"title":403,"path":404,"stem":405,"icon":406},"Pitfalls and invariants","\u002Fai-agents\u002Finvariants","5.ai-agents\u002F4.invariants","i-lucide-shield-alert",{"title":408,"path":409,"stem":410,"icon":411},"Verify","\u002Fai-agents\u002Fverify","5.ai-agents\u002F5.verify","i-lucide-check-check",{"id":413,"title":248,"body":414,"description":1447,"extension":1448,"links":1449,"meta":1450,"navigation":1451,"path":249,"seo":1452,"stem":250,"__hash__":1453},"docs\u002F3.guides\u002F4.routes-and-auth.md",{"type":415,"value":416,"toc":1441},"minimark",[417,447,452,1044,1050,1054,1091,1214,1225,1229,1233,1339,1342,1437],[418,419,420,421,425,426,429,430,433,434,436,437,440,441,446],"p",{},"Every route authenticates through ",[422,423,424],"code",{},"ports.identity.authenticate","; the package guards its own routes and expects no host middleware (the demo's session middleware only makes sure a session exists; it is not what protects the routes). A ",[422,427,428],{},"null"," user answers 401 „Nicht angemeldet“ on API routes. The websocket upgrade of ",[422,431,432],{},"\u002Fcollab\u002F:id"," succeeds first by default, and a socket whose user is ",[422,435,428],{}," is closed with code 4401 right after; with the module option ",[422,438,439],{},"collab.authenticateUpgrade"," the upgrade itself is refused with HTTP 401 (see ",[442,443,445],"a",{"href":444},"#auth-notes","Auth notes",").",[448,449,451],"h2",{"id":450},"routes","Routes",[453,454,455,471],"table",{},[456,457,458],"thead",{},[459,460,461,465,468],"tr",{},[462,463,464],"th",{},"Method",[462,466,467],{},"Path",[462,469,470],{},"Purpose",[472,473,474,495,508,528,550,576,593,710,725,757,772,785,807,823,843,864,891,910,928,1016],"tbody",{},[459,475,476,480,484],{},[477,478,479],"td",{},"WS",[477,481,482],{},[422,483,432],{},[477,485,486,487,490,491,494],{},"Hocuspocus sync; the document name comes from the provider's ",[422,488,489],{},"name",". Yjs state is the source of truth; JSON is mirrored via ",[422,492,493],{},"storeContent",".",[459,496,497,500,505],{},[477,498,499],{},"GET",[477,501,502],{},[422,503,504],{},"\u002Fapi\u002Fai\u002Fmodels",[477,506,507],{},"Model presets without keys + default Model roles (not rate limited)",[459,509,510,513,518],{},[477,511,512],{},"POST",[477,514,515],{},[422,516,517],{},"\u002Fapi\u002Fai\u002Fcomplete",[477,519,520,521,524,525],{},"Ghost text: ",[422,522,523],{},"{ before, model }"," → ",[422,526,527],{},"{ text }",[459,529,530,532,537],{},[477,531,512],{},[477,533,534],{},[422,535,536],{},"\u002Fapi\u002Fai\u002Fgenerate",[477,538,539,540,543,544,543,547],{},"Task run → SSE ",[422,541,542],{},"delta"," \u002F ",[422,545,546],{},"done",[422,548,549],{},"error",[459,551,552,554,559],{},[477,553,512],{},[477,555,556],{},[422,557,558],{},"\u002Fapi\u002Fai\u002Fchat",[477,560,561,562,564,565,568,569,564,572,564,574],{},"Document chat\u002Fagent → SSE ",[422,563,542],{},", ",[422,566,567],{},"tool"," (a read-only tool call the server ran), ",[422,570,571],{},"ops",[422,573,546],{},[422,575,549],{},[459,577,578,580,585],{},[477,579,512],{},[477,581,582],{},[422,583,584],{},"\u002Fapi\u002Fai\u002Ftranscript-cleanup",[477,586,587,524,590],{},[422,588,589],{},"{ segments, model }",[422,591,592],{},"{ cleaned, failed }",[459,594,595,597,602],{},[477,596,512],{},[477,598,599],{},[422,600,601],{},"\u002Fapi\u002Fai\u002Fextract",[477,603,604,524,607,610,611,614,615,618,619,622,623,626,627,630,631,634,635,638,639,642,643,646,647,650,651,653,654,656,657,659,660,663,664,667,668,671,672,675,676,679,680,683,684,687,688,691,692,695,696,698,699,701,702,705,706,709],{},[422,605,606],{},"{ documentId, name, method, model, bibliography?, doi?, maxPages? }",[422,608,609],{},"{ method, markdown, segments?, bib?, model?, inputHash, outputHash, output, warnings }"," (",[422,612,613],{},"model",": the speech-to-text model of a transcription). Turns a stored asset into readable Markdown: ",[422,616,617],{},"method"," ",[422,620,621],{},"auto"," picks by MIME type (audio\u002Fvideo → ",[422,624,625],{},"transcription"," with segment timestamps, via ",[422,628,629],{},"ai.transcription",", 501 without it, 413 over 25 MB; image → ",[422,632,633],{},"description","; PDF → ",[422,636,637],{},"pdf-text",", or ",[422,640,641],{},"ocr"," when the text layer averages under 50 characters per page; anything else 415), ",[422,644,645],{},"bibliography"," reads a CSL item from Crossref by DOI (body, or found in the first two pages) and falls back to the model (",[422,648,649],{},"warnings: ['crossref-unavailable']","). ",[422,652,641],{}," and ",[422,655,633],{}," use the request's ",[422,658,613],{}," and need a vision-capable one. OCR makes one model call per page, so it reads at most 50 pages (fewer when ",[422,661,662],{},"maxPages"," is lower); skipped pages add ",[422,665,666],{},"warnings: ['ocr-truncated']",". PDF reading uses ",[422,669,670],{},"pdfjs-dist","; page rasterisation for OCR uses the optional dependency ",[422,673,674],{},"@napi-rs\u002Fcanvas"," (without it a PDF with a text layer answers ",[422,677,678],{},"warnings: ['ocr-unavailable']",", a scan answers 501). Aborting the request stops the page loops between pages. In ",[422,681,682],{},"markdown"," every PDF page after the first starts with a ",[422,685,686],{},"\u003C!-- page N -->"," line; the client turns it into a page label paragraph and the stored raw output keeps it. The raw Markdown is stored as a ",[422,689,690],{},"text\u002Fmarkdown"," asset (",[422,693,694],{},"output"," is its name, ",[422,697,428],{}," for ",[422,700,645],{},"); ",[422,703,704],{},"inputHash"," is the SHA-256 hex of the asset bytes, ",[422,707,708],{},"outputHash"," the SHA-256 hex of that stored raw output (the client hashes its own re-serialised body for edit detection and ignores it).",[459,711,712,714,719],{},[477,713,499],{},[477,715,716],{},[422,717,718],{},"\u002Fapi\u002Feditor\u002Fusers?q=",[477,720,721,724],{},[422,722,723],{},"@"," popup: up to 20 users",[459,726,727,729,734],{},[477,728,499],{},[477,730,731],{},[422,732,733],{},"\u002Fapi\u002Feditor\u002Fcapabilities",[477,735,736,737,610,740,743,744,653,747,750,751,753,754,756],{},"The capabilities this server serves, as ",[422,738,739],{},"BackendCapability[]",[422,741,742],{},"serverCapabilities(ports)",", with ",[422,745,746],{},"ai",[422,748,749],{},"collaboration"," as really mounted: ",[422,752,746],{}," iff the AI routes are, ",[422,755,749],{}," iff the websocket is). Always mounted; the client's probe reads it",[459,758,759,761,766],{},[477,760,499],{},[477,762,763],{},[422,764,765],{},"\u002Fapi\u002Feditor\u002Ftags?q=",[477,767,768,771],{},[422,769,770],{},"#"," popup: up to 20 tags in use",[459,773,774,777,782],{},[477,775,776],{},"GET \u002F PUT",[477,778,779],{},[422,780,781],{},"\u002Fapi\u002Feditor\u002Fsettings",[477,783,784],{},"Per-user settings (table below)",[459,786,787,789,794],{},[477,788,512],{},[477,790,791],{},[422,792,793],{},"\u002Fapi\u002Feditor\u002Fassets\u002F:id",[477,795,796,797,524,800,803,804],{},"Multipart ",[422,798,799],{},"file",[422,801,802],{},"{ url, name }","; 413 above ",[422,805,806],{},"MAX_MEDIA_BYTES",[459,808,809,811,816],{},[477,810,499],{},[477,812,813],{},[422,814,815],{},"\u002Fapi\u002Feditor\u002Fassets\u002F:id\u002F:name",[477,817,818,819,822],{},"Serves an asset with its stored ",[422,820,821],{},"Content-Type",", single byte-range support; 404 when unknown",[459,824,825,827,832],{},[477,826,499],{},[477,828,829],{},[422,830,831],{},"\u002Fapi\u002Feditor\u002Fimages\u002Fprompt-blocks",[477,833,834,835,838,839,842],{},"The prompt blocks of the host as ",[422,836,837],{},"ImageStudioPromptBlock[]","; only mounted with an ",[422,840,841],{},"images"," port",[459,844,845,847,852],{},[477,846,512],{},[477,848,849],{},[422,850,851],{},"\u002Fapi\u002Feditor\u002Fimages\u002Fgenerate",[477,853,854,857,858,861,862,842],{},[422,855,856],{},"{ description, instruction, promptBlockIds, referenceUrls }"," → the generated ",[422,859,860],{},"ImageStudioImage","; 400 for a malformed body; only mounted with an ",[422,863,841],{},[459,865,866,868,873],{},[477,867,512],{},[477,869,870],{},[422,871,872],{},"\u002Fapi\u002Feditor\u002Fimages\u002Fupload",[477,874,796,875,878,879,881,882,884,885,888,889,842],{},[422,876,877],{},"documentId"," (string) and ",[422,880,799],{}," (an image) → the stored ",[422,883,860],{},"; 400 for a malformed id or a missing file, 413 above ",[422,886,887],{},"MAX_MEDIA_BYTES.image",", 415 for a file that is no image; only mounted with an ",[422,890,841],{},[459,892,893,895,900],{},[477,894,499],{},[477,896,897],{},[422,898,899],{},"\u002Fapi\u002Feditor\u002Fthemes",[477,901,902,903,906,907,842],{},"The theme library as ",[422,904,905],{},"ThemeRecord[]","; only mounted with a ",[422,908,909],{},"themes",[459,911,912,914,919],{},[477,913,499],{},[477,915,916],{},[422,917,918],{},"\u002Fapi\u002Feditor\u002Fthemes\u002F:id",[477,920,921,922,925,926,842],{},"The theme's stylesheet as ",[422,923,924],{},"text\u002Fcss","; 400 for a malformed id, 404 when unknown; only mounted with a ",[422,927,909],{},[459,929,930,932,936],{},[477,931,512],{},[477,933,934],{},[422,935,899],{},[477,937,796,938,941,942,945,946,949,950,952,953,956,957,610,960,963,964,967,968,970,971,653,974,977,978,564,981,984,985,988,989,992,993,610,996,999,1000,1002,1003,1005,1006,1009,1010,1013,1014,842],{},[422,939,940],{},"css"," (file, required), ",[422,943,944],{},"manifest"," (file, optional Obsidian ",[422,947,948],{},"manifest.json","), ",[422,951,489],{}," (string, optional) → ",[422,954,955],{},"201"," with the new ",[422,958,959],{},"ThemeRecord",[422,961,962],{},"builtin: false","). The name is ",[422,965,966],{},"manifest.name",", else ",[422,969,489],{},", else the CSS file's base name; the id is its slug (",[422,972,973],{},"a-z0-9",[422,975,976],{},"-",", at most 64 characters), made unique with ",[422,979,980],{},"-2",[422,982,983],{},"-3"," … against the library. Limits: CSS up to ",[422,986,987],{},"MAX_THEME_BYTES"," (2 MB, ",[422,990,991],{},"413"," „Theme ist größer als 2 MB“), manifest up to 64 KB and parseable by ",[422,994,995],{},"themeManifestSchema",[422,997,998],{},"400"," „Ungültiges manifest.json“); ",[422,1001,998],{}," for a missing or empty ",[422,1004,940],{},", for content that is not UTF-8 text (invalid UTF-8, NUL bytes) and for markup (",[422,1007,1008],{},"\u003Cscript"," or ",[422,1011,1012],{},"\u003C?xml"," in the first 512 bytes); only mounted with a ",[422,1015,909],{},[459,1017,1018,1021,1025],{},[477,1019,1020],{},"DELETE",[477,1022,1023],{},[422,1024,918],{},[477,1026,1027,1028,701,1031,1033,1034,1037,1038,1041,1042,842],{},"Deletes an uploaded theme (",[422,1029,1030],{},"204",[422,1032,998],{}," for a malformed id, ",[422,1035,1036],{},"404"," when unknown, ",[422,1039,1040],{},"403"," „Mitgelieferte Themes können nicht gelöscht werden“ for a builtin; only mounted with a ",[422,1043,909],{},[418,1045,1046,1047,494],{},"The AI routes are rate limited per user (sliding window, in memory, per process): exceeding it answers 429 „Zu viele KI-Anfragen, bitte kurz warten“ with ",[422,1048,1049],{},"Retry-After",[448,1051,1053],{"id":1052},"filtering-the-mounted-routes","Filtering the mounted routes",[418,1055,1056,1059,1060,1063,1064,1067,1068,1070,1071,1074,1075,564,1077,564,1080,564,1083,1086,1087,1090],{},[422,1057,1058],{},"installEditorServer"," mounts every route of ",[422,1061,1062],{},"serverRoutesOf(ports, { ai })"," whose port is present. A host that serves some of these paths itself (for example ",[422,1065,1066],{},"\u002Fapi\u002Feditor\u002Fassets\u002F*"," from its own asset studio) passes ",[422,1069,450],{},", a function from the route table to the routes that are mounted; it can drop or reorder routes. The ",[422,1072,1073],{},"RouteDef"," type (",[422,1076,617],{},[422,1078,1079],{},"path",[422,1081,1082],{},"port",[422,1084,1085],{},"handler",") is exported from ",[422,1088,1089],{},"@skaile\u002Fforge-editor\u002Fserver\u002Fnitro",". The websocket is not part of the table; the default keeps every route.",[1092,1093,1098],"pre",{"className":1094,"code":1095,"language":1096,"meta":1097,"style":1097},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","installEditorServer(nitroApp, {\n  ports,\n  collab: false,\n  routes: routes => routes.filter(route => !route.path.startsWith('\u002Fapi\u002Feditor\u002Fassets')),\n})\n","ts","",[422,1099,1100,1119,1128,1144,1205],{"__ignoreMap":1097},[1101,1102,1105,1108,1112,1116],"span",{"class":1103,"line":1104},"line",1,[1101,1106,1058],{"class":1107},"s2Zo4",[1101,1109,1111],{"class":1110},"sTEyZ","(nitroApp",[1101,1113,1115],{"class":1114},"sMK4o",",",[1101,1117,1118],{"class":1114}," {\n",[1101,1120,1122,1125],{"class":1103,"line":1121},2,[1101,1123,1124],{"class":1110},"  ports",[1101,1126,1127],{"class":1114},",\n",[1101,1129,1131,1135,1138,1142],{"class":1103,"line":1130},3,[1101,1132,1134],{"class":1133},"swJcz","  collab",[1101,1136,1137],{"class":1114},":",[1101,1139,1141],{"class":1140},"sfNiH"," false",[1101,1143,1127],{"class":1114},[1101,1145,1147,1150,1152,1156,1160,1162,1164,1167,1170,1173,1175,1178,1180,1182,1184,1186,1189,1191,1194,1198,1200,1203],{"class":1103,"line":1146},4,[1101,1148,1149],{"class":1107},"  routes",[1101,1151,1137],{"class":1114},[1101,1153,1155],{"class":1154},"sHdIc"," routes",[1101,1157,1159],{"class":1158},"spNyl"," =>",[1101,1161,1155],{"class":1110},[1101,1163,494],{"class":1114},[1101,1165,1166],{"class":1107},"filter",[1101,1168,1169],{"class":1110},"(",[1101,1171,1172],{"class":1154},"route",[1101,1174,1159],{"class":1158},[1101,1176,1177],{"class":1114}," !",[1101,1179,1172],{"class":1110},[1101,1181,494],{"class":1114},[1101,1183,1079],{"class":1110},[1101,1185,494],{"class":1114},[1101,1187,1188],{"class":1107},"startsWith",[1101,1190,1169],{"class":1110},[1101,1192,1193],{"class":1114},"'",[1101,1195,1197],{"class":1196},"sfazB","\u002Fapi\u002Feditor\u002Fassets",[1101,1199,1193],{"class":1114},[1101,1201,1202],{"class":1110},"))",[1101,1204,1127],{"class":1114},[1101,1206,1208,1211],{"class":1103,"line":1207},5,[1101,1209,1210],{"class":1114},"}",[1101,1212,1213],{"class":1110},")\n",[418,1215,1216,1217,1220,1221,1224],{},"A host that drops the asset routes answers ",[422,1218,1219],{},"GET \u002Fapi\u002Feditor\u002Fassets\u002F:id\u002F:name"," itself (media elements request that URL) and gives the client a backend whose ",[422,1222,1223],{},"assets.upload"," returns the URL of its own route.",[448,1226,1228],{"id":1227},"settings-route-status-codes","Settings route status codes",[418,1230,1231,1137],{},[422,1232,781],{},[453,1234,1235,1245],{},[456,1236,1237],{},[459,1238,1239,1242],{},[462,1240,1241],{},"Request",[462,1243,1244],{},"Status",[472,1246,1247,1261,1278,1291,1308,1319,1330],{},[459,1248,1249,1258],{},[477,1250,1251,1253,1254,1257],{},[422,1252,499],{},"\u002F",[422,1255,1256],{},"PUT"," without a user",[477,1259,1260],{},"401",[459,1262,1263,1271],{},[477,1264,1265,1267,1268,842],{},[422,1266,499],{},", no ",[422,1269,1270],{},"settings",[477,1272,1273,1274,1277],{},"404 (route not mounted; client stays on ",[422,1275,1276],{},"localStorage",")",[459,1279,1280,1285],{},[477,1281,1282,1284],{},[422,1283,499],{},", nothing stored",[477,1286,1287,1288,1290],{},"200 with body ",[422,1289,428],{}," (client uploads its local settings)",[459,1292,1293,1298],{},[477,1294,1295,1297],{},[422,1296,499],{},", stored",[477,1299,1300,1301,1304,1305],{},"200, ",[422,1302,1303],{},"EditorSettings"," normalized by ",[422,1306,1307],{},"parseEditorSettings",[459,1309,1310,1316],{},[477,1311,1312,1267,1314,842],{},[422,1313,1256],{},[422,1315,1270],{},[477,1317,1318],{},"404 (route not mounted)",[459,1320,1321,1328],{},[477,1322,1323,1325,1326],{},[422,1324,1256],{},", body is no complete valid ",[422,1327,1303],{},[477,1329,998],{},[459,1331,1332,1337],{},[477,1333,1334,1336],{},[422,1335,1256],{},", ok",[477,1338,1030],{},[448,1340,445],{"id":1341},"auth-notes",[1343,1344,1345,1380,1414,1434],"ul",{},[1346,1347,1348,1352,1353,1355,1356,1359,1360,1362,1363,1365,1366,618,1369,1371,1372,1375,1376,1379],"li",{},[1349,1350,1351],"strong",{},"Websocket authentication (default)."," The upgrade to ",[422,1354,432],{}," always succeeds (HTTP 101). Hocuspocus then authenticates the connection from the upgrade request's headers, so the session cookie authenticates the socket like any same-origin request, and from the client's ",[422,1357,1358],{},"token",": clients that cannot send cookies pass ",[422,1361,1358],{}," to the ",[422,1364,749],{}," prop (a string or an async function; it becomes the ",[422,1367,1368],{},"HocuspocusProvider",[422,1370,1358],{},") and ",[422,1373,1374],{},"authenticate"," receives it as ",[422,1377,1378],{},"request.token"," next to the headers. A client without a user gets a permission-denied answer and its socket is closed with code 4401 (not an HTTP 401).",[1346,1381,1382,1395,1396,1399,1400,1402,1403,1405,1406,1409,1410,1413],{},[1349,1383,1384,1385,1388,1389,1391,1392,446],{},"Rejecting at the upgrade (",[422,1386,1387],{},"collab.authenticateUpgrade: true","; Nuxt: the module option, ",[422,1390,1058],{},": ",[422,1393,1394],{},"collab: { authenticateUpgrade: true }"," The route calls ",[422,1397,1398],{},"authenticate({ headers })"," (no ",[422,1401,1358],{},") before the upgrade; a ",[422,1404,428],{}," user answers HTTP 401 and no websocket is opened, otherwise the user is passed to the connection and not authenticated a second time. Use it when every client authenticates by cookie or other request headers; a client that identifies itself only by ",[422,1407,1408],{},"collaboration.token"," cannot connect then, because the token is only sent after the socket is open. ",[422,1411,1412],{},"authorize"," still runs per document in both modes.",[1346,1415,1416,1417,1419,1420,1423,1424,1426,1427,1430,1431,1433],{},"Document-level authorization (who may open which document) is the host's decision: ",[422,1418,1374],{}," returns the user, and ",[422,1421,1422],{},"authorize(user, id)"," decides per document on connect (",[422,1425,428],{}," rejects, ",[422,1428,1429],{},"{ readOnly: true }"," makes the connection read-only). Without ",[422,1432,1412],{}," the websocket route passes any authenticated user to Hocuspocus for any document name.",[1346,1435,1436],{},"Asset URLs are guarded too; media elements send the session cookie.",[1438,1439,1440],"style",{},"html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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);}",{"title":1097,"searchDepth":1121,"depth":1121,"links":1442},[1443,1444,1445,1446],{"id":450,"depth":1121,"text":451},{"id":1052,"depth":1121,"text":1053},{"id":1227,"depth":1121,"text":1228},{"id":1341,"depth":1121,"text":445},"How every editor route authenticates through the identity port, the full route table with status codes, and websocket authentication.","md",null,{},{"icon":163},{"title":248,"description":1447},"CKsa671etUmPITh3W9r1S2Mqh5pW88QbrgClODIZDyI",[1455,1457],{"title":243,"path":244,"stem":245,"description":1456,"icon":246,"children":-1},"Which Blocks point at a Block: the Edges the Block index projects from references, Derivations, embeds and tags, the ones a person adds in the inspector, the edges route and the drizzle table.",{"title":252,"path":253,"stem":254,"description":1458,"icon":255,"children":-1},"The SpeechProvider port with its engines and voices, the SSE route that streams progress and stores the audio as an asset, the daily character budget, the client call, and the block action that exports a transcript as WebVTT or SubRip.",1793178235629]