---
title: "Migrating from #tiptap-editor"
description: "Move a host from the removed #tiptap-editor Nuxt module to explicit imports from @skaile/forge-editor entries."
canonical_url: "https://skaile-ai.github.io/forge-editor/guides/migration"
---
# Migrating from #tiptap-editor

> Move a host from the removed #tiptap-editor Nuxt module to explicit imports from @skaile/forge-editor entries.

The former Nuxt module `modules/tiptap-editor` (alias `#tiptap-editor`, auto-imported components, composables and utils, one server directory) is gone. Nothing is auto-imported and no alias remains: import from the entries below.

1. `nuxt.config.ts`: replace `'./modules/tiptap-editor'` with `'@skaile/forge-editor/nuxt'` (after `'@nuxt/ui'`). The `tiptapEditor` options keep their shape and defaults. Add `"@skaile/forge-editor": "workspace:*"` to the host's dependencies.
2. Replace auto-imported components and composables by explicit imports:

<table>
<thead>
  <tr>
    <th>
      Before (auto-import or <code>
        #tiptap-editor
      </code>
      
      )
    </th>
    
    <th>
      After
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        DocumentEditor
      </code>
    </td>
    
    <td>
      <code>
        AdvancedEditor
      </code>
      
       from <code>
        @skaile/forge-editor/vue/advanced
      </code>
      
       (same props and events; plus <code>
        settings-ui
      </code>
      
      , see <a href="https://skaile-ai.github.io/forge-editor/reference/presets-and-features">
        Presets and features
      </a>
      
      ); on React <code>
        @skaile/forge-editor/react/advanced
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        EditorToolbar
      </code>
      
      , <code>
        EditorSettingsModal
      </code>
      
      , <code>
        useEditorSettings
      </code>
      
      , <code>
        useEditorUi
      </code>
      
      , <code>
        useEditorContext
      </code>
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/vue
      </code>
      
       (the toolbar and the panel take <code>
        :editor
      </code>
      
      )
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        AiSidebar
      </code>
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/ai/vue/chat
      </code>
      
       (needs the optional peer <code>
        @skaile/forge-chat
      </code>
      
      ; <code>
        /ai/react
      </code>
      
       on React)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        AiReviewBar
      </code>
      
      , <code>
        AiSelectionMenu
      </code>
      
      , <code>
        ModelQuickSwitch
      </code>
      
      , <code>
        useAiAssistant
      </code>
      
      , <code>
        useDocumentChat
      </code>
      
      , <code>
        useModelProfiles
      </code>
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/ai/vue
      </code>
      
       (<code>
        /ai/react
      </code>
      
       on React; the framework-free models <code>
        modelProfiles
      </code>
      
      , <code>
        createAiAssistant
      </code>
      
      , <code>
        createDocumentChat
      </code>
      
       in <code>
        @skaile/forge-editor/ai
      </code>
      
      )
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        useFileImport
      </code>
      
      , <code>
        AudioRecorderModal
      </code>
      
      , <code>
        useAudioRecorder
      </code>
      
      , <code>
        pickFiles
      </code>
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/media/vue
      </code>
      
       (<code>
        /media/react
      </code>
      
       on React); <code>
        pickFiles
      </code>
      
       and the framework-free models in <code>
        @skaile/forge-editor/media
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        createTranscriptCleanup
      </code>
      
      , <code>
        hasTranscriptSegments
      </code>
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/integrations/transcript-ai
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      The Block type API (the module's former <code>
        Composite*
      </code>
      
       names; today <code>
        defaultBlockTypes(t)
      </code>
      
      , <code>
        BlockType
      </code>
      
      , <code>
        acceptsChild
      </code>
      
      ), <code>
        AcceptedChildren
      </code>
      
      , <code>
        headingsMarkdown
      </code>
      
      , <code>
        compositeOutline
      </code>
      
      , <code>
        moveBlockInto
      </code>
      
      , <code>
        moveIntoVerdict
      </code>
      
      , markdown fence helpers, <code>
        CompositeTable
      </code>
      
      , <code>
        CompositeInspector
      </code>
      
      , <code>
        useCompositeRows
      </code>
      
      , <code>
        setComposite*
      </code>
      
       writers
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/composites
      </code>
      
       (framework-free), <code>
        /composites/vue
      </code>
      
       or <code>
        /composites/react
      </code>
      
       for the components and <code>
        useCompositeRows
      </code>
      
       (schema subset: <code>
        /composites/schema
      </code>
      
      )
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        headingOutline
      </code>
      
      , <code>
        revealBlockInEditor
      </code>
      
       (framework-free), <code>
        EditorOutline
      </code>
      
       (<code>
        /outline/vue
      </code>
      
      , <code>
        /outline/react
      </code>
      
      )
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/outline
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        EMPTY_EDITOR_CONTENT
      </code>
      
      , <code>
        ABILITY
      </code>
      
      , <code>
        Ability
      </code>
      
      , <code>
        findBlockById
      </code>
      
      , block ID helpers
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/core/schema
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        fetchErrorMessage
      </code>
      
      , <code>
        downloadText
      </code>
      
      , abilities helpers (<code>
        abilitiesAtSelection
      </code>
      
      , <code>
        hasAbility
      </code>
      
      )
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/core
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        DocumentTree
      </code>
      
      , <code>
        useTreeView
      </code>
      
      , <code>
        TreeFolder
      </code>
      
      , <code>
        DocumentSummary
      </code>
      
       (were host files and host shared types)
    </td>
    
    <td>
      <code>
        DocumentTree
      </code>
      
      , <code>
        useTreeView
      </code>
      
       from <code>
        @skaile/forge-editor/tree/vue
      </code>
      
       (or <code>
        /tree/react
      </code>
      
      ); <code>
        DocumentStore
      </code>
      
      , <code>
        TreeFolder
      </code>
      
      , <code>
        DocumentSummary
      </code>
      
       from <code>
        @skaile/forge-editor/tree
      </code>
      
       (the host's <code>
        DocumentStore
      </code>
      
       implementation stays in the app; the host's ref-based store becomes stores with <code>
        storeFromRef
      </code>
      
       from <code>
        @skaile/forge-editor/vue
      </code>
      
      )
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        setEditorAdapter
      </code>
      
      , <code>
        forgetCollabDocument
      </code>
      
      , <code>
        liveContent
      </code>
      
      , <code>
        EditorAdapter
      </code>
      
       (Nitro, previously auto-imported)
    </td>
    
    <td>
      <code>
        provideEditorServer({ ports })
      </code>
      
      , <code>
        useEditorServer().forgetDocument
      </code>
      
      , <code>
        useEditorServer().liveContent
      </code>
      
       from <code>
        @skaile/forge-editor/server/nitro
      </code>
      
      , <code>
        EditorPorts
      </code>
      
       from <code>
        @skaile/forge-editor/server
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Server schema / migration imports of the old shared directory
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/schema/advanced
      </code>
      
      , <code>
        /composites/schema
      </code>
      
      , <code>
        /media/schema
      </code>
      
      , …
    </td>
  </tr>
</tbody>
</table>

1. Collaboration, block UI and the integrations are now features. `AdvancedEditor` includes them; a custom preset adds `collabFeature()`, `blockUiFeature()` and the integrations explicitly. Features report user-facing messages through the surface's `Notifier` (`ctx.notify`, [per-feature entries](https://skaile-ai.github.io/forge-editor/guides/composition#per-feature-entries-framework-free-vue-react)), so host code no longer hands toast objects to feature functions.
2. Search the host for `#tiptap-editor`, `modules/tiptap-editor` and for symbols that used to resolve without an import (`useEditorSettings`, `useFileImport`, `ABILITY`, `fileNameError`'s neighbors…); `nuxt typecheck` reports every unresolved one.
3. Styles: the Nuxt module adds every feature stylesheet; a plain-Vue app imports `core.css` plus the feature CSS it uses ([README](https://skaile-ai.github.io/forge-editor/reference/css-and-ui)).

Stored data needs no migration: document JSON, Yjs state, `tiptap-editor:settings`, `tiptap-editor:model-profiles` and `tip-tree:node-filters` keep their keys and shapes. Legacy `section` nodes are still migrated on load (`currentContent` on the server, the composites Feature's `migrateContent` hook in the editor).

## Block vocabulary

The library, the reference app and the docs name things in the block vocabulary ([glossary](https://skaile-ai.github.io/forge-editor/getting-started/glossary): Typed block, Block type, Property definition, Model role, …). The former names are removed; no alias remains. Switch a host over like this:

<table>
<thead>
  <tr>
    <th>
      Former name
    </th>
    
    <th>
      New name
    </th>
    
    <th>
      Where
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        CompositeKind
      </code>
      
      , <code>
        CompositeKindAi
      </code>
      
      , <code>
        CompositeMetaField
      </code>
    </td>
    
    <td>
      <code>
        BlockType
      </code>
      
      , <code>
        BlockTypeAi
      </code>
      
      , <code>
        PropertyDefinition
      </code>
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/composites
      </code>
      
      , <code>
        /composites/schema
      </code>
      
      ; <code>
        PropertyDefinition
      </code>
      
       from <code>
        @skaile/forge-editor/core
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        defaultCompositeKinds
      </code>
      
      , <code>
        fallbackCompositeKinds
      </code>
      
      , <code>
        compositeKind
      </code>
      
      , <code>
        kindAccepts
      </code>
    </td>
    
    <td>
      <code>
        defaultBlockTypes(t)
      </code>
      
      , <code>
        fallbackBlockTypes
      </code>
      
      , <code>
        blockTypeOf
      </code>
      
      , <code>
        acceptsChild
      </code>
    </td>
    
    <td>
      the same entries
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        compositeKindsOf(editor)
      </code>
    </td>
    
    <td>
      <code>
        blockTypesOf(editor)
      </code>
    </td>
    
    <td>
      the same entries
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        CompositeKindCount
      </code>
      
      , <code>
        CompositeKindOption
      </code>
      
      , <code>
        ChatCompositeKind
      </code>
    </td>
    
    <td>
      <code>
        BlockTypeCount
      </code>
      
      , <code>
        BlockTypeOption
      </code>
      
      , <code>
        ChatBlockType
      </code>
    </td>
    
    <td>
      the same entries; the chat type in <code>
        @skaile/forge-editor/ai
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      command <code>
        setCompositeKind(kind, pos?)
      </code>
    </td>
    
    <td>
      <code>
        changeBlockType(blockTypeId, pos?)
      </code>
    </td>
    
    <td>
      editor commands of the Typed block (not <code>
        setBlockType
      </code>
      
      : ProseMirror uses that name for node-type changes)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        compositeMetaWith
      </code>
      
      , <code>
        setCompositeMetaField
      </code>
    </td>
    
    <td>
      <code>
        metaWithProperty
      </code>
      
      , <code>
        setBlockProperty
      </code>
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/composites
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        renditionsOf
      </code>
    </td>
    
    <td>
      <code>
        derivedChildrenOf
      </code>
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/core
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      option and prop <code>
        kinds
      </code>
      
       or <code>
        compositeKinds
      </code>
    </td>
    
    <td>
      <code>
        blockTypes
      </code>
      
       (<code>
        compositeFeature({ blockTypes })
      </code>
      
      , <code>
        composeEditor({ blockTypes })
      </code>
      
      , <code>
        AdvancedEditor
      </code>
      
      , <code>
        ComposedSurface
      </code>
      
      )
    </td>
    
    <td>
      the same entries
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        skeleton
      </code>
      
       in the <code>
        ai
      </code>
      
       brief of a Block type, and the AI wire field <code>
        block.skeleton
      </code>
    </td>
    
    <td>
      <code>
        contentTemplate
      </code>
    </td>
    
    <td>
      <code>
        BlockTypeAi
      </code>
      
      ; client and server of the AI endpoints ship in the same package
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ModelSlot
      </code>
      
      , <code>
        MODEL_SLOTS
      </code>
      
      , <code>
        MODEL_SLOT_KEYS
      </code>
    </td>
    
    <td>
      <code>
        ModelRole
      </code>
      
      , <code>
        MODEL_ROLES
      </code>
      
      , <code>
        MODEL_ROLE_KEYS
      </code>
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/settings
      </code>
      
       (the stored key <code>
        ai.slots
      </code>
      
       is now <code>
        ai.roles
      </code>
      
      ; saved settings migrate on load)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        PresetConfig
      </code>
    </td>
    
    <td>
      <code>
        ModelPresetConfig
      </code>
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/config
      </code>
      
      , <code>
        /server
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        Identity
      </code>
      
      , <code>
        DocumentStore
      </code>
      
       of the server ports
    </td>
    
    <td>
      <code>
        AccessControl
      </code>
      
      , <code>
        DocumentContentStore
      </code>
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/server
      </code>
      
       (the <code>
        EditorPorts
      </code>
      
       members <code>
        identity
      </code>
      
       and <code>
        documents
      </code>
      
       keep their names; the Document tree's own <code>
        DocumentStore
      </code>
      
       in <code>
        @skaile/forge-editor/tree
      </code>
      
       keeps its name)
    </td>
  </tr>
  
  <tr>
    <td>
      the tree command string of the folder block
    </td>
    
    <td>
      <code>
        createFolderBlock
      </code>
    </td>
    
    <td>
      <code>
        TreeCommand
      </code>
      
       of <code>
        @skaile/forge-editor/tree
      </code>
      
      ; a host executor that switches on the command type must use the new string
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        aiKindsOf
      </code>
      
      , <code>
        derivableKindsOf
      </code>
      
      , <code>
        AiContextKind
      </code>
    </td>
    
    <td>
      <code>
        aiBlockTypesOf
      </code>
      
      , <code>
        derivableBlockTypesOf
      </code>
      
      , <code>
        AiContextBlockType
      </code>
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/composites
      </code>
      
      , <code>
        /integrations/composite-ai
      </code>
      
      , <code>
        /core
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        AiContext.kinds
      </code>
      
      , <code>
        ChatBlockModel.kinds
      </code>
      
      , the AI chat request field <code>
        kinds
      </code>
    </td>
    
    <td>
      <code>
        blockTypes
      </code>
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/core
      </code>
      
      , <code>
        /ai
      </code>
      
      ; client and server of the AI endpoints ship in the same package
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ConvertTarget
      </code>
      
       <code>
        { type: 'typedBlock', kind }
      </code>
    </td>
    
    <td>
      <code>
        { type: 'typedBlock', blockType }
      </code>
      
       (the target id <code>
        typedBlock:<id>
      </code>
      
       is unchanged)
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/core
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        BlockProperties.fields
      </code>
    </td>
    
    <td>
      <code>
        BlockProperties.definitions
      </code>
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/composites
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        listsBlockTypeCapability(type, id)
      </code>
      
      , <code>
        listsCapability(ctx, node, id)
      </code>
    </td>
    
    <td>
      <code>
        listsCapability(type, id)
      </code>
      
       (pass <code>
        ctx.blockTypeOf(node)
      </code>
      
      )
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/core
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        blockTypeConfigOf
      </code>
      
       from <code>
        /composites
      </code>
    </td>
    
    <td>
      <code>
        blockTypeConfigOf(type, id)
      </code>
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/core
      </code>
      
      ; <code>
        configOf
      </code>
      
       and <code>
        capabilityConfigOf
      </code>
      
       now return <code>
        undefined
      </code>
      
       (was <code>
        null
      </code>
      
      ) when absent
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        BlockTypeSpec
      </code>
    </td>
    
    <td>
      <code>
        BlockType
      </code>
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/composites
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        derivationOf
      </code>
      
      , <code>
        derivationState
      </code>
      
      , <code>
        DERIVATION_KEY
      </code>
      
      , <code>
        Derivation
      </code>
      
      , <code>
        DerivationMethod
      </code>
      
      , <code>
        DerivationSource
      </code>
      
      , <code>
        PropertyDefinition
      </code>
      
       from <code>
        /composites
      </code>
      
       or <code>
        /composites/schema
      </code>
    </td>
    
    <td>
      the same names
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/core
      </code>
      
       only
    </td>
  </tr>
  
  <tr>
    <td>
      CSS <code>
        --sk-kind-tone
      </code>
      
      , <code>
        --sk-kind-tone-mix
      </code>
    </td>
    
    <td>
      <code>
        --sk-block-type-tone
      </code>
      
      , <code>
        --sk-block-type-tone-mix
      </code>
    </td>
    
    <td>
      host stylesheets that set or read the tone
    </td>
  </tr>
</tbody>
</table>

Behaviour that changed with the rename:

- **Accepted children.** The built-in Folder and Document Block types declare `accepts: 'all'` themselves; the id-keyed default is gone. A Block type without `accepts`, and a type ID that a list does not define, accepts no nested Typed blocks (`acceptsChild`). A host list that defines its own `folder` or `document` Block type must set `accepts` on it.
- **Block UI.** The hover bar, the toolbar Block actions and the drag handle address the outermost block, so a caret in a list item or a quote paragraph acts on the whole list or quote ([Block UI](https://skaile-ai.github.io/forge-editor/guides/block-ui#where-block-actions-appear)).
- **Labels.** English: Typed block, Block type, Readable rendition, Theme with Default appearance, Document facts, Structure mode and Flat mode. German: Block and Blocktyp; the two German labels that still use the legacy words for basket and readable rendition stay. Message keys keep their IDs, so `messages` overrides still apply, but check the wording of an override against the new labels.

## Block types as data

A `BlockType` (`@skaile/forge-editor/composites`) is now an `id`, its presentation (`label`, `icon`, `titlePlaceholder`, `descriptionPlaceholder`, `chrome`) and a list `capabilities: { id, config? }[]`. The former switches move into it ([Typed blocks](https://skaile-ai.github.io/forge-editor/guides/composites)):

<table>
<thead>
  <tr>
    <th>
      Former field
    </th>
    
    <th>
      Now
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        fields: PropertyDefinition[]
      </code>
    </td>
    
    <td>
      <code>
        { id: 'properties', config: { definitions } }
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        source: ('image' | 'audio' | 'video' | 'file')[]
      </code>
    </td>
    
    <td>
      <code>
        { id: 'source', config: { media } }
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        accepts: string[] | 'all'
      </code>
    </td>
    
    <td>
      <code>
        { id: 'container', config: { accepts } }
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ai: BlockTypeAi
      </code>
    </td>
    
    <td>
      <code>
        { id: 'ai-brief', config: ai }
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      (every type had a Basket menu)
    </td>
    
    <td>
      <code>
        { id: 'basket' }
      </code>
      
      ; a type without it has no Basket menu
    </td>
  </tr>
  
  <tr>
    <td>
      a <code>
        bibliography
      </code>
      
       property implied the BibTeX export
    </td>
    
    <td>
      <code>
        { id: 'bibliography' }
      </code>
    </td>
  </tr>
</tbody>
</table>

A host list that spreads `defaultBlockTypes(t)` and adds its own types must give them the capabilities they need. An unknown capability id or an invalid config throws when the editor is created. `meta` keys and the `::: <Block type id>` Markdown fences keep their names; the node and its type attribute are renamed (below).

### Persisted names

Stored documents and settings use the vocabulary of the glossary. Everything saved before loads through a migration that reads the old names and never writes them back; hosts do nothing for stored data.

<table>
<thead>
  <tr>
    <th>
      Old
    </th>
    
    <th>
      New
    </th>
    
    <th>
      Where
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      node <code>
        composite
      </code>
    </td>
    
    <td>
      <code>
        typedBlock
      </code>
    </td>
    
    <td>
      document JSON, Yjs state, <code>
        .cdoc
      </code>
      
       packages, clipboard and drag payloads
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        compositeTitle
      </code>
      
      , <code>
        compositeDescription
      </code>
      
      , <code>
        compositeTags
      </code>
    </td>
    
    <td>
      <code>
        typedBlockTitle
      </code>
      
      , <code>
        typedBlockDescription
      </code>
      
      , <code>
        typedBlockTags
      </code>
    </td>
    
    <td>
      same
    </td>
  </tr>
  
  <tr>
    <td>
      attribute <code>
        kind
      </code>
      
       on the Typed block and on <code>
        opaqueFence
      </code>
    </td>
    
    <td>
      <code>
        blockType
      </code>
    </td>
    
    <td>
      same; block IDs (<code>
        attrs.id
      </code>
      
      ) and <code>
        meta
      </code>
      
       are untouched
    </td>
  </tr>
  
  <tr>
    <td>
      HTML <code>
        section[data-type="composite"][data-kind]
      </code>
    </td>
    
    <td>
      <code>
        section[data-type="typedBlock"][data-block-type]
      </code>
    </td>
    
    <td>
      clipboard HTML: both shapes parse, only the new one is written
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        BlockTransfer.kind
      </code>
      
       (drag payload on <code>
        application/x-tip-block
      </code>
      
      )
    </td>
    
    <td>
      <code>
        BlockTransfer.blockType
      </code>
    </td>
    
    <td>
      an old payload is read, its <code>
        json
      </code>
      
       migrated
    </td>
  </tr>
</tbody>
</table>

Markdown needs no migration: the fence is `::: <Block type id> #id {meta}` before and after, so old Markdown parses to Typed blocks and the export is byte-identical.

The server migrates Yjs state when a document loads (`onLoadDocument`, before any client syncs): it reads the schema-less JSON of the stored state, applies the same JSON migration and writes the result back with the block IDs and content unchanged, then persists the migrated state. A second load finds nothing to migrate. Client JSON goes through the rename in `defineEditor`, which runs ahead of any contributed `migrateContent` (the Typed blocks feature contributes the legacy-node migration), so a host hook cannot drop it.

Settings version 2 renamed four keys (table below). Saved settings (server store, `localStorage`) migrate on load and are rewritten once. The host config key change needs a code change (no migration).

<table>
<thead>
  <tr>
    <th>
      Old
    </th>
    
    <th>
      New
    </th>
    
    <th>
      Where
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        ai.slots
      </code>
    </td>
    
    <td>
      <code>
        ai.roles
      </code>
    </td>
    
    <td>
      settings; host config key (code change, no migration)
    </td>
  </tr>
  
  <tr>
    <td>
      wire key <code>
        slots
      </code>
      
       of <code>
        GET /api/ai/models
      </code>
    </td>
    
    <td>
      <code>
        roles
      </code>
    </td>
    
    <td>
      HTTP response
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        blocks.defaultKind
      </code>
    </td>
    
    <td>
      <code>
        blocks.defaultBlockType
      </code>
    </td>
    
    <td>
      settings
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        blocks.kindIcon
      </code>
    </td>
    
    <td>
      <code>
        blocks.blockTypeIcon
      </code>
    </td>
    
    <td>
      settings
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        blocks.structure
      </code>
      
       value <code>
        'composite'
      </code>
    </td>
    
    <td>
      <code>
        'structured'
      </code>
    </td>
    
    <td>
      settings
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        KIND_ICON_VISIBILITIES
      </code>
      
      , <code>
        KindIconVisibility
      </code>
    </td>
    
    <td>
      <code>
        BLOCK_TYPE_ICON_VISIBILITIES
      </code>
      
      , <code>
        BlockTypeIconVisibility
      </code>
    </td>
    
    <td>
      <code>
        @skaile/forge-editor/settings
      </code>
      
       (code names, nothing stored)
    </td>
  </tr>
</tbody>
</table>


## Sitemap

See the full [sitemap](https://skaile-ai.github.io/forge-editor/sitemap.md) for all pages.
