[{"data":1,"prerenderedAt":3404},["ShallowReactive",2],{"navigation_docs":3,"-guides-editor-ports":412,"-guides-editor-ports-surround":3399},[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":195,"body":414,"description":3392,"extension":3393,"links":3394,"meta":3395,"navigation":3396,"path":196,"seo":3397,"stem":197,"__hash__":3398},"docs\u002F3.guides\u002F3.editor-ports.md",{"type":415,"value":416,"toc":3378},"minimark",[417,422,493,497,565,1894,1898,1953,1957,1963,2095,2129,2133,2923,2962,2983,2992,3040,3044,3082,3086,3127,3131,3210,3214,3231,3235,3275,3279,3319,3323,3353,3374],[418,419,421],"h2",{"id":420},"who-owns-what","Who owns what",[423,424,425,426,430,431,434,435,439,440,443,444,447,448,451,452,455,456,459,460,463,464,467,468,471,472,475,476,479,480,482,483,475,486,489,490,492],"p",{},"The package owns the routes, the Hocuspocus server, rate limiting and the wire formats; the host owns ",[427,428,429],"em",{},"identity"," (sessions, sign-in, which user may open which document) and ",[427,432,433],{},"storage"," (where documents, Yjs state, assets, settings and themes live). Both enter through the one adapter below. The package never reads cookies or touches files itself; ",[436,437,438],"code",{},"authenticate"," returns the user (or ",[436,441,442],{},"null","), the storage methods persist what they are given. In this repository ",[436,445,446],{},"server\u002Fplugins\u002Feditor-adapter.ts"," wires the adapter to ",[436,449,450],{},"nuxt-auth-utils"," sessions and the file system under ",[436,453,454],{},".data\u002F",". The app has no login: ",[436,457,458],{},"server\u002Fmiddleware\u002Fdemo-session.ts"," signs every ",[436,461,462],{},"\u002Fapi\u002F"," request whose session is not one of the demo users ",[436,465,466],{},"anna",", ",[436,469,470],{},"ben"," or ",[436,473,474],{},"bernd"," (",[436,477,478],{},"shared\u002Futils\u002Fdemo-users.ts",") in as ",[436,481,466],{},", and ",[436,484,485],{},"POST \u002Fapi\u002Fauth\u002Fswitch",[436,487,488],{},"server\u002Fapi\u002Fauth\u002Fswitch.post.ts",") switches the session to another demo user. Both are host code; the package only sees what ",[436,491,438],{}," returns.",[418,494,496],{"id":495},"registering-the-ports","Registering the ports",[423,498,499,500,503,504,467,507,467,510,467,513,467,516,467,519,467,522,467,525,467,528,467,531,534,535,537,538,541,542,537,544,547,548,534,551,554,555,558,559,561,562,564],{},"The single seam between the package and the host: one object of ports, named by the capabilities the client's ",[436,501,502],{},"EditorBackend"," knows (",[436,505,506],{},"documents",[436,508,509],{},"collaboration",[436,511,512],{},"assets",[436,514,515],{},"users",[436,517,518],{},"tags",[436,520,521],{},"settings",[436,523,524],{},"themes",[436,526,527],{},"ai",[436,529,530],{},"comments",[436,532,533],{},"images","). ",[436,536,429],{}," (type ",[436,539,540],{},"AccessControl",") and ",[436,543,506],{},[436,545,546],{},"DocumentContentStore",") are required; every other port is optional, and the route table serves only the routes whose port is present (the client treats a refused settings load as \"no account settings\" and stays on ",[436,549,550],{},"localStorage",[436,552,553],{},"PORT_CAPABILITY"," maps port to capability, ",[436,556,557],{},"serverCapabilities(ports)"," lists what a set of ports serves (",[436,560,518],{}," follows from ",[436,563,506],{},"). Register the ports in a Nitro plugin:",[566,567,572],"pre",{"className":568,"code":569,"filename":446,"language":570,"meta":571,"style":571},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import type { User } from '#auth-utils'\nimport { createJsonAdapter } from '@skaile\u002Fforge-editor\u002Fadapters\u002Fjson'\nimport { provideEditorServer } from '@skaile\u002Fforge-editor\u002Fserver\u002Fnitro'\nimport { createWorkspaceTools } from '@skaile\u002Fforge-editor\u002Fserver'\n\n\u002F\u002F Connects the editor package's Nuxt integration to this app's sessions, JSON document store and per-user settings.\n\u002F\u002F Synchronous on purpose: Nitro does not await a plugin, so registering after an `await` would leave the first requests without an editor server.\nexport default defineNitroPlugin(() => {\n  \u002F\u002F The add-ons' ports (render targets, speech, knowledge graph) and Block types; each add-on is on behind its flag, `runtimeConfig.public.addons.\u003Cname>` (`server\u002Futils\u002Faddons.ts`).\n  const addons = createAddonServer({ storeAsset, loadAsset }, addonFlagsOf(useRuntimeConfig().public.addons))\n  provideEditorServer({\n    ports: {\n      identity: {\n        \u002F\u002F Without a session cookie h3 throws (\"Cannot initialize a new session\") outside a main handler.\n        authenticate: request => getUserSession({ headers: request.headers, context: {} }).then(s => s.user ?? null, () => null),\n      },\n      documents: {\n        loadContent: async id => (await getDocument(id))?.content ?? null,\n        async storeContent(id, content) {\n          const existing = await getDocument(id)\n          if (!existing) return \u002F\u002F deleted while a store was pending\n          await putDocument({ ...existing, content, updatedAt: new Date().toISOString() })\n        },\n        listContents: async () => (await listAllDocuments()).map(({ id, content }) => ({ id, content })),\n        \u002F\u002F Document management over the package store: folders, create, move, delete (`\u002Fapi\u002Feditor\u002F{documents,tree}`).\n        listDocumentIds: async () => indexedIds(),\n        listTree,\n        async createDocument(input) {\n          const { id, title, updatedAt } = await createDocument(input)\n          return { id, title, updatedAt, folder: input.folder ?? '' }\n        },\n        moveDocument,\n        deleteDocument: removeDocument,\n      },\n      directory: { listUsers: async () => (await listUsers()).map(toSessionUser) },\n      collabState: { loadState, storeState, removeState },\n      assets: { storeAsset, loadAsset },\n      \u002F\u002F `user` is what `authenticate` returned: the session user.\n      settings: {\n        loadSettings: user => getUserSettings((user as User).id),\n        storeSettings: (user, settings) => putUserSettings((user as User).id, settings),\n      },\n      themes: { listThemes, loadTheme, storeTheme, removeTheme },\n      \u002F\u002F Block index (`index` capability): a projection of the documents above, rebuilt on start and kept current by the editor server; in memory (memory adapter, PGlite with `NUXT_BLOCK_INDEX=pglite`, or PGlite with trigram search and vectors with `NUXT_BLOCK_INDEX=pg-vector`), so nothing to migrate.\n      index: createHostBlockIndex(addons.ports.embeddings, addons.embeddingsError),\n      \u002F\u002F Prüfung records (`pruefung` capability): the editor's JSON store on `\u003Cdocuments dir>\u002F.pruefung.json`, a dot-named file the document store never lists.\n      pruefung: createJsonAdapter({ dir: storeRoot() }).pruefung,\n      \u002F\u002F Change sets of the document chat (`changeSets` capability): what the model proposed for other Documents, decided per Document; `\u003Cdocuments dir>\u002F.change-sets.json`, likewise dot-named.\n      changeSets: createJsonAdapter({ dir: storeRoot() }).changeSets,\n      \u002F\u002F Demo of the model port (`DEMO_STUB_MODEL=1`): the stub answers `{ preset: 'stub' }`; `null` for anything else falls through to the environment presets.\n      models: {\n        languageModel: async ref => stubModelEnabled() && 'preset' in ref && ref.preset === STUB_MODEL_ID ? stubLanguageModel : null,\n        listModels: async () => stubModelEnabled() ? [...publicEnvPresets(), stubModelProfile] : null,\n      },\n      ...addons.ports,\n    },\n    ...(addons.blockTypes && { blockTypes: addons.blockTypes }),\n    \u002F\u002F The document chat's read-only workspace tools (`find_blocks`, `read_block`): the model finds and reads Blocks of the user's other Documents through the block index above.\n    tools: createWorkspaceTools(addons.blockTypes && { blockTypes: addons.blockTypes }),\n  })\n})\n","ts","",[436,573,574,610,631,652,673,680,687,693,719,725,782,793,804,814,820,907,913,923,966,988,1011,1034,1084,1090,1151,1157,1178,1186,1203,1235,1276,1281,1289,1302,1307,1350,1376,1394,1400,1410,1447,1493,1498,1528,1534,1572,1578,1613,1619,1652,1658,1668,1730,1774,1779,1793,1799,1835,1841,1879,1887],{"__ignoreMap":571},[575,576,579,583,586,590,594,597,600,603,607],"span",{"class":577,"line":578},"line",1,[575,580,582],{"class":581},"s7zQu","import",[575,584,585],{"class":581}," type",[575,587,589],{"class":588},"sMK4o"," {",[575,591,593],{"class":592},"sTEyZ"," User",[575,595,596],{"class":588}," }",[575,598,599],{"class":581}," from",[575,601,602],{"class":588}," '",[575,604,606],{"class":605},"sfazB","#auth-utils",[575,608,609],{"class":588},"'\n",[575,611,613,615,617,620,622,624,626,629],{"class":577,"line":612},2,[575,614,582],{"class":581},[575,616,589],{"class":588},[575,618,619],{"class":592}," createJsonAdapter",[575,621,596],{"class":588},[575,623,599],{"class":581},[575,625,602],{"class":588},[575,627,628],{"class":605},"@skaile\u002Fforge-editor\u002Fadapters\u002Fjson",[575,630,609],{"class":588},[575,632,634,636,638,641,643,645,647,650],{"class":577,"line":633},3,[575,635,582],{"class":581},[575,637,589],{"class":588},[575,639,640],{"class":592}," provideEditorServer",[575,642,596],{"class":588},[575,644,599],{"class":581},[575,646,602],{"class":588},[575,648,649],{"class":605},"@skaile\u002Fforge-editor\u002Fserver\u002Fnitro",[575,651,609],{"class":588},[575,653,655,657,659,662,664,666,668,671],{"class":577,"line":654},4,[575,656,582],{"class":581},[575,658,589],{"class":588},[575,660,661],{"class":592}," createWorkspaceTools",[575,663,596],{"class":588},[575,665,599],{"class":581},[575,667,602],{"class":588},[575,669,670],{"class":605},"@skaile\u002Fforge-editor\u002Fserver",[575,672,609],{"class":588},[575,674,676],{"class":577,"line":675},5,[575,677,679],{"emptyLinePlaceholder":678},true,"\n",[575,681,683],{"class":577,"line":682},6,[575,684,686],{"class":685},"sHwdD","\u002F\u002F Connects the editor package's Nuxt integration to this app's sessions, JSON document store and per-user settings.\n",[575,688,690],{"class":577,"line":689},7,[575,691,692],{"class":685},"\u002F\u002F Synchronous on purpose: Nitro does not await a plugin, so registering after an `await` would leave the first requests without an editor server.\n",[575,694,696,699,702,706,709,712,716],{"class":577,"line":695},8,[575,697,698],{"class":581},"export",[575,700,701],{"class":581}," default",[575,703,705],{"class":704},"s2Zo4"," defineNitroPlugin",[575,707,708],{"class":592},"(",[575,710,711],{"class":588},"()",[575,713,715],{"class":714},"spNyl"," =>",[575,717,718],{"class":588}," {\n",[575,720,722],{"class":577,"line":721},9,[575,723,724],{"class":685},"  \u002F\u002F The add-ons' ports (render targets, speech, knowledge graph) and Block types; each add-on is on behind its flag, `runtimeConfig.public.addons.\u003Cname>` (`server\u002Futils\u002Faddons.ts`).\n",[575,726,728,731,734,737,740,743,746,749,752,755,758,761,763,766,768,771,774,776,779],{"class":577,"line":727},10,[575,729,730],{"class":714},"  const",[575,732,733],{"class":592}," addons",[575,735,736],{"class":588}," =",[575,738,739],{"class":704}," createAddonServer",[575,741,708],{"class":742},"swJcz",[575,744,745],{"class":588},"{",[575,747,748],{"class":592}," storeAsset",[575,750,751],{"class":588},",",[575,753,754],{"class":592}," loadAsset",[575,756,757],{"class":588}," },",[575,759,760],{"class":704}," addonFlagsOf",[575,762,708],{"class":742},[575,764,765],{"class":704},"useRuntimeConfig",[575,767,711],{"class":742},[575,769,770],{"class":588},".",[575,772,773],{"class":592},"public",[575,775,770],{"class":588},[575,777,778],{"class":592},"addons",[575,780,781],{"class":742},"))\n",[575,783,785,788,790],{"class":577,"line":784},11,[575,786,787],{"class":704},"  provideEditorServer",[575,789,708],{"class":742},[575,791,792],{"class":588},"{\n",[575,794,796,799,802],{"class":577,"line":795},12,[575,797,798],{"class":742},"    ports",[575,800,801],{"class":588},":",[575,803,718],{"class":588},[575,805,807,810,812],{"class":577,"line":806},13,[575,808,809],{"class":742},"      identity",[575,811,801],{"class":588},[575,813,718],{"class":588},[575,815,817],{"class":577,"line":816},14,[575,818,819],{"class":685},"        \u002F\u002F Without a session cookie h3 throws (\"Cannot initialize a new session\") outside a main handler.\n",[575,821,823,826,828,832,834,837,839,841,844,846,848,850,853,855,858,860,863,865,868,870,873,875,878,880,883,885,888,891,894,897,899,902,904],{"class":577,"line":822},15,[575,824,825],{"class":704},"        authenticate",[575,827,801],{"class":588},[575,829,831],{"class":830},"sHdIc"," request",[575,833,715],{"class":714},[575,835,836],{"class":704}," getUserSession",[575,838,708],{"class":742},[575,840,745],{"class":588},[575,842,843],{"class":742}," headers",[575,845,801],{"class":588},[575,847,831],{"class":592},[575,849,770],{"class":588},[575,851,852],{"class":592},"headers",[575,854,751],{"class":588},[575,856,857],{"class":742}," context",[575,859,801],{"class":588},[575,861,862],{"class":588}," {}",[575,864,596],{"class":588},[575,866,867],{"class":742},")",[575,869,770],{"class":588},[575,871,872],{"class":704},"then",[575,874,708],{"class":742},[575,876,877],{"class":830},"s",[575,879,715],{"class":714},[575,881,882],{"class":592}," s",[575,884,770],{"class":588},[575,886,887],{"class":592},"user",[575,889,890],{"class":588}," ??",[575,892,893],{"class":588}," null,",[575,895,896],{"class":588}," ()",[575,898,715],{"class":714},[575,900,901],{"class":588}," null",[575,903,867],{"class":742},[575,905,906],{"class":588},",\n",[575,908,910],{"class":577,"line":909},16,[575,911,912],{"class":588},"      },\n",[575,914,916,919,921],{"class":577,"line":915},17,[575,917,918],{"class":742},"      documents",[575,920,801],{"class":588},[575,922,718],{"class":588},[575,924,926,929,931,934,937,939,941,944,947,949,952,955,958,961,963],{"class":577,"line":925},18,[575,927,928],{"class":704},"        loadContent",[575,930,801],{"class":588},[575,932,933],{"class":714}," async",[575,935,936],{"class":830}," id",[575,938,715],{"class":714},[575,940,475],{"class":742},[575,942,943],{"class":581},"await",[575,945,946],{"class":704}," getDocument",[575,948,708],{"class":742},[575,950,951],{"class":592},"id",[575,953,954],{"class":742},"))",[575,956,957],{"class":588},"?.",[575,959,960],{"class":592},"content",[575,962,890],{"class":588},[575,964,965],{"class":588}," null,\n",[575,967,969,972,975,977,979,981,984,986],{"class":577,"line":968},19,[575,970,971],{"class":714},"        async",[575,973,974],{"class":742}," storeContent",[575,976,708],{"class":588},[575,978,951],{"class":830},[575,980,751],{"class":588},[575,982,983],{"class":830}," content",[575,985,867],{"class":588},[575,987,718],{"class":588},[575,989,991,994,997,999,1002,1004,1006,1008],{"class":577,"line":990},20,[575,992,993],{"class":714},"          const",[575,995,996],{"class":592}," existing",[575,998,736],{"class":588},[575,1000,1001],{"class":581}," await",[575,1003,946],{"class":704},[575,1005,708],{"class":742},[575,1007,951],{"class":592},[575,1009,1010],{"class":742},")\n",[575,1012,1014,1017,1019,1022,1025,1028,1031],{"class":577,"line":1013},21,[575,1015,1016],{"class":581},"          if",[575,1018,475],{"class":742},[575,1020,1021],{"class":588},"!",[575,1023,1024],{"class":592},"existing",[575,1026,1027],{"class":742},") ",[575,1029,1030],{"class":581},"return",[575,1032,1033],{"class":685}," \u002F\u002F deleted while a store was pending\n",[575,1035,1037,1040,1043,1045,1047,1050,1052,1054,1056,1058,1061,1063,1066,1069,1071,1073,1076,1079,1082],{"class":577,"line":1036},22,[575,1038,1039],{"class":581},"          await",[575,1041,1042],{"class":704}," putDocument",[575,1044,708],{"class":742},[575,1046,745],{"class":588},[575,1048,1049],{"class":588}," ...",[575,1051,1024],{"class":592},[575,1053,751],{"class":588},[575,1055,983],{"class":592},[575,1057,751],{"class":588},[575,1059,1060],{"class":742}," updatedAt",[575,1062,801],{"class":588},[575,1064,1065],{"class":588}," new",[575,1067,1068],{"class":704}," Date",[575,1070,711],{"class":742},[575,1072,770],{"class":588},[575,1074,1075],{"class":704},"toISOString",[575,1077,1078],{"class":742},"() ",[575,1080,1081],{"class":588},"}",[575,1083,1010],{"class":742},[575,1085,1087],{"class":577,"line":1086},23,[575,1088,1089],{"class":588},"        },\n",[575,1091,1093,1096,1098,1100,1102,1104,1106,1108,1111,1114,1116,1119,1121,1124,1126,1128,1130,1133,1135,1137,1139,1141,1143,1145,1147,1149],{"class":577,"line":1092},24,[575,1094,1095],{"class":704},"        listContents",[575,1097,801],{"class":588},[575,1099,933],{"class":714},[575,1101,896],{"class":588},[575,1103,715],{"class":714},[575,1105,475],{"class":742},[575,1107,943],{"class":581},[575,1109,1110],{"class":704}," listAllDocuments",[575,1112,1113],{"class":742},"())",[575,1115,770],{"class":588},[575,1117,1118],{"class":704},"map",[575,1120,708],{"class":742},[575,1122,1123],{"class":588},"({",[575,1125,936],{"class":830},[575,1127,751],{"class":588},[575,1129,983],{"class":830},[575,1131,1132],{"class":588}," })",[575,1134,715],{"class":714},[575,1136,475],{"class":742},[575,1138,745],{"class":588},[575,1140,936],{"class":592},[575,1142,751],{"class":588},[575,1144,983],{"class":592},[575,1146,596],{"class":588},[575,1148,954],{"class":742},[575,1150,906],{"class":588},[575,1152,1154],{"class":577,"line":1153},25,[575,1155,1156],{"class":685},"        \u002F\u002F Document management over the package store: folders, create, move, delete (`\u002Fapi\u002Feditor\u002F{documents,tree}`).\n",[575,1158,1160,1163,1165,1167,1169,1171,1174,1176],{"class":577,"line":1159},26,[575,1161,1162],{"class":704},"        listDocumentIds",[575,1164,801],{"class":588},[575,1166,933],{"class":714},[575,1168,896],{"class":588},[575,1170,715],{"class":714},[575,1172,1173],{"class":704}," indexedIds",[575,1175,711],{"class":742},[575,1177,906],{"class":588},[575,1179,1181,1184],{"class":577,"line":1180},27,[575,1182,1183],{"class":592},"        listTree",[575,1185,906],{"class":588},[575,1187,1189,1191,1194,1196,1199,1201],{"class":577,"line":1188},28,[575,1190,971],{"class":714},[575,1192,1193],{"class":742}," createDocument",[575,1195,708],{"class":588},[575,1197,1198],{"class":830},"input",[575,1200,867],{"class":588},[575,1202,718],{"class":588},[575,1204,1206,1208,1210,1212,1214,1217,1219,1221,1223,1225,1227,1229,1231,1233],{"class":577,"line":1205},29,[575,1207,993],{"class":714},[575,1209,589],{"class":588},[575,1211,936],{"class":592},[575,1213,751],{"class":588},[575,1215,1216],{"class":592}," title",[575,1218,751],{"class":588},[575,1220,1060],{"class":592},[575,1222,596],{"class":588},[575,1224,736],{"class":588},[575,1226,1001],{"class":581},[575,1228,1193],{"class":704},[575,1230,708],{"class":742},[575,1232,1198],{"class":592},[575,1234,1010],{"class":742},[575,1236,1238,1241,1243,1245,1247,1249,1251,1253,1255,1258,1260,1263,1265,1268,1270,1273],{"class":577,"line":1237},30,[575,1239,1240],{"class":581},"          return",[575,1242,589],{"class":588},[575,1244,936],{"class":592},[575,1246,751],{"class":588},[575,1248,1216],{"class":592},[575,1250,751],{"class":588},[575,1252,1060],{"class":592},[575,1254,751],{"class":588},[575,1256,1257],{"class":742}," folder",[575,1259,801],{"class":588},[575,1261,1262],{"class":592}," input",[575,1264,770],{"class":588},[575,1266,1267],{"class":592},"folder",[575,1269,890],{"class":588},[575,1271,1272],{"class":588}," ''",[575,1274,1275],{"class":588}," }\n",[575,1277,1279],{"class":577,"line":1278},31,[575,1280,1089],{"class":588},[575,1282,1284,1287],{"class":577,"line":1283},32,[575,1285,1286],{"class":592},"        moveDocument",[575,1288,906],{"class":588},[575,1290,1292,1295,1297,1300],{"class":577,"line":1291},33,[575,1293,1294],{"class":742},"        deleteDocument",[575,1296,801],{"class":588},[575,1298,1299],{"class":592}," removeDocument",[575,1301,906],{"class":588},[575,1303,1305],{"class":577,"line":1304},34,[575,1306,912],{"class":588},[575,1308,1310,1313,1315,1317,1320,1322,1324,1326,1328,1330,1332,1334,1336,1338,1340,1342,1345,1347],{"class":577,"line":1309},35,[575,1311,1312],{"class":742},"      directory",[575,1314,801],{"class":588},[575,1316,589],{"class":588},[575,1318,1319],{"class":704}," listUsers",[575,1321,801],{"class":588},[575,1323,933],{"class":714},[575,1325,896],{"class":588},[575,1327,715],{"class":714},[575,1329,475],{"class":742},[575,1331,943],{"class":581},[575,1333,1319],{"class":704},[575,1335,1113],{"class":742},[575,1337,770],{"class":588},[575,1339,1118],{"class":704},[575,1341,708],{"class":742},[575,1343,1344],{"class":592},"toSessionUser",[575,1346,1027],{"class":742},[575,1348,1349],{"class":588},"},\n",[575,1351,1353,1356,1358,1360,1363,1365,1368,1370,1373],{"class":577,"line":1352},36,[575,1354,1355],{"class":742},"      collabState",[575,1357,801],{"class":588},[575,1359,589],{"class":588},[575,1361,1362],{"class":592}," loadState",[575,1364,751],{"class":588},[575,1366,1367],{"class":592}," storeState",[575,1369,751],{"class":588},[575,1371,1372],{"class":592}," removeState",[575,1374,1375],{"class":588}," },\n",[575,1377,1379,1382,1384,1386,1388,1390,1392],{"class":577,"line":1378},37,[575,1380,1381],{"class":742},"      assets",[575,1383,801],{"class":588},[575,1385,589],{"class":588},[575,1387,748],{"class":592},[575,1389,751],{"class":588},[575,1391,754],{"class":592},[575,1393,1375],{"class":588},[575,1395,1397],{"class":577,"line":1396},38,[575,1398,1399],{"class":685},"      \u002F\u002F `user` is what `authenticate` returned: the session user.\n",[575,1401,1403,1406,1408],{"class":577,"line":1402},39,[575,1404,1405],{"class":742},"      settings",[575,1407,801],{"class":588},[575,1409,718],{"class":588},[575,1411,1413,1416,1418,1421,1423,1426,1429,1431,1434,1437,1439,1441,1443,1445],{"class":577,"line":1412},40,[575,1414,1415],{"class":704},"        loadSettings",[575,1417,801],{"class":588},[575,1419,1420],{"class":830}," user",[575,1422,715],{"class":714},[575,1424,1425],{"class":704}," getUserSettings",[575,1427,1428],{"class":742},"((",[575,1430,887],{"class":592},[575,1432,1433],{"class":581}," as",[575,1435,593],{"class":1436},"sBMFI",[575,1438,867],{"class":742},[575,1440,770],{"class":588},[575,1442,951],{"class":592},[575,1444,867],{"class":742},[575,1446,906],{"class":588},[575,1448,1450,1453,1455,1457,1459,1461,1464,1466,1468,1471,1473,1475,1477,1479,1481,1483,1485,1487,1489,1491],{"class":577,"line":1449},41,[575,1451,1452],{"class":704},"        storeSettings",[575,1454,801],{"class":588},[575,1456,475],{"class":588},[575,1458,887],{"class":830},[575,1460,751],{"class":588},[575,1462,1463],{"class":830}," settings",[575,1465,867],{"class":588},[575,1467,715],{"class":714},[575,1469,1470],{"class":704}," putUserSettings",[575,1472,1428],{"class":742},[575,1474,887],{"class":592},[575,1476,1433],{"class":581},[575,1478,593],{"class":1436},[575,1480,867],{"class":742},[575,1482,770],{"class":588},[575,1484,951],{"class":592},[575,1486,751],{"class":588},[575,1488,1463],{"class":592},[575,1490,867],{"class":742},[575,1492,906],{"class":588},[575,1494,1496],{"class":577,"line":1495},42,[575,1497,912],{"class":588},[575,1499,1501,1504,1506,1508,1511,1513,1516,1518,1521,1523,1526],{"class":577,"line":1500},43,[575,1502,1503],{"class":742},"      themes",[575,1505,801],{"class":588},[575,1507,589],{"class":588},[575,1509,1510],{"class":592}," listThemes",[575,1512,751],{"class":588},[575,1514,1515],{"class":592}," loadTheme",[575,1517,751],{"class":588},[575,1519,1520],{"class":592}," storeTheme",[575,1522,751],{"class":588},[575,1524,1525],{"class":592}," removeTheme",[575,1527,1375],{"class":588},[575,1529,1531],{"class":577,"line":1530},44,[575,1532,1533],{"class":685},"      \u002F\u002F Block index (`index` capability): a projection of the documents above, rebuilt on start and kept current by the editor server; in memory (memory adapter, PGlite with `NUXT_BLOCK_INDEX=pglite`, or PGlite with trigram search and vectors with `NUXT_BLOCK_INDEX=pg-vector`), so nothing to migrate.\n",[575,1535,1537,1540,1542,1545,1547,1549,1551,1554,1556,1559,1561,1563,1565,1568,1570],{"class":577,"line":1536},45,[575,1538,1539],{"class":742},"      index",[575,1541,801],{"class":588},[575,1543,1544],{"class":704}," createHostBlockIndex",[575,1546,708],{"class":742},[575,1548,778],{"class":592},[575,1550,770],{"class":588},[575,1552,1553],{"class":592},"ports",[575,1555,770],{"class":588},[575,1557,1558],{"class":592},"embeddings",[575,1560,751],{"class":588},[575,1562,733],{"class":592},[575,1564,770],{"class":588},[575,1566,1567],{"class":592},"embeddingsError",[575,1569,867],{"class":742},[575,1571,906],{"class":588},[575,1573,1575],{"class":577,"line":1574},46,[575,1576,1577],{"class":685},"      \u002F\u002F Prüfung records (`pruefung` capability): the editor's JSON store on `\u003Cdocuments dir>\u002F.pruefung.json`, a dot-named file the document store never lists.\n",[575,1579,1581,1584,1586,1588,1590,1592,1595,1597,1600,1602,1604,1606,1608,1611],{"class":577,"line":1580},47,[575,1582,1583],{"class":742},"      pruefung",[575,1585,801],{"class":588},[575,1587,619],{"class":704},[575,1589,708],{"class":742},[575,1591,745],{"class":588},[575,1593,1594],{"class":742}," dir",[575,1596,801],{"class":588},[575,1598,1599],{"class":704}," storeRoot",[575,1601,1078],{"class":742},[575,1603,1081],{"class":588},[575,1605,867],{"class":742},[575,1607,770],{"class":588},[575,1609,1610],{"class":592},"pruefung",[575,1612,906],{"class":588},[575,1614,1616],{"class":577,"line":1615},48,[575,1617,1618],{"class":685},"      \u002F\u002F Change sets of the document chat (`changeSets` capability): what the model proposed for other Documents, decided per Document; `\u003Cdocuments dir>\u002F.change-sets.json`, likewise dot-named.\n",[575,1620,1622,1625,1627,1629,1631,1633,1635,1637,1639,1641,1643,1645,1647,1650],{"class":577,"line":1621},49,[575,1623,1624],{"class":742},"      changeSets",[575,1626,801],{"class":588},[575,1628,619],{"class":704},[575,1630,708],{"class":742},[575,1632,745],{"class":588},[575,1634,1594],{"class":742},[575,1636,801],{"class":588},[575,1638,1599],{"class":704},[575,1640,1078],{"class":742},[575,1642,1081],{"class":588},[575,1644,867],{"class":742},[575,1646,770],{"class":588},[575,1648,1649],{"class":592},"changeSets",[575,1651,906],{"class":588},[575,1653,1655],{"class":577,"line":1654},50,[575,1656,1657],{"class":685},"      \u002F\u002F Demo of the model port (`DEMO_STUB_MODEL=1`): the stub answers `{ preset: 'stub' }`; `null` for anything else falls through to the environment presets.\n",[575,1659,1661,1664,1666],{"class":577,"line":1660},51,[575,1662,1663],{"class":742},"      models",[575,1665,801],{"class":588},[575,1667,718],{"class":588},[575,1669,1671,1674,1676,1678,1681,1683,1686,1688,1691,1693,1696,1699,1702,1704,1707,1709,1711,1713,1716,1719,1722,1725,1728],{"class":577,"line":1670},52,[575,1672,1673],{"class":704},"        languageModel",[575,1675,801],{"class":588},[575,1677,933],{"class":714},[575,1679,1680],{"class":830}," ref",[575,1682,715],{"class":714},[575,1684,1685],{"class":704}," stubModelEnabled",[575,1687,1078],{"class":742},[575,1689,1690],{"class":588},"&&",[575,1692,602],{"class":588},[575,1694,1695],{"class":605},"preset",[575,1697,1698],{"class":588},"'",[575,1700,1701],{"class":588}," in",[575,1703,1680],{"class":592},[575,1705,1706],{"class":588}," &&",[575,1708,1680],{"class":592},[575,1710,770],{"class":588},[575,1712,1695],{"class":592},[575,1714,1715],{"class":588}," ===",[575,1717,1718],{"class":592}," STUB_MODEL_ID",[575,1720,1721],{"class":588}," ?",[575,1723,1724],{"class":592}," stubLanguageModel",[575,1726,1727],{"class":588}," :",[575,1729,965],{"class":588},[575,1731,1733,1736,1738,1740,1742,1744,1746,1748,1751,1754,1757,1760,1762,1764,1767,1770,1772],{"class":577,"line":1732},53,[575,1734,1735],{"class":704},"        listModels",[575,1737,801],{"class":588},[575,1739,933],{"class":714},[575,1741,896],{"class":588},[575,1743,715],{"class":714},[575,1745,1685],{"class":704},[575,1747,1078],{"class":742},[575,1749,1750],{"class":588},"?",[575,1752,1753],{"class":742}," [",[575,1755,1756],{"class":588},"...",[575,1758,1759],{"class":704},"publicEnvPresets",[575,1761,711],{"class":742},[575,1763,751],{"class":588},[575,1765,1766],{"class":592}," stubModelProfile",[575,1768,1769],{"class":742},"] ",[575,1771,801],{"class":588},[575,1773,965],{"class":588},[575,1775,1777],{"class":577,"line":1776},54,[575,1778,912],{"class":588},[575,1780,1782,1785,1787,1789,1791],{"class":577,"line":1781},55,[575,1783,1784],{"class":588},"      ...",[575,1786,778],{"class":592},[575,1788,770],{"class":588},[575,1790,1553],{"class":592},[575,1792,906],{"class":588},[575,1794,1796],{"class":577,"line":1795},56,[575,1797,1798],{"class":588},"    },\n",[575,1800,1802,1805,1807,1809,1811,1814,1816,1818,1821,1823,1825,1827,1829,1831,1833],{"class":577,"line":1801},57,[575,1803,1804],{"class":588},"    ...",[575,1806,708],{"class":742},[575,1808,778],{"class":592},[575,1810,770],{"class":588},[575,1812,1813],{"class":592},"blockTypes",[575,1815,1706],{"class":588},[575,1817,589],{"class":588},[575,1819,1820],{"class":742}," blockTypes",[575,1822,801],{"class":588},[575,1824,733],{"class":592},[575,1826,770],{"class":588},[575,1828,1813],{"class":592},[575,1830,596],{"class":588},[575,1832,867],{"class":742},[575,1834,906],{"class":588},[575,1836,1838],{"class":577,"line":1837},58,[575,1839,1840],{"class":685},"    \u002F\u002F The document chat's read-only workspace tools (`find_blocks`, `read_block`): the model finds and reads Blocks of the user's other Documents through the block index above.\n",[575,1842,1844,1847,1849,1851,1853,1855,1857,1859,1861,1863,1865,1867,1869,1871,1873,1875,1877],{"class":577,"line":1843},59,[575,1845,1846],{"class":742},"    tools",[575,1848,801],{"class":588},[575,1850,661],{"class":704},[575,1852,708],{"class":742},[575,1854,778],{"class":592},[575,1856,770],{"class":588},[575,1858,1813],{"class":592},[575,1860,1706],{"class":588},[575,1862,589],{"class":588},[575,1864,1820],{"class":742},[575,1866,801],{"class":588},[575,1868,733],{"class":592},[575,1870,770],{"class":588},[575,1872,1813],{"class":592},[575,1874,596],{"class":588},[575,1876,867],{"class":742},[575,1878,906],{"class":588},[575,1880,1882,1885],{"class":577,"line":1881},60,[575,1883,1884],{"class":588},"  }",[575,1886,1010],{"class":742},[575,1888,1890,1892],{"class":577,"line":1889},61,[575,1891,1081],{"class":588},[575,1893,1010],{"class":592},[418,1895,1897],{"id":1896},"capability-probe","Capability probe",[423,1899,1900,1901,1904,1905,1908,1909,1911,1912,1914,1915,1917,1918,1921,1922,1925,1926,1929,1930,1933,1934,1937,1938,1941,1942,1945,1946,1949,1950,1952],{},"By default the HTTP backend assumes every capability and a feature whose route the server does not mount fails on use (404\u002F501). ",[436,1902,1903],{},"createHttpBackend({ probe: true })"," instead asks ",[436,1906,1907],{},"GET \u002Fapi\u002Feditor\u002Fcapabilities"," once, drops the backend fields the server does not list (",[436,1910,530],{}," without a comments port, ",[436,1913,524],{}," without a themes port, ",[436,1916,527],{}," without configured models, …) and exposes the request as ",[436,1919,1920],{},"backend.ready",", which ",[436,1923,1924],{},"createEditorContext"," awaits before it reports ",[436,1927,1928],{},"ready","; so ",[436,1931,1932],{},"composeEditor(…, { backend })"," prunes exactly what the server lacks, reported in ",[436,1935,1936],{},"omitted",". Compose after ",[436,1939,1940],{},"await backend.ready"," (the Nuxt plugin does: it installs the context with ",[436,1943,1944],{},"probe: true"," and finishes only then). A failed probe (offline, 401, an answer that is no list) keeps every capability and warns once on the console (",[436,1947,1948],{},"@skaile\u002Fforge-editor: the capability probe …","). The Nuxt module passes ",[436,1951,1944],{},"; a Vite or bare Nitro host opts in.",[418,1954,1956],{"id":1955},"capability-locality","Capability locality",[423,1958,1959,1960,1962],{},"Every capability of ",[436,1961,502],{}," falls in one of three classes, by what a server is needed for. The class is derived from the adapters, not a runtime setting; it tells you which capabilities a client-only host keeps and which it gives up:",[1964,1965,1966,1982],"table",{},[1967,1968,1969],"thead",{},[1970,1971,1972,1976,1979],"tr",{},[1973,1974,1975],"th",{},"Class",[1973,1977,1978],{},"Meaning",[1973,1980,1981],{},"Capabilities",[1983,1984,1985,2026,2077],"tbody",{},[1970,1986,1987,1993,1996],{},[1988,1989,1990],"td",{},[436,1991,1992],{},"local",[1988,1994,1995],{},"works in the page; a server only makes it durable or shared",[1988,1997,1998,467,2000,467,2002,467,2004,467,2006,2008,2009,2015,2016,2019,2020,2022,2023,2025],{},[436,1999,506],{},[436,2001,512],{},[436,2003,515],{},[436,2005,518],{},[436,2007,521],{}," (all served by ",[2010,2011,2012],"a",{"href":146},[436,2013,2014],{},"createMemoryBackend","; documents, uploaded files as ",[436,2017,2018],{},"blob:"," URLs and settings last as long as the page); ",[436,2021,524],{}," (in the page only through a host-written ",[436,2024,524],{}," member: the memory backend ships none)",[1970,2027,2028,2033,2036],{},[1988,2029,2030],{},[436,2031,2032],{},"relay",[1988,2034,2035],{},"a server only holds a secret and enforces a limit; the work itself can run in the page",[1988,2037,2038,2040,2041,2044,2045,2048,2049,2052,2053,467,2056,467,2059,2062,2063,2066,2067,2062,2070,2073,2074,2076],{},[436,2039,527],{},": the server keeps the model key and applies the per-user rate limit (",[436,2042,2043],{},"ai.rateLimit"," of the ",[2010,2046,2047],{"href":293},"configuration","), then calls the model. ",[436,2050,2051],{},"createDirectAi"," makes ",[436,2054,2055],{},"generate",[436,2057,2058],{},"complete",[436,2060,2061],{},"models"," and ",[436,2064,2065],{},"transcriptCleanup"," local, at the price of the key in the browser and no rate limit; ",[436,2068,2069],{},"chat",[436,2071,2072],{},"extract"," stay server-only. ",[436,2075,533],{},": the host's provider holds the image-model key, stores the generated and uploaded files and keeps the prompt blocks; there is no browser-direct variant",[1970,2078,2079,2084,2087],{},[1988,2080,2081],{},[436,2082,2083],{},"session",[1988,2085,2086],{},"a server owns live state that several clients share",[1988,2088,2089,2091,2092,2094],{},[436,2090,509],{}," (the Hocuspocus server holds the Yjs document), ",[436,2093,530],{}," (the comments endpoint holds the threads)",[423,2096,2097,2098,2101,2102,2106,2107,2109,2110,2112,2113,2115,2116,2118,2119,467,2122,2062,2124,2126,2127,770],{},"A client-only composition is ",[436,2099,2100],{},"{ ...createMemoryBackend(), ai: createDirectAi({ presets }) }"," (see ",[2010,2103,2105],{"href":2104},"\u002Fguides\u002Fstorage-adapters#browser-direct-ai","Browser-direct AI","): the ",[436,2108,1992],{}," capabilities the memory backend serves plus a locally running ",[436,2111,527],{},", no ",[436,2114,2083],{}," capability. ",[436,2117,1932],{}," then prunes ",[436,2120,2121],{},"collab",[436,2123,530],{},[436,2125,524],{},", reported in ",[436,2128,1936],{},[418,2130,2132],{"id":2131},"port-members","Port members",[1964,2134,2135,2154],{},[1967,2136,2137],{},[1970,2138,2139,2142,2145,2148,2151],{},[1973,2140,2141],{},"Port",[1973,2143,2144],{},"Member",[1973,2146,2147],{},"Signature",[1973,2149,2150],{},"Called",[1973,2152,2153],{},"Must return",[1983,2155,2156,2205,2233,2262,2286,2322,2356,2379,2409,2444,2480,2515,2542,2571,2595,2627,2657,2684,2716,2758,2802,2826,2854,2884],{},[1970,2157,2158,2162,2166,2171,2186],{},[1988,2159,2160],{},[436,2161,429],{},[1988,2163,2164],{},[436,2165,438],{},[1988,2167,2168],{},[436,2169,2170],{},"(request: { headers: Headers, token?: string }) => Promise\u003Cobject | null>",[1988,2172,2173,2174,2177,2178,2181,2182,2185],{},"Collab websocket (Hocuspocus ",[436,2175,2176],{},"onAuthenticate","; ",[436,2179,2180],{},"token"," is the client's ",[436,2183,2184],{},"collaboration.token",", absent for HTTP routes and token-less clients); first in every API route that needs a user",[1988,2187,2188,2189,2191,2192,2194,2195,2197,2198,2200,2201,2204],{},"The user, or ",[436,2190,442],{}," (→ 401). The value becomes the Hocuspocus connection context's ",[436,2193,887],{},", the ",[436,2196,887],{}," argument of the settings methods and the rate-limit key (",[436,2199,951],{},", else ",[436,2202,2203],{},"username",", else its JSON).",[1970,2206,2207,2211,2216,2221,2227],{},[1988,2208,2209],{},[436,2210,506],{},[1988,2212,2213],{},[436,2214,2215],{},"loadContent",[1988,2217,2218],{},[436,2219,2220],{},"(id) => Promise\u003CJSONContent | null>",[1988,2222,2223,2226],{},[436,2224,2225],{},"onLoadDocument",", when no usable Yjs state exists (new, legacy or restored document)",[1988,2228,2229,2230,2232],{},"TipTap JSON to seed the Y.Doc from, as stored (the editor migrates it to the current shape itself, see below); ",[436,2231,442],{}," = the document does not exist (connection closed)",[1970,2234,2235,2239,2244,2249,2259],{},[1988,2236,2237],{},[436,2238,506],{},[1988,2240,2241],{},[436,2242,2243],{},"storeContent",[1988,2245,2246],{},[436,2247,2248],{},"(id, content) => Promise\u003Cvoid>",[1988,2250,2251,2254,2255,2258],{},[436,2252,2253],{},"onStoreDocument"," (debounced after edits, and on shutdown via the Nitro ",[436,2256,2257],{},"close"," hook)",[1988,2260,2261],{},"Mirrors the JSON; tolerate ids deleted meanwhile",[1970,2263,2264,2268,2273,2278,2283],{},[1988,2265,2266],{},[436,2267,506],{},[1988,2269,2270],{},[436,2271,2272],{},"listContents",[1988,2274,2275],{},[436,2276,2277],{},"() => Promise\u003C{ id, content }[]>",[1988,2279,2280],{},[436,2281,2282],{},"GET \u002Fapi\u002Feditor\u002Ftags",[1988,2284,2285],{},"Stored JSON of every document, as stored",[1970,2287,2288,2293,2298,2306,2315],{},[1988,2289,2290],{},[436,2291,2292],{},"directory",[1988,2294,2295],{},[436,2296,2297],{},"listUsers",[1988,2299,2300,475,2303,867],{},[436,2301,2302],{},"() => Promise\u003CMentionUser[]>",[436,2304,2305],{},"{ id, username, color }",[1988,2307,2308,467,2311,2314],{},[436,2309,2310],{},"GET \u002Fapi\u002Feditor\u002Fusers",[436,2312,2313],{},"POST \u002Fapi\u002Fai\u002Fgenerate"," for tasks that need users",[1988,2316,2317,2318,2321],{},"Every user that can be ",[436,2319,2320],{},"@","-mentioned, no credentials",[1970,2323,2324,2329,2334,2339,2343],{},[1988,2325,2326],{},[436,2327,2328],{},"collabState",[1988,2330,2331],{},[436,2332,2333],{},"loadState",[1988,2335,2336],{},[436,2337,2338],{},"(id) => Promise\u003CUint8Array | null>",[1988,2340,2341],{},[436,2342,2225],{},[1988,2344,2345,2346,2349,2350,2352,2353,2355],{},"The bytes ",[436,2347,2348],{},"storeState"," received, unchanged (the Yjs update behind a content-version prefix; state from earlier releases is a raw update and loads as version ",[436,2351,442],{},"); ",[436,2354,442],{}," = none yet",[1970,2357,2358,2362,2366,2371,2376],{},[1988,2359,2360],{},[436,2361,2328],{},[1988,2363,2364],{},[436,2365,2348],{},[1988,2367,2368],{},[436,2369,2370],{},"(id, state) => Promise\u003Cvoid>",[1988,2372,2373,2375],{},[436,2374,2253],{},", and right after a Y.Doc was seeded or block IDs were backfilled",[1988,2377,2378],{},"Persist; tolerate deleted ids",[1970,2380,2381,2385,2390,2395,2406],{},[1988,2382,2383],{},[436,2384,2328],{},[1988,2386,2387],{},[436,2388,2389],{},"removeState",[1988,2391,2392],{},[436,2393,2394],{},"(id) => Promise\u003Cvoid>",[1988,2396,2397,482,2400,2402,2403,867],{},[436,2398,2399],{},"EditorServer.forgetDocument",[436,2401,2225],{}," when the stored state is stale (",[436,2404,2405],{},"contentVersion",[1988,2407,2408],{},"Drop the state of a deleted or rewritten document",[1970,2410,2411,2415,2420,2425,2435],{},[1988,2412,2413],{},[436,2414,429],{},[1988,2416,2417],{},[436,2418,2419],{},"authorize?",[1988,2421,2422],{},[436,2423,2424],{},"(user, id) => Promise\u003C{ readOnly: boolean } | null>",[1988,2426,2427,2428,2431,2432,2434],{},"Hocuspocus ",[436,2429,2430],{},"onConnect",", with the object ",[436,2433,438],{}," returned",[1988,2436,2437,2439,2440,2443],{},[436,2438,442],{}," rejects the connection (permission denied); ",[436,2441,2442],{},"{ readOnly: true }"," lets it sync but applies none of its edits. Omit: every authenticated user may edit every document",[1970,2445,2446,2450,2455,2460,2468],{},[1988,2447,2448],{},[436,2449,506],{},[1988,2451,2452],{},[436,2453,2454],{},"contentVersion?",[1988,2456,2457],{},[436,2458,2459],{},"(id) => Promise\u003Cstring | null>",[1988,2461,2462,2464,2465,2467],{},[436,2463,2225],{},"; right after every ",[436,2466,2243],{},"; before every store of an open document",[1988,2469,2470,2471,2473,2474,2476,2477,2479],{},"Opaque version of the stored content (mtime, hash, revision; no NUL character), ",[436,2472,442],{}," = unknown. A stored state with another version is discarded and the document is re-seeded from ",[436,2475,2215],{},"; an open document whose version moved is merged with ",[436,2478,2215],{}," on its next store instead of being written back. Omit: state is never discarded",[1970,2481,2482,2486,2491,2496,2501],{},[1988,2483,2484],{},[436,2485,512],{},[1988,2487,2488],{},[436,2489,2490],{},"storeAsset",[1988,2492,2493],{},[436,2494,2495],{},"(id, asset: AssetRecord & { data: Buffer }) => Promise\u003Cvoid>",[1988,2497,2498],{},[436,2499,2500],{},"POST \u002Fapi\u002Feditor\u002Fassets\u002F:id",[1988,2502,2503,2504,2507,2508,2510,2511,2514],{},"Persist the file under ",[436,2505,2506],{},"asset.name"," with its record. ",[436,2509,951],{}," is a document id or ",[436,2512,2513],{},"scratch","; it need not name an existing document.",[1970,2516,2517,2521,2526,2531,2536],{},[1988,2518,2519],{},[436,2520,512],{},[1988,2522,2523],{},[436,2524,2525],{},"loadAsset",[1988,2527,2528],{},[436,2529,2530],{},"(id, name) => Promise\u003C{ record, data } | null>",[1988,2532,2533],{},[436,2534,2535],{},"GET \u002Fapi\u002Feditor\u002Fassets\u002F:id\u002F:name",[1988,2537,2538,2539,2541],{},"The stored file; ",[436,2540,442],{}," → 404",[1970,2543,2544,2548,2553,2558,2563],{},[1988,2545,2546],{},[436,2547,521],{},[1988,2549,2550],{},[436,2551,2552],{},"loadSettings",[1988,2554,2555],{},[436,2556,2557],{},"(user) => Promise\u003Cunknown | null>",[1988,2559,2560],{},[436,2561,2562],{},"GET \u002Fapi\u002Feditor\u002Fsettings",[1988,2564,2565,2566,2568,2569],{},"Stored settings (normalized by the route), ",[436,2567,442],{}," = none yet. Port absent: the settings routes are not mounted, settings stay in ",[436,2570,550],{},[1970,2572,2573,2577,2582,2587,2592],{},[1988,2574,2575],{},[436,2576,521],{},[1988,2578,2579],{},[436,2580,2581],{},"storeSettings",[1988,2583,2584],{},[436,2585,2586],{},"(user, settings) => Promise\u003Cvoid>",[1988,2588,2589],{},[436,2590,2591],{},"PUT \u002Fapi\u002Feditor\u002Fsettings",[1988,2593,2594],{},"Persist the validated settings",[1970,2596,2597,2601,2606,2611,2616],{},[1988,2598,2599],{},[436,2600,524],{},[1988,2602,2603],{},[436,2604,2605],{},"listThemes",[1988,2607,2608],{},[436,2609,2610],{},"() => Promise\u003CThemeRecord[]>",[1988,2612,2613],{},[436,2614,2615],{},"GET \u002Fapi\u002Feditor\u002Fthemes",[1988,2617,2618,2619,2622,2623,2626],{},"The shared theme library (",[436,2620,2621],{},"{ id, name, version?, author?, authorUrl?, builtin }","), host-seeded themes marked ",[436,2624,2625],{},"builtin: true",". Port absent: the themes routes are not mounted",[1970,2628,2629,2633,2638,2643,2648],{},[1988,2630,2631],{},[436,2632,524],{},[1988,2634,2635],{},[436,2636,2637],{},"loadTheme",[1988,2639,2640],{},[436,2641,2642],{},"(id) => Promise\u003C{ record, css } | null>",[1988,2644,2645],{},[436,2646,2647],{},"GET \u002Fapi\u002Feditor\u002Fthemes\u002F:id",[1988,2649,2650,2651,2654,2655,2541],{},"The theme's ",[436,2652,2653],{},"theme.css"," text with its record; ",[436,2656,442],{},[1970,2658,2659,2663,2668,2673,2678],{},[1988,2660,2661],{},[436,2662,524],{},[1988,2664,2665],{},[436,2666,2667],{},"storeTheme",[1988,2669,2670],{},[436,2671,2672],{},"(record: Omit\u003CThemeRecord, 'builtin'>, css) => Promise\u003Cvoid>",[1988,2674,2675],{},[436,2676,2677],{},"POST \u002Fapi\u002Feditor\u002Fthemes",[1988,2679,2680,2681,770],{},"Persist an uploaded theme. The route has already validated the content and chosen a unique ",[436,2682,2683],{},"record.id",[1970,2685,2686,2690,2695,2700,2705],{},[1988,2687,2688],{},[436,2689,524],{},[1988,2691,2692],{},[436,2693,2694],{},"removeTheme",[1988,2696,2697],{},[436,2698,2699],{},"(id) => Promise\u003Cboolean>",[1988,2701,2702],{},[436,2703,2704],{},"DELETE \u002Fapi\u002Feditor\u002Fthemes\u002F:id",[1988,2706,2707,2708,2711,2712,2715],{},"Delete an upload; ",[436,2709,2710],{},"false"," = unknown id or builtin (the route has checked ",[436,2713,2714],{},"listThemes()"," first and answers 403 \u002F 404 itself)",[1970,2717,2718,2722,2727,2732,2739],{},[1988,2719,2720],{},[436,2721,2061],{},[1988,2723,2724],{},[436,2725,2726],{},"languageModel?",[1988,2728,2729],{},[436,2730,2731],{},"(ref: ModelRef, user) => Promise\u003CLanguageModel | null>",[1988,2733,2734,2735,2738],{},"Every AI endpoint (",[436,2736,2737],{},"\u002Fapi\u002Fai\u002F{generate,chat,complete,transcript-cleanup}","), before the runtime-config Model presets",[1988,2740,2741,2742,475,2745,2748,2749,2751,2752,2754,2755,2757],{},"The AI SDK language model for ",[436,2743,2744],{},"ref",[436,2746,2747],{},"{ preset }"," or a user Model profile's endpoint\u002Fmodel\u002Fkey), so the host's own providers serve the editor. ",[436,2750,887],{}," is what ",[436,2753,438],{}," returned. ",[436,2756,442],{}," falls through to the Model presets (400 for an unknown preset)",[1970,2759,2760,2764,2769,2774,2779],{},[1988,2761,2762],{},[436,2763,2061],{},[1988,2765,2766],{},[436,2767,2768],{},"listModels?",[1988,2770,2771],{},[436,2772,2773],{},"(user) => Promise\u003CModelProfile[] | null>",[1988,2775,2776],{},[436,2777,2778],{},"GET \u002Fapi\u002Fai\u002Fmodels",[1988,2780,2781,2782,2784,2785,2788,2789,2791,2792,2795,2796,534,2799,2801],{},"The models offered to ",[436,2783,887],{},", replacing the Model preset list (list them with ",[436,2786,2787],{},"source: 'preset'"," and the ",[436,2790,951],{}," that ",[436,2793,2794],{},"languageModel"," receives as ",[436,2797,2798],{},"{ preset: id }",[436,2800,442],{}," lists the runtime-config Model presets",[1970,2803,2804,2808,2814,2820,2823],{},[1988,2805,2806],{},[436,2807,530],{},[1988,2809,2810,2811],{},"the ",[436,2812,2813],{},"CommentStore",[1988,2815,2816,2817],{},"see ",[2010,2818,2819],{"href":146},"Storage adapters",[1988,2821,2822],{},"the comments routes (Nitro host only)",[1988,2824,2825],{},"The comment store",[1970,2827,2828,2832,2837,2842,2847],{},[1988,2829,2830],{},[436,2831,533],{},[1988,2833,2834],{},[436,2835,2836],{},"promptBlocks",[1988,2838,2839],{},[436,2840,2841],{},"(user) => Promise\u003CImageStudioPromptBlock[]>",[1988,2843,2844],{},[436,2845,2846],{},"GET \u002Fapi\u002Feditor\u002Fimages\u002Fprompt-blocks",[1988,2848,2849,2850,2853],{},"The prompt blocks (",[436,2851,2852],{},"{ id, label, text }",": style, brand, …) the host manages, in its order. Port absent: the image routes are not mounted",[1970,2855,2856,2860,2864,2869,2874],{},[1988,2857,2858],{},[436,2859,533],{},[1988,2861,2862],{},[436,2863,2055],{},[1988,2865,2866],{},[436,2867,2868],{},"(body: ImageStudioGenerateBody, user) => Promise\u003CImageStudioImage>",[1988,2870,2871],{},[436,2872,2873],{},"POST \u002Fapi\u002Feditor\u002Fimages\u002Fgenerate",[1988,2875,2876,2877,2880,2881],{},"Generates and stores one image from ",[436,2878,2879],{},"{ description, instruction, promptBlockIds, referenceUrls }","; the host builds the prompt. Answers ",[436,2882,2883],{},"{ id, url, title, active }",[1970,2885,2886,2890,2895,2900,2905],{},[1988,2887,2888],{},[436,2889,533],{},[1988,2891,2892],{},[436,2893,2894],{},"upload",[1988,2896,2897],{},[436,2898,2899],{},"(documentId, file: File, user) => Promise\u003CImageStudioImage>",[1988,2901,2902],{},[436,2903,2904],{},"POST \u002Fapi\u002Feditor\u002Fimages\u002Fupload",[1988,2906,2907,2908,2911,2912,2915,2916,467,2919,2922],{},"Stores an uploaded reference image of document ",[436,2909,2910],{},"documentId",". The route has checked the id, that the file is an image and its size (",[436,2913,2914],{},"413"," above ",[436,2917,2918],{},"MAX_MEDIA_BYTES.image",[436,2920,2921],{},"415"," for other types)",[423,2924,2925,2926,2062,2929,2932,2933,2936,2937,2940,2941,2352,2944,2947,2948,2044,2951,2954,2955,2958,2959,2961],{},"The collaboration schema is not part of storage: ",[436,2927,2928],{},"createCollabServer({ ports, schema })",[436,2930,2931],{},"installEditorServer"," take ",[436,2934,2935],{},"schema?: () => AnyExtension[]"," (default ",[436,2938,2939],{},"advancedSchemaExtensions()","; host nodes: ",[436,2942,2943],{},"() => [...advancedSchemaExtensions(), Callout]",[436,2945,2946],{},"provideEditorServer({ ports, schema })"," (Nuxt) takes the same option, and ",[436,2949,2950],{},"server.collab?.stats()",[436,2952,2953],{},"EditorServer"," handle returns ",[436,2956,2957],{},"{ connections, documents }"," of the running server. The collab server needs the ",[436,2960,2328],{}," port and throws „@skaile\u002Fforge-editor: collaboration needs the collabState port“ without it.",[423,2963,2964,2965,2062,2968,2971,2972,2974,2975,2978,2979,2982],{},"The host's Block types are not storage either; ",[436,2966,2967],{},"installEditorServer({ blockTypes })",[436,2969,2970],{},"provideEditorServer({ ports, blockTypes })"," take the list the editors get through ",[436,2973,1813],{}," (for instance loaded from a JSON file, see ",[2010,2976,165],{"href":2977},"\u002Fguides\u002Fblock-types#the-server","), so the AI chat describes them to the model instead of the ",[436,2980,2981],{},"kinds"," the client sends.",[423,2984,2985,2986,2988,2989,2991],{},"Omit the ",[436,2987,521],{}," port to keep settings in the browser only (the settings routes are not mounted; the client falls back to ",[436,2990,550],{},").",[423,2993,2994,2995,2062,2997,2999,3000,3002,3003,3005,3006,2788,3009,3012,3013,3016,3017,3020,3021,475,3023,3026,3027,3030,3031,3033,3034,3036,3037,3039],{},"The theme methods ",[436,2996,2667],{},[436,2998,2694],{}," are only needed for uploads; without them the upload and delete routes answer 501 while builtins stay selectable. Without the ",[436,3001,524],{}," port the routes are not mounted and the ",[436,3004,524],{}," feature falls back to the Default appearance (a console warning, the stored setting stays). ",[436,3007,3008],{},"ThemeRecord",[436,3010,3011],{},"THEME_ID"," pattern come from the Vue-free ",[436,3014,3015],{},"@skaile\u002Fforge-editor\u002Fthemes\u002Fschema",". The demo host keeps builtins in ",[436,3018,3019],{},"server\u002Fthemes\u002F\u003Cid>\u002F{manifest.json,theme.css}"," (git-tracked, read-only) and uploads in the Nitro storage mount ",[436,3022,524],{},[436,3024,3025],{},".data\u002Fthemes\u002F\u003Cid>\u002F{manifest.json,theme.css}",", configured in ",[436,3028,3029],{},"nuxt.config.ts","), so uploads survive restarts; ",[436,3032,2605],{}," returns builtins and then uploads, ",[436,3035,2637],{}," checks builtins first, ",[436,3038,2694],{}," refuses builtins.",[418,3041,3043],{"id":3042},"deleting-a-document","Deleting a document",[423,3045,3046,3049,3050,3053,3054,3057,3058,3061,3062,2044,3065,3067,3068,3070,3071,3074,3075,3078,3079,3081],{},[436,3047,3048],{},"DELETE \u002Fapi\u002Feditor\u002Fdocuments\u002F:id"," does it all: it calls ",[436,3051,3052],{},"forgetDocument"," of the collaboration server (stateless message ",[436,3055,3056],{},"deleted"," to connected clients, connections closed, a pending store blocked from writing the state back) and then ",[436,3059,3060],{},"DocumentAdmin.deleteDocument",", which also drops the document's Yjs state and its Blocks from the index. A host route that removes a document itself calls ",[436,3063,3064],{},"forgetDocument(id)",[436,3066,2953],{}," handle (",[436,3069,2931],{}," returns it; a Nuxt host's routes get it from ",[436,3072,3073],{},"useEditorServer()",") before removing the JSON. ",[436,3076,3077],{},"liveContent(id)"," of the handle returns the current content of a document that is open in Hocuspocus (unsaved edits included), ",[436,3080,442],{}," when nobody has it open.",[418,3083,3085],{"id":3084},"listing-creating-and-moving-documents","Listing, creating and moving documents",[423,3087,3088,3089,3092,3093,467,3096,2062,3099,3102,3103,3106,3107,467,3110,2062,3113,3116,3117,3120,3121,3123,3124,3126],{},"A documents port whose documents live in folders implements three optional ",[436,3090,3091],{},"DocumentAdmin"," members: ",[436,3094,3095],{},"listTree(): TreeFolder",[436,3097,3098],{},"createDocument({ title?, folder? }): DocumentSummary",[436,3100,3101],{},"moveDocument(id, folder)",". They serve ",[436,3104,3105],{},"GET \u002Fapi\u002Feditor\u002Fdocuments"," (the Documents the user may read, newest first), ",[436,3108,3109],{},"GET \u002Fapi\u002Feditor\u002Ftree",[436,3111,3112],{},"POST \u002Fapi\u002Feditor\u002Fdocuments",[436,3114,3115],{},"PUT \u002Fapi\u002Feditor\u002Fdocuments\u002F:id\u002Ffolder","; without them these routes answer 501. A ",[436,3118,3119],{},"DocumentStore"," for the file tree (see the document tree guide) is a client of exactly these routes plus ",[436,3122,3048],{},"; the reference app's ",[436,3125,446],{}," serves them over its package store.",[418,3128,3130],{"id":3129},"changing-a-document-from-the-server","Changing a document from the server",[423,3132,3133,3136,3137,3140,3141,467,3144,467,3147,467,3150,3153,3154,3157,3158,3161,3162,3165,3166,3169,3170,2177,3172,3175,3176,3179,3180,3183,3184,3186,3187,3190,3191,3194,3195,3198,3199,3202,3203,3206,3207,770],{},[436,3134,3135],{},"POST \u002Fapi\u002Feditor\u002Fdocuments\u002F:id\u002Fops"," with ",[436,3138,3139],{},"{ ops }"," applies block operations (",[436,3142,3143],{},"update",[436,3145,3146],{},"add",[436,3148,3149],{},"delete",[436,3151,3152],{},"convert",": the shape of the document chat's ",[436,3155,3156],{},"edit_document"," tool, ",[436,3159,3160],{},"ModelAgentOp",") to a document nobody has to have open, all or none. The ",[436,3163,3164],{},"DocumentMutator"," behind it (",[436,3167,3168],{},"createDocumentMutator({ ports, collab, schema, blockTypes, reindex })"," of ",[436,3171,670],{},[436,3173,3174],{},"EditorServer.mutator"," of the installed server) checks every operation against the block IDs of the document (",[436,3177,3178],{},"checkAgentOps","), parses the Markdown without an editor (",[436,3181,3182],{},"createMarkdownBlocks","), changes an open document inside its Y.Doc (connected clients see an ordinary edit) and a stored one through ",[436,3185,2243],{},", and re-projects the Block index either way. Refusals: ",[436,3188,3189],{},"403"," for a read-only user, ",[436,3192,3193],{},"404"," for an unknown document, ",[436,3196,3197],{},"409"," when a named block no longer exists, ",[436,3200,3201],{},"422"," for an invalid operation (the error ",[436,3204,3205],{},"data"," lists the problems). Host code that acts for a user calls ",[436,3208,3209],{},"server.mutator.apply(documentId, ops, { user })",[418,3211,3213],{"id":3212},"content-rewritten-behind-the-editors-back","Content rewritten behind the editor's back",[423,3215,3216,3217,3220,3221,3223,3224,3227,3228,3230],{},"When something other than the editor writes a document's content (an agent rewrites the file), call ",[436,3218,3219],{},"server.collab.contentChanged(id)"," (the handle's ",[436,3222,2121],{},", or the one of your own ",[436,3225,3226],{},"createCollabServer",") after the write. If the document is open, the server merges the new content into it right away as a diff-update: connected clients see an ordinary edit, unchanged blocks keep their Yjs items, nobody reconnects. It is a no-op when nobody has the document open or the version did not move. It needs ",[436,3229,2405],{},": without it a rewrite cannot be told from the server's own writes. Without the call an open document picks the rewrite up only on its next store (the next edit or the last client leaving).",[418,3232,3234],{"id":3233},"reading-stored-content","Reading stored content",[423,3236,3237,3238,3240,3241,3244,3245,3247,3248,3251,3252,3255,3256,3259,3260,3263,3264,3266,3267,3270,3271,3274],{},"The ports return content exactly as the host stored it, possibly written by an earlier release. Server code that reads it (a host route, a script) uses the one load operation of ",[436,3239,670],{},", which applies the stored-content migration once and completely: ",[436,3242,3243],{},"loadCurrentContent(ports.documents, id)"," (one document, ",[436,3246,442],{}," when missing), ",[436,3249,3250],{},"listCurrentContents(ports.documents)"," (all documents) and ",[436,3253,3254],{},"currentContent(json)"," for stored content that did not come from the port (a ",[436,3257,3258],{},".cdoc"," package a host imports, a document a host's own route loads next to its metadata). The collaboration load, ",[436,3261,3262],{},"GET \u002Fapi\u002Feditor\u002Fdocuments\u002F:id",", the tag index and the reference app's import, ",[436,3265,3258],{}," export and ",[436,3268,3269],{},"GET","\u002F",[436,3272,3273],{},"PUT \u002Fapi\u002Fdocuments\u002F:id"," all read through them; no caller picks a migration itself.",[418,3276,3278],{"id":3277},"what-the-collab-server-does-on-load","What the collab server does on load",[3280,3281,3282,3298],"ol",{},[3283,3284,3285,3286,467,3289,3292,3293,3297],"li",{},"A stored Yjs state without old persisted node names (",[436,3287,3288],{},"composite*",[436,3290,3291],{},"section*",") is used; blocks without an ID get one assigned ",[3294,3295,3296],"strong",{},"on the server",", before any client syncs, and the state is persisted at once (so a backfill after a restart cannot assign other IDs than clients already hold).",[3283,3299,3300,3301,3304,3305,3307,3308,3311,3312,3314,3315,3318],{},"Otherwise (no state, a legacy state containing the old ",[436,3302,3303],{},"section"," node, or a restored document) the Y.Doc is seeded from ",[436,3306,2215],{},", read as current content (",[436,3309,3310],{},"loadCurrentContent",": old persisted names, the earliest ",[436,3313,3291],{}," family and a flat ",[436,3316,3317],{},"meta.transcript"," migrated) and given block IDs, then persisted immediately.",[418,3320,3322],{"id":3321},"agent-texts-for-host-driven-agent-chats","Agent texts for host-driven agent chats",[423,3324,3325,3326,475,3329,467,3332,467,3335,467,3338,467,3341,3344,3345,3348,3349,3352],{},"Model-facing agent texts of ",[436,3327,3328],{},"\u002Fai\u002Fprotocol",[436,3330,3331],{},"checkAgentOps(raw, { …context, locale })",[436,3333,3334],{},"agentShownMessage(ops, dropped, { locale })",[436,3336,3337],{},"agentFeedbackText(feedback, { locale })",[436,3339,3340],{},"agentRetryMessage",[436,3342,3343],{},"agentOpSummary",") are German by default and English with ",[436,3346,3347],{},"locale: 'en'","; the package's own ",[436,3350,3351],{},"\u002Fapi\u002Fai\u002Fchat"," prompts and results stay German.",[423,3354,3355,3356,3359,3360,2936,3363,3365,3366,3369,3370,3373],{},"A host that exposes the edit operations under its own tool name builds the retry result with ",[436,3357,3358],{},"agentRetryMessage(problems, scoped, { locale, tool, partial })",", so the text tells the model to call ",[436,3361,3362],{},"tool",[436,3364,3156],{},") again rather than the editor's tool. Without ",[436,3367,3368],{},"partial"," the text says nothing was applied and asks for the whole corrected list (the package's own all-or-nothing retry); a host that already shows the valid operations passes ",[436,3371,3372],{},"partial: true",", and the text asks only for corrected versions of the listed operations.",[3375,3376,3377],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}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 .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}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":571,"searchDepth":612,"depth":612,"links":3379},[3380,3381,3382,3383,3384,3385,3386,3387,3388,3389,3390,3391],{"id":420,"depth":612,"text":421},{"id":495,"depth":612,"text":496},{"id":1896,"depth":612,"text":1897},{"id":1955,"depth":612,"text":1956},{"id":2131,"depth":612,"text":2132},{"id":3042,"depth":612,"text":3043},{"id":3084,"depth":612,"text":3085},{"id":3129,"depth":612,"text":3130},{"id":3212,"depth":612,"text":3213},{"id":3233,"depth":612,"text":3234},{"id":3277,"depth":612,"text":3278},{"id":3321,"depth":612,"text":3322},"The single seam between the package and the host: ports for identity, documents, Yjs state, assets, settings, themes and AI models.","md",null,{},{"icon":198},{"title":195,"description":3392},"b_T7kmnUxzO9ik8y56eyJ2M-l2KHji66i4QSkEjNQAU",[3400,3402],{"title":190,"path":191,"stem":192,"description":3401,"icon":193,"children":-1},"The Block index, Workspace search, Block references and Embeds that name a Block address, Document routes with the DocumentMutator, Tool providers for the document chat, and change sets for edits to other Documents.",{"title":200,"path":201,"stem":202,"description":3403,"icon":203,"children":-1},"The collection Block type: its items and stored query, the node view with reorder and „Aus Abfrage füllen“, the block action that adds a Block, and the Markdown export.",1793178225761]