[{"data":1,"prerenderedAt":1579},["ShallowReactive",2],{"navigation_docs":3,"-guides-obsidian":412,"-guides-obsidian-surround":1574},[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":267,"body":414,"description":1567,"extension":1568,"links":1569,"meta":1570,"navigation":1571,"path":268,"seo":1572,"stem":269,"__hash__":1573},"docs\u002F3.guides\u002F44.obsidian.md",{"type":415,"value":416,"toc":1554},"minimark",[417,440,448,453,577,607,814,824,829,850,854,861,979,1015,1019,1078,1082,1085,1176,1235,1239,1284,1299,1365,1371,1375,1386,1477,1480,1484,1506,1521,1530,1534,1550],[418,419,420,421,425,426,433,434,439],"p",{},"The add-on ",[422,423,424],"code",{},"@skaile\u002Fforge-editor-obsidian"," moves notes between an ",[427,428,432],"a",{"href":429,"rel":430},"https:\u002F\u002Fobsidian.md",[431],"nofollow","Obsidian"," vault and the editor. The database stays canonical (",[427,435,438],{"href":436,"rel":437},"https:\u002F\u002Fgithub.com\u002Fskaile-ai\u002Fforge-editor\u002Fblob\u002Fmain\u002Fdocs\u002Fadr\u002F0001-database-canonical-markdown-export.md",[431],"ADR-0001","): a vault is a file format for import and export, the editor does not watch a folder and does not keep a vault in sync.",[418,441,442,443,447],{},"The add-on has no editor feature and no UI. It is a set of pure functions, a small upload helper and a command. The host needs ",[444,445,446],"strong",{},"no wiring",": install the package where the script runs.",[449,450,452],"h2",{"id":451},"import","Import",[454,455,460],"pre",{"className":456,"code":457,"language":458,"meta":459,"style":459},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { importVault } from '@skaile\u002Fforge-editor-obsidian'\n\nconst plan = importVault(files) \u002F\u002F files: { path: 'Notes\u002FNote B.md', text: '…' }[]\nplan.documents \u002F\u002F one PlannedDocument per note\nplan.unresolved \u002F\u002F links no note answers\nplan.warnings \u002F\u002F frontmatter or Templater code outside the supported subset, a missing heading or block id\nplan.skipped \u002F\u002F paths that are no notes (attachments, canvases, folders that start with a dot)\n","ts","",[422,461,462,493,500,523,538,551,564],{"__ignoreMap":459},[463,464,467,470,474,478,481,484,487,490],"span",{"class":465,"line":466},"line",1,[463,468,451],{"class":469},"s7zQu",[463,471,473],{"class":472},"sMK4o"," {",[463,475,477],{"class":476},"sTEyZ"," importVault",[463,479,480],{"class":472}," }",[463,482,483],{"class":469}," from",[463,485,486],{"class":472}," '",[463,488,424],{"class":489},"sfazB",[463,491,492],{"class":472},"'\n",[463,494,496],{"class":465,"line":495},2,[463,497,499],{"emptyLinePlaceholder":498},true,"\n",[463,501,503,507,510,513,516,519],{"class":465,"line":502},3,[463,504,506],{"class":505},"spNyl","const",[463,508,509],{"class":476}," plan ",[463,511,512],{"class":472},"=",[463,514,477],{"class":515},"s2Zo4",[463,517,518],{"class":476},"(files) ",[463,520,522],{"class":521},"sHwdD","\u002F\u002F files: { path: 'Notes\u002FNote B.md', text: '…' }[]\n",[463,524,526,529,532,535],{"class":465,"line":525},4,[463,527,528],{"class":476},"plan",[463,530,531],{"class":472},".",[463,533,534],{"class":476},"documents ",[463,536,537],{"class":521},"\u002F\u002F one PlannedDocument per note\n",[463,539,541,543,545,548],{"class":465,"line":540},5,[463,542,528],{"class":476},[463,544,531],{"class":472},[463,546,547],{"class":476},"unresolved ",[463,549,550],{"class":521},"\u002F\u002F links no note answers\n",[463,552,554,556,558,561],{"class":465,"line":553},6,[463,555,528],{"class":476},[463,557,531],{"class":472},[463,559,560],{"class":476},"warnings ",[463,562,563],{"class":521},"\u002F\u002F frontmatter or Templater code outside the supported subset, a missing heading or block id\n",[463,565,567,569,571,574],{"class":465,"line":566},7,[463,568,528],{"class":476},[463,570,531],{"class":472},[463,572,573],{"class":476},"skipped ",[463,575,576],{"class":521},"\u002F\u002F paths that are no notes (attachments, canvases, folders that start with a dot)\n",[418,578,579,582,583,586,587,590,591,594,595,598,599,602,603,606],{},[422,580,581],{},"importVault"," writes nothing. Each ",[422,584,585],{},"PlannedDocument"," is ",[422,588,589],{},"{ id, path, title, folder, template, properties, content }",". ",[422,592,593],{},"content"," is the Document's TipTap JSON: one Typed block of the Block type ",[422,596,597],{},"document"," that holds the note's blocks, so ",[422,600,601],{},"[[Note]]"," has a block to point at. Its ",[422,604,605],{},"meta"," is the note's frontmatter, its tags are the note's tags, its title is the file name.",[608,609,610,623],"table",{},[611,612,613],"thead",{},[614,615,616,620],"tr",{},[617,618,619],"th",{},"In the note",[617,621,622],{},"In the Document",[624,625,626,649,672,682,693,708,722,735,751,761,771,788,801],"tbody",{},[614,627,628,636],{},[629,630,631,632,635],"td",{},"Frontmatter keys (the subset ",[422,633,634],{},"parseFrontmatter"," reads: scalars, flow lists, block lists)",[629,637,638,641,642,644,645,648],{},[422,639,640],{},"properties",", the ",[422,643,605],{}," of the wrapping block. Nested maps are reported in ",[422,646,647],{},"warnings"," and skipped",[614,650,651,661],{},[629,652,653,656,657,660],{},[422,654,655],{},"tags",", ",[422,658,659],{},"tag"," in frontmatter",[629,662,663,664,667,668,671],{},"The tags of the wrapping block, in the editor's tag name form (",[422,665,666],{},"Ideas\u002FNew"," → ",[422,669,670],{},"ideas\u002Fnew",")",[614,673,674,679],{},[629,675,676,660],{},[422,677,678],{},"aliases",[629,680,681],{},"Kept as a property, and used to resolve links",[614,683,684,687],{},[629,685,686],{},"Body",[629,688,689,690,671],{},"The library's Markdown parser (the same one the server uses for ",[422,691,692],{},"documentOps",[614,694,695,701],{},[629,696,697,700],{},[422,698,699],{},"text ^id"," at the end of a paragraph or heading",[629,702,703,704,707],{},"The block's ",[422,705,706],{},"id"," is that id; the marker leaves the text",[614,709,710,716],{},[629,711,712,715],{},[422,713,714],{},"^id"," on a line of its own after a list, quote, table or code block",[629,717,718,719,721],{},"The ",[422,720,706],{}," of the block before it",[614,723,724,728],{},[629,725,726],{},[422,727,601],{},[629,729,730,731,734],{},"A ",[422,732,733],{},"reference"," chip to the note's wrapping block",[614,736,737,745],{},[629,738,739,656,742],{},[422,740,741],{},"[[Note#Heading]]",[422,743,744],{},"[[Note#^id]]",[629,746,747,748,750],{},"A chip to that heading or block; when the note has none, the chip points at the note and ",[422,749,647],{}," says so",[614,752,753,758],{},[629,754,755],{},[422,756,757],{},"[[Note|alias]]",[629,759,760],{},"The chip with the alias as its label",[614,762,763,768],{},[629,764,765],{},[422,766,767],{},"[[#Heading]]",[629,769,770],{},"A chip to a heading of the same note",[614,772,773,782],{},[629,774,775,656,778,781],{},[422,776,777],{},"![[Note]]",[422,779,780],{},"![[Note#Heading]]"," alone in a paragraph",[629,783,730,784,787],{},[422,785,786],{},"blockEmbed"," block (the whole note: its children; a heading or block: that block)",[614,789,790,795],{},[629,791,792],{},[422,793,794],{},"[[Missing]]",[629,796,797,798],{},"Stays text, and is listed in ",[422,799,800],{},"unresolved",[614,802,803,808],{},[629,804,805],{},[422,806,807],{},"\u003C% tp.date.now() %>",[629,809,810,813],{},[422,811,812],{},"{{date}}",", see below",[418,815,816,817,820,821,823],{},"A link names its note by file name, by path (",[422,818,819],{},"[[folder\u002FNote]]",") or by an ",[422,822,678],{}," entry, without regard to case. Where several notes match, the one in the same folder wins, then the one with the shortest path. Links are resolved in a second pass, after every note has been read, so a link may point at a note that comes later in the vault.",[825,826,828],"h3",{"id":827},"block-ids","Block ids",[418,830,831,832,590,835,837,838,840,841,843,844,846,847,849],{},"The ids of blocks carry the links: a chip is ",[422,833,834],{},"{ target: blockId, documentId }",[422,836,581],{}," keeps every ",[422,839,714],{}," as the block's ",[422,842,706],{}," and gives all other blocks a new one. The first of a repeated id wins and the rest are reported in ",[422,845,647],{},". The ids are valid inside one Document only; a link ",[422,848,744],{}," is resolved against the ids of that note.",[825,851,853],{"id":852},"templater","Templater",[418,855,856,857,860],{},"Templater is code, and none of it runs. A small subset has a Dokumentvorlage placeholder (see ",[427,858,859],{"href":225},"Templates",") and is translated:",[608,862,863,872],{},[611,864,865],{},[614,866,867,869],{},[617,868,853],{},[617,870,871],{},"Placeholder",[624,873,874,884,896,909,924,939,955,967],{},[614,875,876,880],{},[629,877,878],{},[422,879,807],{},[629,881,882],{},[422,883,812],{},[614,885,886,891],{},[629,887,888],{},[422,889,890],{},"\u003C% tp.date.now(\"YYYY-MM-DD\") %>",[629,892,893],{},[422,894,895],{},"{{date:iso}}",[614,897,898,904],{},[629,899,900,903],{},[422,901,902],{},"\u003C% tp.date.now(\"HH:mm\") %>"," (a clock format)",[629,905,906],{},[422,907,908],{},"{{time}}",[614,910,911,919],{},[629,912,913,656,916],{},[422,914,915],{},"\u003C% tp.date.now(\"DD.MM.YYYY\") %>",[422,917,918],{},"\"L\"",[629,920,921],{},[422,922,923],{},"{{date:short}}",[614,925,926,934],{},[629,927,928,656,931],{},[422,929,930],{},"\u003C% tp.date.now(\"LL\") %>",[422,932,933],{},"\"D MMM YYYY\"",[629,935,936],{},[422,937,938],{},"{{date:medium}}",[614,940,941,950],{},[629,942,943,946,947],{},[422,944,945],{},"\u003C% tp.date.now(\"LLL\") %>",", a format with ",[422,948,949],{},"MMMM",[629,951,952],{},[422,953,954],{},"{{date:long}}",[614,956,957,962],{},[629,958,959],{},[422,960,961],{},"\u003C% tp.file.title %>",[629,963,964],{},[422,965,966],{},"{{title}}",[614,968,969,974],{},[629,970,971],{},[422,972,973],{},"\u003C% tp.file.cursor() %>",[629,975,976],{},[422,977,978],{},"{{cursor}}",[418,980,981,982,985,986,988,989,992,993,656,995,998,999,1002,1003,1006,1007,1010,1011,1014],{},"Every other ",[422,983,984],{},"\u003C% … %>"," stays as written and is named in ",[422,987,647],{},". The notes of the vault's templates folder (",[422,990,991],{},"templatesFolder",", default ",[422,994,859],{},[422,996,997],{},"null"," for none) are planned into the folder ",[422,1000,1001],{},"Dokumentvorlagen"," and have ",[422,1004,1005],{},"template: true",". A Document made from one of them through ",[422,1008,1009],{},"documentCreate"," with ",[422,1012,1013],{},"templateId"," gets the placeholders expanded.",[825,1016,1018],{"id":1017},"options","Options",[608,1020,1021,1031],{},[611,1022,1023],{},[614,1024,1025,1028],{},[617,1026,1027],{},"Option",[617,1029,1030],{},"Meaning",[624,1032,1033,1051,1065],{},[614,1034,1035,1040],{},[629,1036,1037],{},[422,1038,1039],{},"markdown",[629,1041,1042,1043,1046,1047,1050],{},"The Markdown parser, ",[422,1044,1045],{},"createMarkdownBlocks({ blockTypes })"," of the host, when notes hold ",[422,1048,1049],{},":::"," fences of the host's own Block types",[614,1052,1053,1057],{},[629,1054,1055],{},[422,1056,991],{},[629,1058,1059,1060,656,1062,1064],{},"The vault's templates folder, default ",[422,1061,859],{},[422,1063,997],{}," for none",[614,1066,1067,1072],{},[629,1068,1069],{},[422,1070,1071],{},"newId",[629,1073,1074,1075],{},"Where Document ids and missing block ids come from, default ",[422,1076,1077],{},"crypto.randomUUID",[449,1079,1081],{"id":1080},"create-the-documents","Create the Documents",[418,1083,1084],{},"Links between Documents name provisional ids. Create the Documents first, then swap the ids and store the content:",[454,1086,1088],{"className":456,"code":1087,"language":458,"meta":459,"style":459},"import { importVault, uploadVault } from '@skaile\u002Fforge-editor-obsidian'\n\nconst plan = importVault(files)\nawait uploadVault(plan.documents, { url: 'https:\u002F\u002Feditor.example.com', token })\n",[422,1089,1090,1114,1118,1131],{"__ignoreMap":459},[463,1091,1092,1094,1096,1098,1101,1104,1106,1108,1110,1112],{"class":465,"line":466},[463,1093,451],{"class":469},[463,1095,473],{"class":472},[463,1097,477],{"class":476},[463,1099,1100],{"class":472},",",[463,1102,1103],{"class":476}," uploadVault",[463,1105,480],{"class":472},[463,1107,483],{"class":469},[463,1109,486],{"class":472},[463,1111,424],{"class":489},[463,1113,492],{"class":472},[463,1115,1116],{"class":465,"line":495},[463,1117,499],{"emptyLinePlaceholder":498},[463,1119,1120,1122,1124,1126,1128],{"class":465,"line":502},[463,1121,506],{"class":505},[463,1123,509],{"class":476},[463,1125,512],{"class":472},[463,1127,477],{"class":515},[463,1129,1130],{"class":476},"(files)\n",[463,1132,1133,1136,1138,1141,1143,1146,1148,1150,1154,1157,1159,1162,1165,1167,1170,1173],{"class":465,"line":525},[463,1134,1135],{"class":469},"await",[463,1137,1103],{"class":515},[463,1139,1140],{"class":476},"(plan",[463,1142,531],{"class":472},[463,1144,1145],{"class":476},"documents",[463,1147,1100],{"class":472},[463,1149,473],{"class":472},[463,1151,1153],{"class":1152},"swJcz"," url",[463,1155,1156],{"class":472},":",[463,1158,486],{"class":472},[463,1160,1161],{"class":489},"https:\u002F\u002Feditor.example.com",[463,1163,1164],{"class":472},"'",[463,1166,1100],{"class":472},[463,1168,1169],{"class":476}," token ",[463,1171,1172],{"class":472},"}",[463,1174,1175],{"class":476},")\n",[418,1177,1178,1181,1182,1184,1185,1188,1189,1192,1193,1196,1197,1200,1201,1204,1205,1208,1209,1196,1212,1215,1216,1219,1220,1223,1224,1227,1228,1230,1231,1234],{},[422,1179,1180],{},"uploadVault"," calls ",[422,1183,1009],{}," for every Document, then ",[422,1186,1187],{},"documentPut"," with the content after ",[422,1190,1191],{},"bindDocumentIds"," (",[422,1194,1195],{},"API"," and ",[422,1198,1199],{},"routeUrl"," from ",[422,1202,1203],{},"@skaile\u002Fforge-editor\u002Fcore"," name the routes). ",[422,1206,1207],{},"token"," goes out as ",[422,1210,1211],{},"Authorization: Bearer \u003Ctoken>",[422,1213,1214],{},"cookie"," as ",[422,1217,1218],{},"Cookie: \u003Ccookie>","; what the host's ",[422,1221,1222],{},"authenticate"," makes of them is the host's choice. The Reference app reads its session cookie only, so a bearer token gets ",[422,1225,1226],{},"401"," there; use ",[422,1229,1214],{},". A Document goes into its folder when the server has it. The routes cannot create folders, so a note whose folder is missing lands in the root and ",[422,1232,1233],{},"warn"," says so. The routes do not know a note by its path: a second run creates the Documents again.",[449,1236,1238],{"id":1237},"export","Export",[454,1240,1242],{"className":456,"code":1241,"language":458,"meta":459,"style":459},"import { exportVault } from '@skaile\u002Fforge-editor-obsidian'\n\nconst files = exportVault(documents) \u002F\u002F documents: { id, title, folder?, content }[] → { path, text }[]\n",[422,1243,1244,1263,1267],{"__ignoreMap":459},[463,1245,1246,1248,1250,1253,1255,1257,1259,1261],{"class":465,"line":466},[463,1247,451],{"class":469},[463,1249,473],{"class":472},[463,1251,1252],{"class":476}," exportVault",[463,1254,480],{"class":472},[463,1256,483],{"class":469},[463,1258,486],{"class":472},[463,1260,424],{"class":489},[463,1262,492],{"class":472},[463,1264,1265],{"class":465,"line":495},[463,1266,499],{"emptyLinePlaceholder":498},[463,1268,1269,1271,1274,1276,1278,1281],{"class":465,"line":502},[463,1270,506],{"class":505},[463,1272,1273],{"class":476}," files ",[463,1275,512],{"class":472},[463,1277,1252],{"class":515},[463,1279,1280],{"class":476},"(documents) ",[463,1282,1283],{"class":521},"\u002F\u002F documents: { id, title, folder?, content }[] → { path, text }[]\n",[418,1285,1286,1287,1290,1291,1294,1295,1298],{},"One ",[422,1288,1289],{},".md"," per Document, at ",[422,1292,1293],{},"\u003Cfolder>\u002F\u003Ctitle>.md","; two Documents with the same path get ",[422,1296,1297],{}," (2)"," added. The Markdown is the library's Markdown export (the same as the source mode), with these changes:",[1300,1301,1302,1323,1339,1352,1358],"ul",{},[1303,1304,1305,1306,1308,1309,1311,1312,1314,1315,1318,1319,1322],"li",{},"A Document that is one Typed block of the Block type ",[422,1307,597],{}," (what ",[422,1310,581],{}," plans) is unwrapped: its ",[422,1313,605],{}," and tags are the frontmatter, its body the text. A ",[422,1316,1317],{},"derivation"," or ",[422,1320,1321],{},"edges"," entry stays in the database.",[1303,1324,1325,1326,656,1328,656,1330,1318,1332,1335,1336,531],{},"A reference chip or embed to a Document in the export becomes ",[422,1327,601],{},[422,1329,741],{},[422,1331,744],{},[422,1333,1334],{},"![[…]]",", with the chip's label as the alias. Where two Documents share a title, the link names the path. A chip to a Document that is not in the export stays ",[422,1337,1338],{},"[@…]",[1303,1340,1341,1342,1344,1345,656,1348,1351],{},"A block that a link names gets its id as ",[422,1343,714],{},": at the end of a paragraph or heading or list item, else on a line of its own after the block. The ids that came from a vault (",[422,1346,1347],{},"intro",[422,1349,1350],{},"key-point",") are written for every block that has one. A block the editor numbered (a UUID) that no link names gets none: the database keeps that id (ADR-0001).",[1303,1353,1354,1355,1357],{},"A link that cannot name its block (the block sits inside a quote, or its id is not a legal Obsidian id) points at the note, and ",[422,1356,1233],{}," says so.",[1303,1359,1360,1361,1364],{},"Typed blocks of other types are written as ",[422,1362,1363],{},"::: kind"," fences. Obsidian shows them as text.",[418,1366,1367,1368,1370],{},"A vault that is exported and imported again keeps its notes' frontmatter, links and ",[422,1369,714],{}," lines.",[449,1372,1374],{"id":1373},"command","Command",[454,1376,1380],{"className":1377,"code":1378,"language":1379,"meta":459,"style":459},"language-sh shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","bunx @skaile\u002Fforge-editor-obsidian import .\u002FMyVault --url https:\u002F\u002Feditor.example.com --token $TOKEN\n","sh",[422,1381,1382],{"__ignoreMap":459},[463,1383,1384],{"class":465,"line":466},[463,1385,1378],{},[608,1387,1388,1396],{},[611,1389,1390],{},[614,1391,1392,1394],{},[617,1393,1027],{},[617,1395,1030],{},[624,1397,1398,1411,1432,1450,1464],{},[614,1399,1400,1405],{},[629,1401,1402],{},[422,1403,1404],{},"--url",[629,1406,1407,1408],{},"The editor server, also ",[422,1409,1410],{},"EDITOR_URL",[614,1412,1413,1418],{},[629,1414,1415],{},[422,1416,1417],{},"--token",[629,1419,1420,1421,1424,1425,1428,1429,1431],{},"Sent as the bearer token (",[422,1422,1423],{},"Authorization: Bearer","), also ",[422,1426,1427],{},"EDITOR_TOKEN","; for a host whose ",[422,1430,1222],{}," accepts a bearer token",[614,1433,1434,1439],{},[629,1435,1436],{},[422,1437,1438],{},"--cookie",[629,1440,1441,1442,1445,1446,1449],{},"Sent as the ",[422,1443,1444],{},"Cookie"," header, also ",[422,1447,1448],{},"EDITOR_COOKIE","; for a host with a session cookie",[614,1451,1452,1457],{},[629,1453,1454],{},[422,1455,1456],{},"--templates",[629,1458,1459,1460,1463],{},"The vault's templates folder (",[422,1461,1462],{},"\"\""," for none)",[614,1465,1466,1471],{},[629,1467,1468],{},[422,1469,1470],{},"--dry-run",[629,1472,1473,1474,1476],{},"Plan and print the counts, call nothing; ",[422,1475,1404],{}," is then optional",[418,1478,1479],{},"It prints the warnings and unresolved links, and one line per Document with the id the server gave.",[825,1481,1483],{"id":1482},"against-the-reference-app","Against the Reference app",[418,1485,1486,1487,1192,1490,656,1493,1318,1496,1499,1500,1503,1504,1156],{},"The Reference app of this repository has no bearer tokens; it knows a caller by its session cookie. Sign in as one of its users with ",[422,1488,1489],{},"POST \u002Fapi\u002Fauth\u002Fswitch",[422,1491,1492],{},"anna",[422,1494,1495],{},"ben",[422,1497,1498],{},"bernd",") and hand the ",[422,1501,1502],{},"set-cookie"," pair to ",[422,1505,1438],{},[454,1507,1509],{"className":1377,"code":1508,"language":1379,"meta":459,"style":459},"COOKIE=$(curl -si -X POST http:\u002F\u002Flocalhost:3056\u002Fapi\u002Fauth\u002Fswitch -H 'content-type: application\u002Fjson' -d '{\"username\":\"anna\"}' | grep -i '^set-cookie:' | sed 's\u002F^[^:]*: *\u002F\u002F; s\u002F;.*\u002F\u002F')\nbunx @skaile\u002Fforge-editor-obsidian import .\u002FMyVault --url http:\u002F\u002Flocalhost:3056 --cookie \"$COOKIE\"\n",[422,1510,1511,1516],{"__ignoreMap":459},[463,1512,1513],{"class":465,"line":466},[463,1514,1515],{},"COOKIE=$(curl -si -X POST http:\u002F\u002Flocalhost:3056\u002Fapi\u002Fauth\u002Fswitch -H 'content-type: application\u002Fjson' -d '{\"username\":\"anna\"}' | grep -i '^set-cookie:' | sed 's\u002F^[^:]*: *\u002F\u002F; s\u002F;.*\u002F\u002F')\n",[463,1517,1518],{"class":465,"line":495},[463,1519,1520],{},"bunx @skaile\u002Fforge-editor-obsidian import .\u002FMyVault --url http:\u002F\u002Flocalhost:3056 --cookie \"$COOKIE\"\n",[418,1522,1523,586,1526,1529],{},[422,1524,1525],{},"$COOKIE",[422,1527,1528],{},"nuxt-session=Fe26.2**…",". The Documents belong to that user.",[449,1531,1533],{"id":1532},"not-included","Not included",[1300,1535,1536,1543],{},[1303,1537,1538,1539,1542],{},"Attachments (images, PDFs) are skipped. Obsidian canvases, Dataview queries, callouts' foldable state and inline ",[422,1540,1541],{},"#tags"," outside frontmatter stay as the Markdown parser reads them.",[1303,1544,1545,1546,1549],{},"No two-way sync. The ",[422,1547,1548],{},".obsidian"," folder and every folder that starts with a dot are never read.",[1551,1552,1553],"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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}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 .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);}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}",{"title":459,"searchDepth":495,"depth":495,"links":1555},[1556,1561,1562,1563,1566],{"id":451,"depth":495,"text":452,"children":1557},[1558,1559,1560],{"id":827,"depth":502,"text":828},{"id":852,"depth":502,"text":853},{"id":1017,"depth":502,"text":1018},{"id":1080,"depth":495,"text":1081},{"id":1237,"depth":495,"text":1238},{"id":1373,"depth":495,"text":1374,"children":1564},[1565],{"id":1482,"depth":502,"text":1483},{"id":1532,"depth":495,"text":1533},"The add-on @skaile\u002Fforge-editor-obsidian: importVault plans one Document per note with frontmatter as properties, wikilinks as reference chips and ^id block ids kept; exportVault writes them back; a command uploads a vault to an editor server.","md",null,{},{"icon":270},{"title":267,"description":1567},"j7fSee4EsTXehgXdlPOp2CVmXfWpo1SxtIALME6yX2Y",[1575,1577],{"title":262,"path":263,"stem":264,"description":1576,"icon":265,"children":-1},"The add-on @skaile\u002Fforge-editor-pdf-viewer: the source-anchor property, a pdfjs viewer with a text layer, scrolling to a passage on reveal, and „Zitat anlegen“, which creates a quote block derived from the PDF.",{"title":272,"path":273,"stem":274,"description":1578,"icon":275,"children":-1},"The add-on @skaile\u002Fforge-editor-typst: the render target typst-pdf that turns a Document or a paper into Typst markup, writes the bibliography as BibTeX, and compiles a PDF in one of four citation styles.",1793219829488]