@ecsplico/editor 3.6.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +73 -0
- package/dist/adapters/direct-ai.d.ts +4 -4
- package/dist/adapters/direct-ai.js +2 -2
- package/dist/adapters/direct-ai.js.map +1 -1
- package/dist/adapters/document-state.d.ts +1 -1
- package/dist/adapters/document-state.js.map +1 -1
- package/dist/adapters/forge.d.ts +2 -2
- package/dist/adapters/forge.js.map +1 -1
- package/dist/adapters/nitro.d.ts +11 -3
- package/dist/adapters/nitro.js +3 -1
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/shared.d.ts +6 -6
- package/dist/adapters/shared.js.map +1 -1
- package/dist/code/CodeSurface.vue.d.ts +3 -3
- package/dist/config/index.d.ts +14 -14
- package/dist/config/index.js +8 -8
- package/dist/config/index.js.map +1 -1
- package/dist/core/backend-types.d.ts +3 -3
- package/dist/core/backend-types.js.map +1 -1
- package/dist/core/backend.d.ts +4 -4
- package/dist/core/backend.js.map +1 -1
- package/dist/core/block-convert.d.ts +1 -1
- package/dist/core/block-convert.js +5 -5
- package/dist/core/block-convert.js.map +1 -1
- package/dist/core/block-transfer.d.ts +8 -4
- package/dist/core/block-transfer.js +23 -14
- package/dist/core/block-transfer.js.map +1 -1
- package/dist/core/capabilities.d.ts +113 -0
- package/dist/core/capabilities.js +155 -0
- package/dist/core/capabilities.js.map +1 -0
- package/dist/core/command-types.d.ts +1 -1
- package/dist/core/context.js.map +1 -1
- package/dist/core/convert.d.ts +5 -5
- package/dist/core/convert.js +5 -5
- package/dist/core/convert.js.map +1 -1
- package/dist/core/core-feature.js +1 -1
- package/dist/core/define-editor.d.ts +2 -2
- package/dist/core/define-editor.js +34 -6
- package/dist/core/define-editor.js.map +1 -1
- package/dist/core/derivation.d.ts +119 -0
- package/dist/core/derivation.js +187 -0
- package/dist/core/derivation.js.map +1 -0
- package/dist/core/derive.d.ts +61 -0
- package/dist/core/derive.js +69 -0
- package/dist/core/derive.js.map +1 -0
- package/dist/core/extension-points.d.ts +16 -0
- package/dist/core/feature-context.d.ts +5 -1
- package/dist/core/feature-context.js +10 -3
- package/dist/core/feature-context.js.map +1 -1
- package/dist/core/feature.d.ts +41 -19
- package/dist/core/feature.js.map +1 -1
- package/dist/core/fences.js +1 -1
- package/dist/core/fences.js.map +1 -1
- package/dist/core/index.d.ts +6 -2
- package/dist/core/index.js +5 -1
- package/dist/core/pipeline.d.ts +14 -5
- package/dist/core/pipeline.js +19 -7
- package/dist/core/pipeline.js.map +1 -1
- package/dist/core/properties.d.ts +22 -0
- package/dist/core/properties.js +17 -0
- package/dist/core/properties.js.map +1 -0
- package/dist/core/schema/block-ids.js +5 -5
- package/dist/core/schema/block-ids.js.map +1 -1
- package/dist/core/schema/index.d.ts +2 -1
- package/dist/core/schema/index.js +2 -1
- package/dist/core/schema/index.js.map +1 -1
- package/dist/core/schema/opaque-fence.d.ts +4 -4
- package/dist/core/schema/opaque-fence.js +7 -7
- package/dist/core/schema/opaque-fence.js.map +1 -1
- package/dist/core/schema/persisted-names.d.ts +58 -0
- package/dist/core/schema/persisted-names.js +96 -0
- package/dist/core/schema/persisted-names.js.map +1 -0
- package/dist/core/toolbar-items.js +1 -1
- package/dist/core/toolbar-items.js.map +1 -1
- package/dist/core/util.js +5 -1
- package/dist/core/util.js.map +1 -1
- package/dist/document/DocumentSurface.vue.d.ts +3 -3
- package/dist/features/ai/agent-ops.js +1 -1
- package/dist/features/ai/ai-review.js +1 -1
- package/dist/features/ai/assistant.d.ts +4 -4
- package/dist/features/ai/assistant.js +1 -1
- package/dist/features/ai/assistant.js.map +1 -1
- package/dist/features/ai/components/AiSelectionMenu.js +1 -1
- package/dist/features/ai/components/AiSelectionMenu.js.map +1 -1
- package/dist/features/ai/components/ModelQuickSwitch.js +7 -7
- package/dist/features/ai/components/ModelQuickSwitch.js.map +1 -1
- package/dist/features/ai/components/ModelQuickSwitch.vue.d.ts +4 -4
- package/dist/features/ai/components/SettingsAiTab.js +8 -8
- package/dist/features/ai/components/SettingsAiTab.js.map +1 -1
- package/dist/features/ai/components/SettingsModelProfiles.js +1 -1
- package/dist/features/ai/components/SettingsModelProfiles.js.map +1 -1
- package/dist/features/ai/document-chat-model.d.ts +2 -2
- package/dist/features/ai/document-chat-model.js +5 -5
- package/dist/features/ai/document-chat-model.js.map +1 -1
- package/dist/features/ai/document-chat.js +2 -2
- package/dist/features/ai/document-chat.js.map +1 -1
- package/dist/features/ai/feature.d.ts +2 -2
- package/dist/features/ai/feature.js +2 -2
- package/dist/features/ai/feature.js.map +1 -1
- package/dist/features/ai/ghost-autocomplete.d.ts +4 -4
- package/dist/features/ai/ghost-autocomplete.js +1 -1
- package/dist/features/ai/ghost-autocomplete.js.map +1 -1
- package/dist/features/ai/index.d.ts +3 -3
- package/dist/features/ai/index.js +2 -2
- package/dist/features/ai/model-profiles.d.ts +9 -9
- package/dist/features/ai/model-profiles.js +13 -13
- package/dist/features/ai/model-profiles.js.map +1 -1
- package/dist/features/ai/protocol/agent-ops.d.ts +2 -2
- package/dist/features/ai/protocol/agent-ops.js +1 -1
- package/dist/features/ai/protocol/agent-ops.js.map +1 -1
- package/dist/features/ai/protocol/block-lines.d.ts +7 -7
- package/dist/features/ai/protocol/block-lines.js +10 -10
- package/dist/features/ai/protocol/block-lines.js.map +1 -1
- package/dist/features/ai/protocol/chat.d.ts +5 -5
- package/dist/features/ai/protocol/chat.js +12 -12
- package/dist/features/ai/protocol/chat.js.map +1 -1
- package/dist/features/ai/protocol/generate.d.ts +1 -1
- package/dist/features/ai/protocol/generate.js +1 -1
- package/dist/features/ai/protocol/generate.js.map +1 -1
- package/dist/features/ai/protocol/index.d.ts +3 -3
- package/dist/features/ai/protocol/index.js +2 -2
- package/dist/features/ai/protocol/models.d.ts +3 -3
- package/dist/features/ai/protocol/models.js +3 -3
- package/dist/features/ai/protocol/models.js.map +1 -1
- package/dist/features/ai/protocol/schemas.d.ts +1 -1
- package/dist/features/ai/protocol/schemas.js +1 -1
- package/dist/features/ai/protocol/schemas.js.map +1 -1
- package/dist/features/ai/protocol/tasks.d.ts +5 -5
- package/dist/features/ai/protocol/tasks.js +12 -12
- package/dist/features/ai/protocol/tasks.js.map +1 -1
- package/dist/features/ai/react/AiSelectionMenu.js.map +1 -1
- package/dist/features/ai/react/ModelQuickSwitch.d.ts +4 -4
- package/dist/features/ai/react/ModelQuickSwitch.js +6 -6
- package/dist/features/ai/react/ModelQuickSwitch.js.map +1 -1
- package/dist/features/ai/react/SettingsAiTab.d.ts +1 -1
- package/dist/features/ai/react/SettingsAiTab.js +8 -8
- package/dist/features/ai/react/SettingsAiTab.js.map +1 -1
- package/dist/features/ai/react/SettingsModelProfiles.d.ts +1 -1
- package/dist/features/ai/react/SettingsModelProfiles.js +1 -1
- package/dist/features/ai/react/SettingsModelProfiles.js.map +1 -1
- package/dist/features/ai/react/use-ai-assistant.d.ts +1 -1
- package/dist/features/ai/react/use-ai-assistant.js +1 -1
- package/dist/features/ai/react/use-ai-assistant.js.map +1 -1
- package/dist/features/ai/react/use-model-profiles.d.ts +5 -5
- package/dist/features/ai/react/use-model-profiles.js +2 -2
- package/dist/features/ai/react/use-model-profiles.js.map +1 -1
- package/dist/features/ai/use-ai-assistant.d.ts +1 -1
- package/dist/features/ai/use-ai-assistant.js +1 -1
- package/dist/features/ai/use-ai-assistant.js.map +1 -1
- package/dist/features/ai/use-model-profiles.d.ts +4 -4
- package/dist/features/ai/use-model-profiles.js +2 -2
- package/dist/features/ai/use-model-profiles.js.map +1 -1
- package/dist/features/block-ui/block-actions.d.ts +8 -4
- package/dist/features/block-ui/block-actions.js +38 -22
- package/dist/features/block-ui/block-actions.js.map +1 -1
- package/dist/features/block-ui/block-target.d.ts +29 -0
- package/dist/features/block-ui/block-target.js +63 -0
- package/dist/features/block-ui/block-target.js.map +1 -0
- package/dist/features/block-ui/components/BlockHandles.js +3 -3
- package/dist/features/block-ui/components/BlockHandles.js.map +1 -1
- package/dist/features/block-ui/components/BlockUi.js +11 -23
- package/dist/features/block-ui/components/BlockUi.js.map +1 -1
- package/dist/features/block-ui/feature.d.ts +3 -2
- package/dist/features/block-ui/feature.js +3 -2
- package/dist/features/block-ui/feature.js.map +1 -1
- package/dist/features/block-ui/handle-geometry.js +12 -23
- package/dist/features/block-ui/handle-geometry.js.map +1 -1
- package/dist/features/block-ui/index.d.ts +2 -1
- package/dist/features/block-ui/index.js +2 -1
- package/dist/features/block-ui/react/BlockHandles.d.ts +1 -1
- package/dist/features/block-ui/react/BlockHandles.js +4 -4
- package/dist/features/block-ui/react/BlockHandles.js.map +1 -1
- package/dist/features/block-ui/react/BlockUi.js +13 -25
- package/dist/features/block-ui/react/BlockUi.js.map +1 -1
- package/dist/features/comments/model.js +1 -1
- package/dist/features/composites/accepted-children.d.ts +5 -4
- package/dist/features/composites/accepted-children.js +26 -26
- package/dist/features/composites/accepted-children.js.map +1 -1
- package/dist/features/composites/ai-brief.d.ts +4 -4
- package/dist/features/composites/ai-brief.js +14 -12
- package/dist/features/composites/ai-brief.js.map +1 -1
- package/dist/features/composites/anchors.d.ts +1 -1
- package/dist/features/composites/anchors.js.map +1 -1
- package/dist/features/composites/baskets.d.ts +1 -1
- package/dist/features/composites/baskets.js.map +1 -1
- package/dist/features/composites/bibliography-command.d.ts +1 -1
- package/dist/features/composites/bibliography-form.js +1 -1
- package/dist/features/composites/bibliography-form.js.map +1 -1
- package/dist/features/composites/bibliography.js.map +1 -1
- package/dist/features/composites/block-types-json.d.ts +38 -0
- package/dist/features/composites/block-types-json.js +122 -0
- package/dist/features/composites/block-types-json.js.map +1 -0
- package/dist/features/composites/block-types.d.ts +119 -0
- package/dist/features/composites/block-types.js +343 -0
- package/dist/features/composites/block-types.js.map +1 -0
- package/dist/features/composites/capabilities.js +109 -0
- package/dist/features/composites/capabilities.js.map +1 -0
- package/dist/features/composites/components/BibliographyEditor.js +5 -5
- package/dist/features/composites/components/BibliographyEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeBasketMenu.js +2 -2
- package/dist/features/composites/components/CompositeBasketMenu.js.map +1 -1
- package/dist/features/composites/components/CompositeChrome.js +18 -8
- package/dist/features/composites/components/CompositeChrome.js.map +1 -1
- package/dist/features/composites/components/CompositeChrome.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeDetails.js +11 -10
- package/dist/features/composites/components/CompositeDetails.js.map +1 -1
- package/dist/features/composites/components/CompositeDetails.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeFieldEditor.js +7 -7
- package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeFieldEditor.vue.d.ts +5 -5
- package/dist/features/composites/components/CompositeInspector.js +136 -113
- package/dist/features/composites/components/CompositeInspector.js.map +1 -1
- package/dist/features/composites/components/CompositeInspector.vue.d.ts +3 -3
- package/dist/features/composites/components/CompositeStatusMenu.js +2 -2
- package/dist/features/composites/components/CompositeStatusMenu.js.map +1 -1
- package/dist/features/composites/components/CompositeSummaryEditor.js +1 -1
- package/dist/features/composites/components/CompositeSummaryEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeSummaryEditor.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeTable.js +2 -2
- package/dist/features/composites/components/CompositeTable.js.map +1 -1
- package/dist/features/composites/components/CompositeTagsEditor.js +1 -1
- package/dist/features/composites/components/CompositeTagsEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeTagsEditor.vue.d.ts +1 -1
- package/dist/features/composites/components/CompositeView.js +19 -17
- package/dist/features/composites/components/CompositeView.js.map +1 -1
- package/dist/features/composites/components/DerivationBadge.js +15 -6
- package/dist/features/composites/components/DerivationBadge.js.map +1 -1
- package/dist/features/composites/components/FocusChip.js +1 -1
- package/dist/features/composites/components/FocusChip.js.map +1 -1
- package/dist/features/composites/components/FocusChip.vue.d.ts +1 -1
- package/dist/features/composites/components/ReferenceFieldSelect.js +3 -3
- package/dist/features/composites/components/ReferenceFieldSelect.js.map +1 -1
- package/dist/features/composites/components/ReferenceView.js +1 -1
- package/dist/features/composites/components/ReferenceView.js.map +1 -1
- package/dist/features/composites/components/SettingsEditingTab.js +18 -18
- package/dist/features/composites/components/SettingsEditingTab.js.map +1 -1
- package/dist/features/composites/components/SettingsEditingTab.vue.d.ts +3 -3
- package/dist/features/composites/convert.d.ts +4 -4
- package/dist/features/composites/convert.js +27 -28
- package/dist/features/composites/convert.js.map +1 -1
- package/dist/features/composites/derived-chrome.js +34 -28
- package/dist/features/composites/derived-chrome.js.map +1 -1
- package/dist/features/composites/editing-settings-keys.js +6 -6
- package/dist/features/composites/editing-settings-keys.js.map +1 -1
- package/dist/features/composites/feature.d.ts +10 -10
- package/dist/features/composites/feature.js +58 -46
- package/dist/features/composites/feature.js.map +1 -1
- package/dist/features/composites/fences.d.ts +3 -3
- package/dist/features/composites/fences.js +18 -13
- package/dist/features/composites/fences.js.map +1 -1
- package/dist/features/composites/focus.d.ts +10 -10
- package/dist/features/composites/focus.js +11 -11
- package/dist/features/composites/focus.js.map +1 -1
- package/dist/features/composites/heading-composites.d.ts +5 -5
- package/dist/features/composites/heading-composites.js +13 -16
- package/dist/features/composites/heading-composites.js.map +1 -1
- package/dist/features/composites/index.d.ts +20 -18
- package/dist/features/composites/index.js +9 -7
- package/dist/features/composites/inspector-model.d.ts +45 -22
- package/dist/features/composites/inspector-model.js +53 -14
- package/dist/features/composites/inspector-model.js.map +1 -1
- package/dist/features/composites/legacy.d.ts +5 -4
- package/dist/features/composites/legacy.js +16 -23
- package/dist/features/composites/legacy.js.map +1 -1
- package/dist/features/composites/markdown-export.js +3 -3
- package/dist/features/composites/markdown-export.js.map +1 -1
- package/dist/features/composites/merge.d.ts +8 -8
- package/dist/features/composites/merge.js +23 -22
- package/dist/features/composites/merge.js.map +1 -1
- package/dist/features/composites/meta-display.js +5 -5
- package/dist/features/composites/meta-display.js.map +1 -1
- package/dist/features/composites/meta-keys.d.ts +5 -5
- package/dist/features/composites/meta-keys.js +8 -8
- package/dist/features/composites/meta-keys.js.map +1 -1
- package/dist/features/composites/node-views.d.ts +3 -3
- package/dist/features/composites/node-views.js +2 -2
- package/dist/features/composites/node-views.js.map +1 -1
- package/dist/features/composites/nodes.d.ts +13 -13
- package/dist/features/composites/nodes.js +100 -77
- package/dist/features/composites/nodes.js.map +1 -1
- package/dist/features/composites/outline.d.ts +15 -12
- package/dist/features/composites/outline.js +24 -21
- package/dist/features/composites/outline.js.map +1 -1
- package/dist/features/composites/properties.d.ts +51 -0
- package/dist/features/composites/properties.js +89 -0
- package/dist/features/composites/properties.js.map +1 -0
- package/dist/features/composites/react/BibliographyEditor.js +5 -5
- package/dist/features/composites/react/BibliographyEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeBasketMenu.js +2 -2
- package/dist/features/composites/react/CompositeBasketMenu.js.map +1 -1
- package/dist/features/composites/react/CompositeChrome.d.ts +1 -1
- package/dist/features/composites/react/CompositeChrome.js +15 -6
- package/dist/features/composites/react/CompositeChrome.js.map +1 -1
- package/dist/features/composites/react/CompositeDetails.d.ts +1 -1
- package/dist/features/composites/react/CompositeDetails.js +11 -10
- package/dist/features/composites/react/CompositeDetails.js.map +1 -1
- package/dist/features/composites/react/CompositeFieldEditor.d.ts +5 -5
- package/dist/features/composites/react/CompositeFieldEditor.js +6 -6
- package/dist/features/composites/react/CompositeFieldEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeInspector.d.ts +3 -3
- package/dist/features/composites/react/CompositeInspector.js +142 -128
- package/dist/features/composites/react/CompositeInspector.js.map +1 -1
- package/dist/features/composites/react/CompositeStatusMenu.js +2 -2
- package/dist/features/composites/react/CompositeStatusMenu.js.map +1 -1
- package/dist/features/composites/react/CompositeSummaryEditor.d.ts +1 -1
- package/dist/features/composites/react/CompositeSummaryEditor.js +1 -1
- package/dist/features/composites/react/CompositeSummaryEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeTable.d.ts +1 -1
- package/dist/features/composites/react/CompositeTable.js +3 -3
- package/dist/features/composites/react/CompositeTable.js.map +1 -1
- package/dist/features/composites/react/CompositeTagsEditor.d.ts +1 -1
- package/dist/features/composites/react/CompositeTagsEditor.js +1 -1
- package/dist/features/composites/react/CompositeTagsEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeView.js +17 -15
- package/dist/features/composites/react/CompositeView.js.map +1 -1
- package/dist/features/composites/react/DerivationBadge.js +13 -4
- package/dist/features/composites/react/DerivationBadge.js.map +1 -1
- package/dist/features/composites/react/FocusChip.d.ts +1 -1
- package/dist/features/composites/react/FocusChip.js +1 -1
- package/dist/features/composites/react/FocusChip.js.map +1 -1
- package/dist/features/composites/react/ReferenceFieldSelect.js +3 -3
- package/dist/features/composites/react/ReferenceFieldSelect.js.map +1 -1
- package/dist/features/composites/react/ReferenceView.d.ts +1 -1
- package/dist/features/composites/react/ReferenceView.js +1 -1
- package/dist/features/composites/react/ReferenceView.js.map +1 -1
- package/dist/features/composites/react/SettingsEditingTab.d.ts +4 -4
- package/dist/features/composites/react/SettingsEditingTab.js +20 -20
- package/dist/features/composites/react/SettingsEditingTab.js.map +1 -1
- package/dist/features/composites/react.js +1 -1
- package/dist/features/composites/react.js.map +1 -1
- package/dist/features/composites/reference-ai.js +1 -1
- package/dist/features/composites/reference-ai.js.map +1 -1
- package/dist/features/composites/reference-label.d.ts +3 -3
- package/dist/features/composites/reference-label.js +6 -6
- package/dist/features/composites/reference-label.js.map +1 -1
- package/dist/features/composites/reference-suggestion.d.ts +1 -1
- package/dist/features/composites/reference-suggestion.js +3 -3
- package/dist/features/composites/reference-suggestion.js.map +1 -1
- package/dist/features/composites/reference-text.d.ts +2 -2
- package/dist/features/composites/reference-text.js +4 -4
- package/dist/features/composites/reference-text.js.map +1 -1
- package/dist/features/composites/reference.d.ts +3 -3
- package/dist/features/composites/reference.js +1 -1
- package/dist/features/composites/reference.js.map +1 -1
- package/dist/features/composites/reveal-source.d.ts +3 -3
- package/dist/features/composites/reveal-source.js +6 -6
- package/dist/features/composites/reveal-source.js.map +1 -1
- package/dist/features/composites/rows-model.d.ts +2 -2
- package/dist/features/composites/rows-model.js +4 -3
- package/dist/features/composites/rows-model.js.map +1 -1
- package/dist/features/composites/rows.d.ts +16 -28
- package/dist/features/composites/rows.js +20 -54
- package/dist/features/composites/rows.js.map +1 -1
- package/dist/features/composites/schema.d.ts +12 -11
- package/dist/features/composites/schema.js +10 -9
- package/dist/features/composites/schema.js.map +1 -1
- package/dist/features/composites/source.d.ts +20 -0
- package/dist/features/composites/source.js +40 -0
- package/dist/features/composites/source.js.map +1 -0
- package/dist/features/composites/split.d.ts +11 -11
- package/dist/features/composites/split.js +20 -20
- package/dist/features/composites/split.js.map +1 -1
- package/dist/features/composites/structure-mode.js +3 -3
- package/dist/features/composites/structure-mode.js.map +1 -1
- package/dist/features/composites/table-model.js +2 -2
- package/dist/features/composites/table-model.js.map +1 -1
- package/dist/features/composites/use-composite-inspector.js +3 -1
- package/dist/features/composites/use-composite-inspector.js.map +1 -1
- package/dist/features/composites/use-composite-rows.d.ts +2 -2
- package/dist/features/composites/use-composite-rows.js.map +1 -1
- package/dist/features/composites/vue.js +1 -1
- package/dist/features/composites/vue.js.map +1 -1
- package/dist/features/image-studio/components/ImageStudioDialog.js +150 -87
- package/dist/features/image-studio/components/ImageStudioDialog.js.map +1 -1
- package/dist/features/image-studio/components/ImageStudioDialog.vue.d.ts +5 -1
- package/dist/features/image-studio/components/ImageStudioLibraryPanel.js +186 -0
- package/dist/features/image-studio/components/ImageStudioLibraryPanel.js.map +1 -0
- package/dist/features/image-studio/components/ImageStudioLibraryTile.js +134 -0
- package/dist/features/image-studio/components/ImageStudioLibraryTile.js.map +1 -0
- package/dist/features/image-studio/components/ImageStudioView.js.map +1 -1
- package/dist/features/image-studio/feature.d.ts +1 -1
- package/dist/features/image-studio/feature.js +1 -1
- package/dist/features/image-studio/feature.js.map +1 -1
- package/dist/features/image-studio/index.d.ts +3 -2
- package/dist/features/image-studio/index.js +2 -2
- package/dist/features/image-studio/library.d.ts +35 -0
- package/dist/features/image-studio/node-core.d.ts +3 -3
- package/dist/features/image-studio/node-core.js +1 -1
- package/dist/features/image-studio/node-core.js.map +1 -1
- package/dist/features/image-studio/node-store.d.ts +1 -1
- package/dist/features/image-studio/node-store.js +1 -1
- package/dist/features/image-studio/node-store.js.map +1 -1
- package/dist/features/image-studio/react/ImageStudioDialog.d.ts +1 -1
- package/dist/features/image-studio/react/ImageStudioDialog.js +46 -5
- package/dist/features/image-studio/react/ImageStudioDialog.js.map +1 -1
- package/dist/features/image-studio/react/ImageStudioLibraryPanel.js +141 -0
- package/dist/features/image-studio/react/ImageStudioLibraryPanel.js.map +1 -0
- package/dist/features/image-studio/react/ImageStudioLibraryTile.js +105 -0
- package/dist/features/image-studio/react/ImageStudioLibraryTile.js.map +1 -0
- package/dist/features/image-studio/react/ImageStudioView.js +1 -1
- package/dist/features/image-studio/react/ImageStudioView.js.map +1 -1
- package/dist/features/image-studio/react/store.d.ts +8 -3
- package/dist/features/image-studio/react/store.js.map +1 -1
- package/dist/features/image-studio/react.d.ts +4 -3
- package/dist/features/image-studio/react.js +3 -3
- package/dist/features/image-studio/react.js.map +1 -1
- package/dist/features/image-studio/schema.d.ts +1 -1
- package/dist/features/image-studio/schema.js +1 -1
- package/dist/features/image-studio/schema.js.map +1 -1
- package/dist/features/image-studio/state.d.ts +8 -3
- package/dist/features/image-studio/state.js +11 -3
- package/dist/features/image-studio/state.js.map +1 -1
- package/dist/features/image-studio/store.d.ts +8 -3
- package/dist/features/image-studio/vue.d.ts +4 -3
- package/dist/features/image-studio/vue.js +3 -3
- package/dist/features/image-studio/vue.js.map +1 -1
- package/dist/features/mentions/tag.js +2 -1
- package/dist/features/mentions/tag.js.map +1 -1
- package/dist/features/themes/components/SettingsAppearanceTab.js +1 -1
- package/dist/features/themes/components/SettingsAppearanceTab.js.map +1 -1
- package/dist/features/themes/feature.d.ts +1 -1
- package/dist/features/themes/feature.js.map +1 -1
- package/dist/features/themes/react/SettingsAppearanceTab.d.ts +1 -1
- package/dist/features/themes/react/SettingsAppearanceTab.js +1 -1
- package/dist/features/themes/react/SettingsAppearanceTab.js.map +1 -1
- package/dist/features/themes/theme-runtime.js +1 -1
- package/dist/features/themes/theme-runtime.js.map +1 -1
- package/dist/features/transcript/TranscriptSegmentView.js +1 -1
- package/dist/features/transcript/TranscriptSegmentView.js.map +1 -1
- package/dist/features/transcript/react/TranscriptSegmentView.js +1 -1
- package/dist/features/transcript/react/TranscriptSegmentView.js.map +1 -1
- package/dist/features/transcript/segment-node.js.map +1 -1
- package/dist/features/transfer/feature.js +1 -1
- package/dist/features/transfer/feature.js.map +1 -1
- package/dist/features/transfer/transforms.d.ts +4 -4
- package/dist/features/transfer/transforms.js +12 -12
- package/dist/features/transfer/transforms.js.map +1 -1
- package/dist/i18n/de/ai.js +4 -4
- package/dist/i18n/de/ai.js.map +1 -1
- package/dist/i18n/de/authors.js +1 -1
- package/dist/i18n/de/authors.js.map +1 -1
- package/dist/i18n/de/comments.js +1 -1
- package/dist/i18n/de/comments.js.map +1 -1
- package/dist/i18n/de/composites.js +62 -59
- package/dist/i18n/de/composites.js.map +1 -1
- package/dist/i18n/de/image-studio.js +11 -2
- package/dist/i18n/de/image-studio.js.map +1 -1
- package/dist/i18n/de/integrations.js +20 -20
- package/dist/i18n/de/integrations.js.map +1 -1
- package/dist/i18n/de/markdown.js +1 -1
- package/dist/i18n/de/markdown.js.map +1 -1
- package/dist/i18n/de/palette.js +1 -1
- package/dist/i18n/de/palette.js.map +1 -1
- package/dist/i18n/de/themes.js +3 -3
- package/dist/i18n/de/themes.js.map +1 -1
- package/dist/i18n/de/transfer.js +2 -2
- package/dist/i18n/de/transfer.js.map +1 -1
- package/dist/i18n/de/tree.js +6 -6
- package/dist/i18n/de/tree.js.map +1 -1
- package/dist/i18n/de.d.ts +110 -98
- package/dist/i18n/en/ai.js +2 -2
- package/dist/i18n/en/ai.js.map +1 -1
- package/dist/i18n/en/composites.js +64 -61
- package/dist/i18n/en/composites.js.map +1 -1
- package/dist/i18n/en/image-studio.js +9 -0
- package/dist/i18n/en/image-studio.js.map +1 -1
- package/dist/i18n/en/integrations.js +9 -9
- package/dist/i18n/en/integrations.js.map +1 -1
- package/dist/i18n/en/markdown.js +1 -1
- package/dist/i18n/en/markdown.js.map +1 -1
- package/dist/i18n/en/palette.js +1 -1
- package/dist/i18n/en/palette.js.map +1 -1
- package/dist/i18n/en/themes.js +4 -4
- package/dist/i18n/en/themes.js.map +1 -1
- package/dist/i18n/en/tree.js +5 -5
- package/dist/i18n/en/tree.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/integrations/composite-ai/bibliography-fetch.d.ts +6 -6
- package/dist/integrations/composite-ai/bibliography-fetch.js +19 -19
- package/dist/integrations/composite-ai/bibliography-fetch.js.map +1 -1
- package/dist/integrations/composite-ai/composite-fill.d.ts +4 -4
- package/dist/integrations/composite-ai/composite-fill.js +5 -5
- package/dist/integrations/composite-ai/composite-fill.js.map +1 -1
- package/dist/integrations/composite-ai/composite-summary.d.ts +2 -2
- package/dist/integrations/composite-ai/composite-summary.js +5 -5
- package/dist/integrations/composite-ai/composite-summary.js.map +1 -1
- package/dist/integrations/composite-ai/derive.d.ts +17 -17
- package/dist/integrations/composite-ai/derive.js +27 -26
- package/dist/integrations/composite-ai/derive.js.map +1 -1
- package/dist/integrations/composite-ai/index.d.ts +14 -15
- package/dist/integrations/composite-ai/index.js +98 -77
- package/dist/integrations/composite-ai/index.js.map +1 -1
- package/dist/integrations/composite-ai/outline-sanitize.d.ts +1 -1
- package/dist/integrations/composite-ai/outline-sanitize.js +1 -1
- package/dist/integrations/composite-ai/outline-sanitize.js.map +1 -1
- package/dist/integrations/composite-ai/rendition.d.ts +9 -9
- package/dist/integrations/composite-ai/rendition.js +27 -27
- package/dist/integrations/composite-ai/rendition.js.map +1 -1
- package/dist/integrations/composite-ai/split.d.ts +8 -8
- package/dist/integrations/composite-ai/split.js +12 -12
- package/dist/integrations/composite-ai/split.js.map +1 -1
- package/dist/integrations/composite-ai/transfer-transforms.d.ts +2 -2
- package/dist/integrations/composite-ai/transfer-transforms.js +11 -11
- package/dist/integrations/composite-ai/transfer-transforms.js.map +1 -1
- package/dist/integrations/composite-media/index.d.ts +4 -3
- package/dist/integrations/composite-media/index.js +20 -14
- package/dist/integrations/composite-media/index.js.map +1 -1
- package/dist/markdown/MarkdownSurface.vue.d.ts +7 -7
- package/dist/markdown/document.js +1 -1
- package/dist/markdown/document.js.map +1 -1
- package/dist/nuxt/module.d.ts +48 -24
- package/dist/nuxt/module.js.map +1 -1
- package/dist/nuxt/runtime/server/plugins/editor-server.js +3 -2
- package/dist/nuxt/runtime/server/plugins/editor-server.js.map +1 -1
- package/dist/presets/compose.d.ts +6 -6
- package/dist/presets/compose.js +7 -4
- package/dist/presets/compose.js.map +1 -1
- package/dist/react/AdvancedEditor.d.ts +2 -2
- package/dist/react/AdvancedEditor.js +1 -1
- package/dist/react/AdvancedEditor.js.map +1 -1
- package/dist/react/compose.d.ts +1 -1
- package/dist/react/compose.js +1 -1
- package/dist/react/compose.js.map +1 -1
- package/dist/react/composed-surface.d.ts +5 -5
- package/dist/react/composed-surface.js +2 -2
- package/dist/react/composed-surface.js.map +1 -1
- package/dist/server/ai.d.ts +7 -7
- package/dist/server/ai.js +1 -1
- package/dist/server/ai.js.map +1 -1
- package/dist/server/auth.d.ts +1 -1
- package/dist/server/collab-state.d.ts +1 -1
- package/dist/server/collab-state.js.map +1 -1
- package/dist/server/collab.d.ts +4 -4
- package/dist/server/collab.js +22 -17
- package/dist/server/collab.js.map +1 -1
- package/dist/server/handlers/ai.d.ts +9 -6
- package/dist/server/handlers/ai.js +13 -17
- package/dist/server/handlers/ai.js.map +1 -1
- package/dist/server/handlers/context.d.ts +4 -0
- package/dist/server/handlers/context.js.map +1 -1
- package/dist/server/handlers/editor.d.ts +33 -32
- package/dist/server/handlers/editor.js +13 -8
- package/dist/server/handlers/editor.js.map +1 -1
- package/dist/server/handlers/images.d.ts +1 -1
- package/dist/server/handlers/images.js +1 -1
- package/dist/server/handlers/images.js.map +1 -1
- package/dist/server/host.d.ts +4 -0
- package/dist/server/host.js +10 -2
- package/dist/server/host.js.map +1 -1
- package/dist/server/index.d.ts +3 -3
- package/dist/server/ports.d.ts +8 -8
- package/dist/server/ports.js.map +1 -1
- package/dist/settings/index.d.ts +20 -19
- package/dist/settings/index.js +25 -24
- package/dist/settings/index.js.map +1 -1
- package/dist/settings/migrate.d.ts +18 -0
- package/dist/settings/migrate.js +46 -0
- package/dist/settings/migrate.js.map +1 -0
- package/dist/settings/values.d.ts +12 -12
- package/dist/settings/values.js +11 -11
- package/dist/settings/values.js.map +1 -1
- package/dist/styles/composites.css +10 -10
- package/dist/tree/DocumentTree.js +12 -5
- package/dist/tree/DocumentTree.js.map +1 -1
- package/dist/tree/drop-rules.js +5 -5
- package/dist/tree/drop-rules.js.map +1 -1
- package/dist/tree/react/DocumentTree.js +14 -5
- package/dist/tree/react/DocumentTree.js.map +1 -1
- package/dist/tree/tree-host.js +5 -5
- package/dist/tree/tree-host.js.map +1 -1
- package/dist/tree/tree-items.js +34 -28
- package/dist/tree/tree-items.js.map +1 -1
- package/dist/tree/tree-model.js +16 -16
- package/dist/tree/tree-model.js.map +1 -1
- package/dist/tree/tree-rows.js +2 -2
- package/dist/tree/tree-rows.js.map +1 -1
- package/dist/tree/tree-view-model.d.ts +2 -2
- package/dist/tree/tree-view-model.js.map +1 -1
- package/dist/vue/AdvancedEditor.js +2 -2
- package/dist/vue/AdvancedEditor.js.map +1 -1
- package/dist/vue/AdvancedEditor.vue.d.ts +10 -10
- package/dist/vue/SimpleEditor.vue.d.ts +4 -4
- package/dist/vue/components/EditorSurface.vue.d.ts +4 -4
- package/dist/vue/compose.d.ts +1 -1
- package/dist/vue/compose.js +1 -1
- package/dist/vue/compose.js.map +1 -1
- package/package.json +1 -1
- package/dist/features/composites/derivation.d.ts +0 -62
- package/dist/features/composites/derivation.js +0 -102
- package/dist/features/composites/derivation.js.map +0 -1
- package/dist/features/composites/kinds.d.ts +0 -89
- package/dist/features/composites/kinds.js +0 -285
- package/dist/features/composites/kinds.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose.js","names":[],"sources":["../../src/presets/compose.ts"],"sourcesContent":["import type { EditorBackend } from '../core/backend'\nimport { coreContentFeature, coreUiFeature } from '../core/core-feature'\nimport { defineEditor } from '../core/define-editor'\nimport type { BlockUiOptions } from '../core/extension-points'\nimport type { Dimension, EditorFeature, EditorPreset } from '../core/feature'\nimport type { CoreContentOptions } from '../core/schema'\nimport type { CommentsFeatureOptions } from '../features/comments/feature'\nimport { CommentMark } from '../features/comments/schema'\nimport type { CompositeFeatureOptions } from '../features/composites/feature'\nimport type { Basket } from '../features/composites/baskets'\nimport type { CompositeKind } from '../features/composites/kinds'\nimport { mentionsFeature } from '../features/mentions'\nimport type { TransferFeatureOptions } from '../features/transfer/feature'\nimport { type BlockTransform, copyTransform } from '../features/transfer/transforms'\nimport { tablesFeature } from '../features/tables'\nimport { compositeMediaFeature } from '../integrations/composite-media'\n\n/** The id of a catalog feature (`CONTENT`, `INTERACTION`, `AI`) or of a host feature passed to `remove`. */\nexport type FeatureId = string\n\n/** How much document model the editor has: `basic` = `core-content`, `rich` = the full content catalog. */\nexport type ContentLevel = 'basic' | 'rich'\n\n/** How much editing UX the editor has: `minimal` = `core-ui`, `full` = every interaction feature. */\nexport type InteractionLevel = 'minimal' | 'full'\n\n/**\n * The features a UI layer binds, keyed by id; the other catalog features are framework-free and built here. The AI\n * features are bound too, although `composite-ai` and `transcript-ai` have no components: the layer owns every import of\n * `features/ai`, so a composition without `ai` binds none of them and its bundle holds no AI code. Each binding is a\n * factory, called only for a feature the composition selects (`themes` reads the current Vue app when built, so\n * unselected features are never built). `composites` receives the composition's `compositeKinds` and `compositeBaskets`, `comments` its\n * `comments` options. `core-ui` takes no parameter here: the framework-free `simpleEditor()` has no command palette;\n * a layer that has one (the `SimpleEditor` surfaces) builds `coreUiFeature({ palette })` itself.\n */\nexport interface UiBindings<C> {\n 'core-ui': () => EditorFeature<C>\n 'media': () => EditorFeature<C>\n 'transcript': () => EditorFeature<C>\n 'composites': (options: CompositeFeatureOptions) => EditorFeature<C>\n 'authors': () => EditorFeature<C>\n 'comments': (options: CommentsFeatureOptions) => EditorFeature<C>\n 'ai': () => EditorFeature<C>\n 'composite-ai': () => EditorFeature<C>\n 'transcript-ai': () => EditorFeature<C>\n 'collab': () => EditorFeature<C>\n 'block-ui': (options: BlockUiOptions) => EditorFeature<C>\n 'themes': () => EditorFeature<C>\n 'transfer': (options: TransferFeatureOptions) => EditorFeature<C>\n /** The AI transforms of the transfer menu (`summaryTransform`, `bulletsTransform` of `integrations/composite-ai`); called only when `ai` is on and the host passes no `transfer.transforms`. */\n 'transfer-ai': () => readonly BlockTransform[]\n}\n\n/** What `composeEditor` builds the editor from. */\nexport interface ComposeOptions<C> {\n /** The document model: a level or the content feature ids to install (`core-content` is always installed). */\n content: ContentLevel | readonly FeatureId[]\n /** The editing UX: a level or the interaction feature ids (`core-ui` is installed with any non-empty list); `[]` = a viewer without any interaction feature. */\n interaction: InteractionLevel | readonly FeatureId[]\n /** Installs `ai` and every integration whose `requires` are met (composite-AI iff composites, transcript-AI iff transcript). */\n ai: boolean\n /** The backend the editor runs on: features needing a capability it lacks are omitted. Absent = nothing is pruned by capability. */\n backend?: EditorBackend\n /**\n * The host supplies the collaboration session itself (the surface's `collaboration` prop, e.g. from its own Hocuspocus\n * provider), so `collab` and `comments` need no `collaboration` capability from the backend. Only a backend that must\n * open the collaboration (`useEditorDocument(id, { collaboration: true })`) has to offer it. Default `false`.\n */\n collaboration?: boolean\n /** Host features, appended after the catalog in the given order. */\n add?: readonly EditorFeature<C>[]\n /** Features left out (catalog or host); features that require them are omitted as well. */\n remove?: readonly FeatureId[]\n /** The composite kinds („Bausteine“) offered in the editor (default: the built-in kinds); read once. */\n compositeKinds?: readonly CompositeKind[]\n /** The colour baskets a Baustein can be put into (default: the built-in red/orange/yellow/green/blue set); read once. */\n compositeBaskets?: readonly Basket[]\n /** Options of the comments feature, e.g. a host `model` (then comments need no `collab`). */\n comments?: CommentsFeatureOptions\n /** Optional structures the content base drops (headings or heading levels, lists, blockquote, code block, rule); everything is on by default. Applies to the editor and to the server schema built from the preset's `schemaExtensions`. */\n coreContent?: CoreContentOptions\n /** Options of the block UI (`block-ui`, `interaction: 'full'`): which surfaces render block actions (hover bar, selected-block toolbar, both, none); the hover bar by default. */\n blockUi?: BlockUiOptions\n /** Options of the transfer feature (`interaction: [..., 'transfer']`; in no level list): the transforms a drop offers (default: the copy, plus the AI transforms when `ai` is on) and the default one. */\n transfer?: TransferFeatureOptions\n}\n\n/** The composed preset and the features that were selected but dropped, in composition order, with the reason. */\nexport interface ComposedEditor<C> extends EditorPreset<C> {\n readonly omitted: readonly { id: FeatureId, reason: string }[]\n}\n\nfunction fail(message: string): never {\n throw new Error(`@ecsplico/editor: composeEditor: ${message}`)\n}\n\n/** The binding `key` of `ui`; a framework binding the composition needs but `ui` lacks fails here, naming it. */\nfunction bound<C, K extends keyof UiBindings<C>>(ui: Partial<UiBindings<C>>, key: K): UiBindings<C>[K] {\n return ui[key] ?? fail(`no UI binding for feature \"${key}\"`)\n}\n\n/** One row of the catalog: where the feature sits, which level lists hold it, and how it is built from the options. */\ninterface CatalogEntry<C> {\n dimension: Dimension\n /** The level lists (`CONTENT`, `INTERACTION`) that include it; none for AI features, which `ai: true` installs. */\n levels?: readonly (ContentLevel | InteractionLevel)[]\n /** `ui` is partial on purpose: a host that never selects a feature (a viewer has no `block-ui`) binds only the rest, so the bundle holds no code of the others. */\n build: (ui: Partial<UiBindings<C>>, options: ComposeOptions<C>) => EditorFeature<C>\n}\n\n/**\n * The catalog: the one table that drives composition. Its key order is the canonical order (content, interaction, AI):\n * the composed feature list, its schema order and its toolbar order follow it, and `CONTENT`, `INTERACTION`, `AI` are\n * derived from it. Adding a catalog feature is one row here, plus, for a UI-bound feature, a key in `UiBindings` and an\n * entry in both binding records (`vue/compose.ts`, `react/compose.ts`; their `satisfies UiBindings` check fails until\n * they hold it). Framework-free features are called directly, UI-bound ones go through `bound`.\n */\n// `any`: the table is module-level and shared by every UI layer; each `build` is typed by `UiBindings<C>` of its caller.\nconst CATALOG: Record<FeatureId, CatalogEntry<any>> = {\n 'core-content': { dimension: 'content', levels: ['basic', 'rich'], build: (_, options) => coreContentFeature(options.coreContent) },\n 'media': { dimension: 'content', levels: ['rich'], build: ui => bound(ui, 'media')() },\n 'transcript': { dimension: 'content', levels: ['rich'], build: ui => bound(ui, 'transcript')() },\n 'composites': { dimension: 'content', levels: ['rich'], build: (ui, options) => bound(ui, 'composites')({ ...(options.compositeKinds && { kinds: options.compositeKinds }), ...(options.compositeBaskets && { baskets: options.compositeBaskets }) }) },\n 'mentions': { dimension: 'content', levels: ['rich'], build: () => mentionsFeature() },\n 'authors': { dimension: 'content', levels: ['rich'], build: ui => bound(ui, 'authors')() },\n 'tables': { dimension: 'content', levels: ['rich'], build: () => tablesFeature() },\n 'composite-media': { dimension: 'content', levels: ['rich'], build: () => compositeMediaFeature() },\n 'core-ui': { dimension: 'interaction', levels: ['minimal', 'full'], build: ui => bound(ui, 'core-ui')() },\n 'collab': { dimension: 'interaction', levels: ['full'], build: ui => bound(ui, 'collab')() },\n 'comments': { dimension: 'interaction', levels: ['full'], build: (ui, options) => bound(ui, 'comments')(options.comments ?? {}) },\n 'block-ui': { dimension: 'interaction', levels: ['full'], build: (ui, options) => bound(ui, 'block-ui')(options.blockUi ?? {}) },\n 'themes': { dimension: 'interaction', levels: ['full'], build: ui => bound(ui, 'themes')() },\n // In no level list: a host opts in with `interaction: [...INTERACTION.full, 'transfer']`. With `ai` on the menu also offers the AI transforms (bound by the layer, which owns every import of `features/ai`), unless the host passes its own `transfer.transforms`.\n 'transfer': { dimension: 'interaction', build: (ui, options) => bound(ui, 'transfer')({ ...options.transfer, ...(!options.transfer?.transforms && options.ai && { transforms: [copyTransform, ...bound(ui, 'transfer-ai')()] }) }) },\n 'ai': { dimension: 'ai', build: ui => bound(ui, 'ai')() },\n 'composite-ai': { dimension: 'ai', build: ui => bound(ui, 'composite-ai')() },\n 'transcript-ai': { dimension: 'ai', build: ui => bound(ui, 'transcript-ai')() },\n}\n\nconst catalogIds = (include: (entry: CatalogEntry<unknown>) => boolean): readonly FeatureId[] =>\n Object.entries(CATALOG).filter(([, entry]) => include(entry)).map(([id]) => id)\nconst levelIds = (level: ContentLevel | InteractionLevel) => catalogIds(entry => entry.levels?.includes(level) ?? false)\n\n/** The content features of each level, in canonical (schema) order. */\nexport const CONTENT: Record<ContentLevel, readonly FeatureId[]> = { basic: levelIds('basic'), rich: levelIds('rich') }\n\n/** The interaction features of each level, in canonical order. */\nexport const INTERACTION: Record<InteractionLevel, readonly FeatureId[]> = { minimal: levelIds('minimal'), full: levelIds('full') }\n\n/** The AI features (`ai: true`): the AI feature and the integrations that need it; each is installed when its `requires` are met. */\nexport const AI: readonly FeatureId[] = catalogIds(entry => entry.dimension === 'ai')\n\n/** Canonical feature order: the key order of the catalog (content, interaction, AI). */\nconst CANONICAL: readonly FeatureId[] = Object.keys(CATALOG)\n\n/** Builds the catalog feature `id`; an id outside the catalog or a missing binding fails, naming it. */\nfunction build<C>(id: FeatureId, ui: Partial<UiBindings<C>>, options: ComposeOptions<C>): EditorFeature<C> {\n const entry = Object.hasOwn(CATALOG, id) ? CATALOG[id] : undefined\n if (!entry) fail(`unknown catalog feature \"${id}\" (host features go in \\`add\\`)`)\n return entry.build(ui, options)\n}\n\n/** Why `feature` cannot stay in a composition holding `ids` over `backend`, or `undefined`. A host session satisfies `collaboration`. */\nfunction unmet(feature: Pick<EditorFeature, 'backend' | 'requires'>, ids: ReadonlySet<FeatureId>, options: Pick<ComposeOptions<unknown>, 'backend' | 'collaboration'>): string | undefined {\n const { backend } = options\n for (const capability of feature.backend ?? []) {\n if (capability === 'collaboration' && options.collaboration) continue\n if (backend && backend[capability] === undefined) return `backend \"${backend.name}\" lacks \"${capability}\"`\n }\n for (const required of feature.requires ?? []) {\n if (!ids.has(required)) return `requires \"${required}\"`\n }\n return undefined\n}\n\n/**\n * The comment mark is part of the document model (stored documents carry it), but only the `comments` feature brings it.\n * A composition that keeps `authors` (every rich one) yet has no `comments` (a viewer, a backend without collaboration,\n * `remove`) gets the mark through `authors`, inert there, so such documents still load. The catalog is the one place\n * that may couple the two features; each stays importable on its own.\n */\nfunction withCommentMark<C>(features: readonly EditorFeature<C>[]): EditorFeature<C>[] {\n if (features.some(feature => feature.id === 'comments')) return [...features]\n return features.map(feature => feature.id !== 'authors'\n ? feature\n : {\n ...feature,\n schemaExtensions: () => [...(feature.schemaExtensions?.() ?? []), CommentMark],\n extensions: ctx => [...(feature.extensions?.(ctx) ?? []), CommentMark],\n })\n}\n\n/**\n * Composes an editor from three dimensions plus the backend's capabilities, over the UI bindings of a layer.\n *\n * The feature list is `content` + `interaction` (+ the AI features when `ai`) + `add`, minus `remove`. `core-content` is\n * always part of it and `core-ui` of every non-empty interaction list. Features that require a missing feature, or a\n * backend capability `options.backend` lacks, are dropped until the list is stable and reported in `omitted` (so\n * `ai: true` over a backend without `ai` installs no AI and says why). The catalog features keep their canonical order\n * (content, interaction, AI), host features follow in the order given; the result is validated by `defineEditor`.\n * Throws when an id of `content` is not a content feature, an id of `interaction` not an interaction feature, an id\n * names no catalog feature, `remove` names `core-content`, or a selected feature has no binding in `ui`.\n */\nexport function composeEditor<C>(ui: Partial<UiBindings<C>>, options: ComposeOptions<C>): ComposedEditor<C> {\n if (options.remove?.includes('core-content')) fail('\"core-content\" cannot be removed')\n const removed = new Set(options.remove ?? [])\n const catalog = new Map<FeatureId, EditorFeature<C>>()\n const select = (ids: readonly FeatureId[], dimension: 'content' | 'interaction' | 'ai') => {\n for (const id of ids) {\n if (removed.has(id) || catalog.has(id)) continue\n const feature = build(id, ui, options)\n if (feature.dimension !== dimension) fail(`\"${id}\" is not ${dimension === 'ai' ? 'an AI' : `a${dimension === 'interaction' ? 'n' : ''} ${dimension}`} feature`)\n catalog.set(id, feature)\n }\n }\n const content = typeof options.content === 'string' ? CONTENT[options.content] : options.content\n const interaction = typeof options.interaction === 'string' ? INTERACTION[options.interaction] : options.interaction\n select(['core-content', ...content], 'content')\n select(interaction.length ? ['core-ui', ...interaction] : [], 'interaction')\n select(options.ai ? AI : [], 'ai')\n\n const ordered = [...catalog.values()].sort((a, b) => CANONICAL.indexOf(a.id) - CANONICAL.indexOf(b.id))\n const all: EditorFeature<C>[] = [...ordered, ...(options.add ?? []).filter(feature => !removed.has(feature.id))]\n\n const reasons = new Map<FeatureId, string>()\n let alive = all\n for (;;) {\n const ids = new Set(alive.map(feature => feature.id))\n const dropped = new Map<FeatureId, string>()\n for (const feature of alive) {\n const reason = unmet(feature, ids, options)\n if (reason) dropped.set(feature.id, reason)\n }\n if (!dropped.size) break\n for (const [id, reason] of dropped) reasons.set(id, reason)\n alive = alive.filter(feature => !dropped.has(feature.id))\n }\n\n const preset = defineEditor({ features: withCommentMark(alive) })\n const omitted = all.flatMap(feature => reasons.has(feature.id) ? [{ id: feature.id, reason: reasons.get(feature.id)! }] : [])\n return Object.freeze({ ...preset, omitted: Object.freeze(omitted) })\n}\n\n/**\n * The simple editor: `core-content` and `core-ui` (formatting, headings, lists, quotes, code, undo/redo). No backend, no AI,\n * no collaboration, and no ⌘K command palette (`coreUiFeature()` gets no `palette` component here, the framework-free\n * layer has none; the `SimpleEditor` components and the `composeEditor` of `/vue/advanced` and `/react/advanced` bind it).\n * Component-free (`ComposedEditor<never>`), so both the Vue and the React surface accept it.\n */\nexport const simpleEditor = (): ComposedEditor<never> => composeEditor<never>({ 'core-ui': coreUiFeature }, { content: 'basic', interaction: 'minimal', ai: false })\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"compose.js","names":[],"sources":["../../src/presets/compose.ts"],"sourcesContent":["import type { EditorBackend } from '../core/backend'\nimport { coreContentFeature, coreUiFeature } from '../core/core-feature'\nimport { defineEditor } from '../core/define-editor'\nimport type { BlockUiOptions } from '../core/extension-points'\nimport type { Dimension, EditorFeature, EditorPreset } from '../core/feature'\nimport type { CoreContentOptions } from '../core/schema'\nimport type { CommentsFeatureOptions } from '../features/comments/feature'\nimport { CommentMark } from '../features/comments/schema'\nimport type { CompositeFeatureOptions } from '../features/composites/feature'\nimport type { Basket } from '../features/composites/baskets'\nimport type { BlockType } from '../features/composites/block-types'\nimport { mentionsFeature } from '../features/mentions'\nimport type { TransferFeatureOptions } from '../features/transfer/feature'\nimport { type BlockTransform, copyTransform } from '../features/transfer/transforms'\nimport { tablesFeature } from '../features/tables'\nimport { compositeMediaFeature } from '../integrations/composite-media'\n\n/** The id of a catalog feature (`CONTENT`, `INTERACTION`, `AI`) or of a host feature passed to `remove`. */\nexport type FeatureId = string\n\n/** How much document model the editor has: `basic` = `core-content`, `rich` = the full content catalog. */\nexport type ContentLevel = 'basic' | 'rich'\n\n/** How much editing UX the editor has: `minimal` = `core-ui`, `full` = every interaction feature. */\nexport type InteractionLevel = 'minimal' | 'full'\n\n/**\n * The features a UI layer binds, keyed by id; the other catalog features are framework-free and built here. The AI\n * features are bound too, although `composite-ai` and `transcript-ai` have no components: the layer owns every import of\n * `features/ai`, so a composition without `ai` binds none of them and its bundle holds no AI code. Each binding is a\n * factory, called only for a feature the composition selects (`themes` reads the current Vue app when built, so\n * unselected features are never built). `composites` receives the composition's `blockTypes` and `compositeBaskets`, `comments` its\n * `comments` options. `core-ui` takes no parameter here: the framework-free `simpleEditor()` has no command palette;\n * a layer that has one (the `SimpleEditor` surfaces) builds `coreUiFeature({ palette })` itself.\n */\nexport interface UiBindings<C> {\n 'core-ui': () => EditorFeature<C>\n 'media': () => EditorFeature<C>\n 'transcript': () => EditorFeature<C>\n 'composites': (options: CompositeFeatureOptions) => EditorFeature<C>\n 'authors': () => EditorFeature<C>\n 'comments': (options: CommentsFeatureOptions) => EditorFeature<C>\n 'ai': () => EditorFeature<C>\n 'composite-ai': () => EditorFeature<C>\n 'transcript-ai': () => EditorFeature<C>\n 'collab': () => EditorFeature<C>\n 'block-ui': (options: BlockUiOptions) => EditorFeature<C>\n 'themes': () => EditorFeature<C>\n 'transfer': (options: TransferFeatureOptions) => EditorFeature<C>\n /** The AI transforms of the transfer menu (`summaryTransform`, `bulletsTransform` of `integrations/composite-ai`); called only when `ai` is on and the host passes no `transfer.transforms`. */\n 'transfer-ai': () => readonly BlockTransform[]\n}\n\n/** What `composeEditor` builds the editor from. */\nexport interface ComposeOptions<C> {\n /** The document model: a level or the content feature ids to install (`core-content` is always installed). */\n content: ContentLevel | readonly FeatureId[]\n /** The editing UX: a level or the interaction feature ids (`core-ui` is installed with any non-empty list); `[]` = a viewer without any interaction feature. */\n interaction: InteractionLevel | readonly FeatureId[]\n /** Installs `ai` and every integration whose `requires` are met (composite-AI iff composites, transcript-AI iff transcript). */\n ai: boolean\n /** The backend the editor runs on: features needing a capability it lacks are omitted. Absent = nothing is pruned by capability. */\n backend?: EditorBackend\n /**\n * The host supplies the collaboration session itself (the surface's `collaboration` prop, e.g. from its own Hocuspocus\n * provider), so `collab` and `comments` need no `collaboration` capability from the backend. Only a backend that must\n * open the collaboration (`useEditorDocument(id, { collaboration: true })`) has to offer it. Default `false`.\n */\n collaboration?: boolean\n /** Host features, appended after the catalog in the given order. */\n add?: readonly EditorFeature<C>[]\n /** Features left out (catalog or host); features that require them are omitted as well. */\n remove?: readonly FeatureId[]\n /** The Block types offered in the editor (default: the built-in Block types); read once. */\n blockTypes?: readonly BlockType[]\n /** The colour baskets a Typed block can be put into (default: the built-in red/orange/yellow/green/blue set); read once. */\n compositeBaskets?: readonly Basket[]\n /** Options of the comments feature, e.g. a host `model` (then comments need no `collab`). */\n comments?: CommentsFeatureOptions\n /** Optional structures the content base drops (headings or heading levels, lists, blockquote, code block, rule); everything is on by default. Applies to the editor and to the server schema built from the preset's `schemaExtensions`. */\n coreContent?: CoreContentOptions\n /** Options of the block UI (`block-ui`, `interaction: 'full'`): which surfaces render block actions (hover bar, selected-block toolbar, both, none); the hover bar by default. */\n blockUi?: BlockUiOptions\n /** Options of the transfer feature (`interaction: [..., 'transfer']`; in no level list): the transforms a drop offers (default: the copy, plus the AI transforms when `ai` is on) and the default one. */\n transfer?: TransferFeatureOptions\n}\n\n/** The composed preset and the features that were selected but dropped, in composition order, with the reason. */\nexport interface ComposedEditor<C> extends EditorPreset<C> {\n readonly omitted: readonly { id: FeatureId, reason: string }[]\n}\n\nfunction fail(message: string): never {\n throw new Error(`@ecsplico/editor: composeEditor: ${message}`)\n}\n\n/** The binding `key` of `ui`; a framework binding the composition needs but `ui` lacks fails here, naming it. */\nfunction bound<C, K extends keyof UiBindings<C>>(ui: Partial<UiBindings<C>>, key: K): UiBindings<C>[K] {\n return ui[key] ?? fail(`no UI binding for feature \"${key}\"`)\n}\n\n/** One row of the catalog: where the feature sits, which level lists hold it, and how it is built from the options. */\ninterface CatalogEntry<C> {\n dimension: Dimension\n /** The level lists (`CONTENT`, `INTERACTION`) that include it; none for AI features, which `ai: true` installs. */\n levels?: readonly (ContentLevel | InteractionLevel)[]\n /** `ui` is partial on purpose: a host that never selects a feature (a viewer has no `block-ui`) binds only the rest, so the bundle holds no code of the others. */\n build: (ui: Partial<UiBindings<C>>, options: ComposeOptions<C>) => EditorFeature<C>\n}\n\n/**\n * The catalog: the one table that drives composition. Its key order is the canonical order (content, interaction, AI):\n * the composed feature list, its schema order and its toolbar order follow it, and `CONTENT`, `INTERACTION`, `AI` are\n * derived from it. Adding a catalog feature is one row here, plus, for a UI-bound feature, a key in `UiBindings` and an\n * entry in both binding records (`vue/compose.ts`, `react/compose.ts`; their `satisfies UiBindings` check fails until\n * they hold it). Framework-free features are called directly, UI-bound ones go through `bound`.\n */\n// `any`: the table is module-level and shared by every UI layer; each `build` is typed by `UiBindings<C>` of its caller.\nconst CATALOG: Record<FeatureId, CatalogEntry<any>> = {\n 'core-content': { dimension: 'content', levels: ['basic', 'rich'], build: (_, options) => coreContentFeature(options.coreContent) },\n 'media': { dimension: 'content', levels: ['rich'], build: ui => bound(ui, 'media')() },\n 'transcript': { dimension: 'content', levels: ['rich'], build: ui => bound(ui, 'transcript')() },\n 'composites': {\n dimension: 'content',\n levels: ['rich'],\n build: (ui, options) => {\n const { blockTypes } = options\n return bound(ui, 'composites')({ ...(blockTypes && { blockTypes }), ...(options.compositeBaskets && { baskets: options.compositeBaskets }) })\n },\n },\n 'mentions': { dimension: 'content', levels: ['rich'], build: () => mentionsFeature() },\n 'authors': { dimension: 'content', levels: ['rich'], build: ui => bound(ui, 'authors')() },\n 'tables': { dimension: 'content', levels: ['rich'], build: () => tablesFeature() },\n 'composite-media': { dimension: 'content', levels: ['rich'], build: () => compositeMediaFeature() },\n 'core-ui': { dimension: 'interaction', levels: ['minimal', 'full'], build: ui => bound(ui, 'core-ui')() },\n 'collab': { dimension: 'interaction', levels: ['full'], build: ui => bound(ui, 'collab')() },\n 'comments': { dimension: 'interaction', levels: ['full'], build: (ui, options) => bound(ui, 'comments')(options.comments ?? {}) },\n 'block-ui': { dimension: 'interaction', levels: ['full'], build: (ui, options) => bound(ui, 'block-ui')(options.blockUi ?? {}) },\n 'themes': { dimension: 'interaction', levels: ['full'], build: ui => bound(ui, 'themes')() },\n // In no level list: a host opts in with `interaction: [...INTERACTION.full, 'transfer']`. With `ai` on the menu also offers the AI transforms (bound by the layer, which owns every import of `features/ai`), unless the host passes its own `transfer.transforms`.\n 'transfer': { dimension: 'interaction', build: (ui, options) => bound(ui, 'transfer')({ ...options.transfer, ...(!options.transfer?.transforms && options.ai && { transforms: [copyTransform, ...bound(ui, 'transfer-ai')()] }) }) },\n 'ai': { dimension: 'ai', build: ui => bound(ui, 'ai')() },\n 'composite-ai': { dimension: 'ai', build: ui => bound(ui, 'composite-ai')() },\n 'transcript-ai': { dimension: 'ai', build: ui => bound(ui, 'transcript-ai')() },\n}\n\nconst catalogIds = (include: (entry: CatalogEntry<unknown>) => boolean): readonly FeatureId[] =>\n Object.entries(CATALOG).filter(([, entry]) => include(entry)).map(([id]) => id)\nconst levelIds = (level: ContentLevel | InteractionLevel) => catalogIds(entry => entry.levels?.includes(level) ?? false)\n\n/** The content features of each level, in canonical (schema) order. */\nexport const CONTENT: Record<ContentLevel, readonly FeatureId[]> = { basic: levelIds('basic'), rich: levelIds('rich') }\n\n/** The interaction features of each level, in canonical order. */\nexport const INTERACTION: Record<InteractionLevel, readonly FeatureId[]> = { minimal: levelIds('minimal'), full: levelIds('full') }\n\n/** The AI features (`ai: true`): the AI feature and the integrations that need it; each is installed when its `requires` are met. */\nexport const AI: readonly FeatureId[] = catalogIds(entry => entry.dimension === 'ai')\n\n/** Canonical feature order: the key order of the catalog (content, interaction, AI). */\nconst CANONICAL: readonly FeatureId[] = Object.keys(CATALOG)\n\n/** Builds the catalog feature `id`; an id outside the catalog or a missing binding fails, naming it. */\nfunction build<C>(id: FeatureId, ui: Partial<UiBindings<C>>, options: ComposeOptions<C>): EditorFeature<C> {\n const entry = Object.hasOwn(CATALOG, id) ? CATALOG[id] : undefined\n if (!entry) fail(`unknown catalog feature \"${id}\" (host features go in \\`add\\`)`)\n return entry.build(ui, options)\n}\n\n/** Why `feature` cannot stay in a composition holding `ids` over `backend`, or `undefined`. A host session satisfies `collaboration`. */\nfunction unmet(feature: Pick<EditorFeature, 'backend' | 'requires'>, ids: ReadonlySet<FeatureId>, options: Pick<ComposeOptions<unknown>, 'backend' | 'collaboration'>): string | undefined {\n const { backend } = options\n for (const capability of feature.backend ?? []) {\n if (capability === 'collaboration' && options.collaboration) continue\n if (backend && backend[capability] === undefined) return `backend \"${backend.name}\" lacks \"${capability}\"`\n }\n for (const required of feature.requires ?? []) {\n if (!ids.has(required)) return `requires \"${required}\"`\n }\n return undefined\n}\n\n/**\n * The comment mark is part of the document model (stored documents carry it), but only the `comments` feature brings it.\n * A composition that keeps `authors` (every rich one) yet has no `comments` (a viewer, a backend without collaboration,\n * `remove`) gets the mark through `authors`, inert there, so such documents still load. The catalog is the one place\n * that may couple the two features; each stays importable on its own.\n */\nfunction withCommentMark<C>(features: readonly EditorFeature<C>[]): EditorFeature<C>[] {\n if (features.some(feature => feature.id === 'comments')) return [...features]\n return features.map(feature => feature.id !== 'authors'\n ? feature\n : {\n ...feature,\n schemaExtensions: () => [...(feature.schemaExtensions?.() ?? []), CommentMark],\n extensions: ctx => [...(feature.extensions?.(ctx) ?? []), CommentMark],\n })\n}\n\n/**\n * Composes an editor from three dimensions plus the backend's capabilities, over the UI bindings of a layer.\n *\n * The feature list is `content` + `interaction` (+ the AI features when `ai`) + `add`, minus `remove`. `core-content` is\n * always part of it and `core-ui` of every non-empty interaction list. Features that require a missing feature, or a\n * backend capability `options.backend` lacks, are dropped until the list is stable and reported in `omitted` (so\n * `ai: true` over a backend without `ai` installs no AI and says why). The catalog features keep their canonical order\n * (content, interaction, AI), host features follow in the order given; the result is validated by `defineEditor`.\n * Throws when an id of `content` is not a content feature, an id of `interaction` not an interaction feature, an id\n * names no catalog feature, `remove` names `core-content`, or a selected feature has no binding in `ui`.\n */\nexport function composeEditor<C>(ui: Partial<UiBindings<C>>, options: ComposeOptions<C>): ComposedEditor<C> {\n if (options.remove?.includes('core-content')) fail('\"core-content\" cannot be removed')\n const removed = new Set(options.remove ?? [])\n const catalog = new Map<FeatureId, EditorFeature<C>>()\n const select = (ids: readonly FeatureId[], dimension: 'content' | 'interaction' | 'ai') => {\n for (const id of ids) {\n if (removed.has(id) || catalog.has(id)) continue\n const feature = build(id, ui, options)\n if (feature.dimension !== dimension) fail(`\"${id}\" is not ${dimension === 'ai' ? 'an AI' : `a${dimension === 'interaction' ? 'n' : ''} ${dimension}`} feature`)\n catalog.set(id, feature)\n }\n }\n const content = typeof options.content === 'string' ? CONTENT[options.content] : options.content\n const interaction = typeof options.interaction === 'string' ? INTERACTION[options.interaction] : options.interaction\n select(['core-content', ...content], 'content')\n select(interaction.length ? ['core-ui', ...interaction] : [], 'interaction')\n select(options.ai ? AI : [], 'ai')\n\n const ordered = [...catalog.values()].sort((a, b) => CANONICAL.indexOf(a.id) - CANONICAL.indexOf(b.id))\n const all: EditorFeature<C>[] = [...ordered, ...(options.add ?? []).filter(feature => !removed.has(feature.id))]\n\n const reasons = new Map<FeatureId, string>()\n let alive = all\n for (;;) {\n const ids = new Set(alive.map(feature => feature.id))\n const dropped = new Map<FeatureId, string>()\n for (const feature of alive) {\n const reason = unmet(feature, ids, options)\n if (reason) dropped.set(feature.id, reason)\n }\n if (!dropped.size) break\n for (const [id, reason] of dropped) reasons.set(id, reason)\n alive = alive.filter(feature => !dropped.has(feature.id))\n }\n\n const preset = defineEditor({ features: withCommentMark(alive) })\n const omitted = all.flatMap(feature => reasons.has(feature.id) ? [{ id: feature.id, reason: reasons.get(feature.id)! }] : [])\n return Object.freeze({ ...preset, omitted: Object.freeze(omitted) })\n}\n\n/**\n * The simple editor: `core-content` and `core-ui` (formatting, headings, lists, quotes, code, undo/redo). No backend, no AI,\n * no collaboration, and no ⌘K command palette (`coreUiFeature()` gets no `palette` component here, the framework-free\n * layer has none; the `SimpleEditor` components and the `composeEditor` of `/vue/advanced` and `/react/advanced` bind it).\n * Component-free (`ComposedEditor<never>`), so both the Vue and the React surface accept it.\n */\nexport const simpleEditor = (): ComposedEditor<never> => composeEditor<never>({ 'core-ui': coreUiFeature }, { content: 'basic', interaction: 'minimal', ai: false })\n"],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ import { ComposedEditorHandle, ComposedEditorProps } from "./composed-surface.js
|
|
|
4
4
|
* Props of the advanced editor: the surface's own (collaboration session or standalone `value`/`onChange`, metadata,
|
|
5
5
|
* abilities, extensions, block actions, commands, `documentId`, `editable`, `settingsUi`, the open state of the sidebar
|
|
6
6
|
* and comments margin, `onReady` and the other callbacks) except the preset, plus the composition: `content`,
|
|
7
|
-
* `interaction`, `ai`, `add`, `remove`, `backend` and the
|
|
7
|
+
* `interaction`, `ai`, `add`, `remove`, `backend` and the Block types. The defaults are the advanced editor's:
|
|
8
8
|
* `content: 'rich'`, `interaction: 'full'`, `ai: true`.
|
|
9
9
|
*/
|
|
10
10
|
export type AdvancedEditorProps = ComposedEditorProps;
|
|
@@ -12,7 +12,7 @@ export type AdvancedEditorProps = ComposedEditorProps;
|
|
|
12
12
|
* The advanced editor on the React surface: `composeEditor({ content: 'rich', interaction: 'full', ai: true })` mounted
|
|
13
13
|
* through `EditorSurface`; every dimension is overridable by its prop, and the backend (default: the editor context's)
|
|
14
14
|
* prunes what it cannot serve. The ref's `preset` is the composed preset (`omitted` lists the dropped features). The
|
|
15
|
-
* composition is fixed at mount like the
|
|
15
|
+
* composition is fixed at mount like the Block types it is built from; hosts remount (`key`) to change it. Place
|
|
16
16
|
* `EditorToolbar` and, with `settingsUi: 'external'`, `EditorSettingsModal`/`EditorSettingsPanel` beside it and give
|
|
17
17
|
* them the editor from `onReady`; `useEditorUi(editor)` reaches the chrome of a ready editor. Collaboration is active
|
|
18
18
|
* only when a `collaboration` session is passed; mount `Toaster` once for notices.
|
|
@@ -6,7 +6,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
6
6
|
* The advanced editor on the React surface: `composeEditor({ content: 'rich', interaction: 'full', ai: true })` mounted
|
|
7
7
|
* through `EditorSurface`; every dimension is overridable by its prop, and the backend (default: the editor context's)
|
|
8
8
|
* prunes what it cannot serve. The ref's `preset` is the composed preset (`omitted` lists the dropped features). The
|
|
9
|
-
* composition is fixed at mount like the
|
|
9
|
+
* composition is fixed at mount like the Block types it is built from; hosts remount (`key`) to change it. Place
|
|
10
10
|
* `EditorToolbar` and, with `settingsUi: 'external'`, `EditorSettingsModal`/`EditorSettingsPanel` beside it and give
|
|
11
11
|
* them the editor from `onReady`; `useEditorUi(editor)` reaches the chrome of a ready editor. Collaboration is active
|
|
12
12
|
* only when a `collaboration` session is passed; mount `Toaster` once for notices.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdvancedEditor.js","names":[],"sources":["../../src/react/AdvancedEditor.tsx"],"sourcesContent":["import { forwardRef } from 'react'\nimport { ComposedSurface, type ComposedEditorHandle, type ComposedEditorProps } from './composed-surface'\n\nexport type { ComposedEditorHandle as AdvancedEditorHandle }\n\n/**\n * Props of the advanced editor: the surface's own (collaboration session or standalone `value`/`onChange`, metadata,\n * abilities, extensions, block actions, commands, `documentId`, `editable`, `settingsUi`, the open state of the sidebar\n * and comments margin, `onReady` and the other callbacks) except the preset, plus the composition: `content`,\n * `interaction`, `ai`, `add`, `remove`, `backend` and the
|
|
1
|
+
{"version":3,"file":"AdvancedEditor.js","names":[],"sources":["../../src/react/AdvancedEditor.tsx"],"sourcesContent":["import { forwardRef } from 'react'\nimport { ComposedSurface, type ComposedEditorHandle, type ComposedEditorProps } from './composed-surface'\n\nexport type { ComposedEditorHandle as AdvancedEditorHandle }\n\n/**\n * Props of the advanced editor: the surface's own (collaboration session or standalone `value`/`onChange`, metadata,\n * abilities, extensions, block actions, commands, `documentId`, `editable`, `settingsUi`, the open state of the sidebar\n * and comments margin, `onReady` and the other callbacks) except the preset, plus the composition: `content`,\n * `interaction`, `ai`, `add`, `remove`, `backend` and the Block types. The defaults are the advanced editor's:\n * `content: 'rich'`, `interaction: 'full'`, `ai: true`.\n */\nexport type AdvancedEditorProps = ComposedEditorProps\n\n/**\n * The advanced editor on the React surface: `composeEditor({ content: 'rich', interaction: 'full', ai: true })` mounted\n * through `EditorSurface`; every dimension is overridable by its prop, and the backend (default: the editor context's)\n * prunes what it cannot serve. The ref's `preset` is the composed preset (`omitted` lists the dropped features). The\n * composition is fixed at mount like the Block types it is built from; hosts remount (`key`) to change it. Place\n * `EditorToolbar` and, with `settingsUi: 'external'`, `EditorSettingsModal`/`EditorSettingsPanel` beside it and give\n * them the editor from `onReady`; `useEditorUi(editor)` reaches the chrome of a ready editor. Collaboration is active\n * only when a `collaboration` session is passed; mount `Toaster` once for notices.\n */\nexport const AdvancedEditor = forwardRef<ComposedEditorHandle, AdvancedEditorProps>(function AdvancedEditor({ content = 'rich', interaction = 'full', ai = true, ...rest }, ref) {\n return <ComposedSurface ref={ref} content={content} interaction={interaction} ai={ai} {...rest} />\n})\n"],"mappings":";;;;;;;;;;;;;AAuBA,MAAa,iBAAiB,WAAsD,SAAS,eAAe,EAAE,UAAU,QAAQ,cAAc,QAAQ,KAAK,MAAM,GAAG,QAAQ,KAAK;CAC/K,OAAO,oBAAC,iBAAD;EAAsB;EAAc;EAAsB;EAAiB;EAAI,GAAI;CAAO,CAAA;AACnG,CAAC"}
|
package/dist/react/compose.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ type ReactComponent = ComponentType<{
|
|
|
12
12
|
export declare const composeEditor: (options: ComposeOptions<ReactComponent>) => ComposedEditor<ReactComponent>;
|
|
13
13
|
/**
|
|
14
14
|
* The advanced editor on the React surface: `{ content: 'rich', interaction: 'full', ai: true }`, every dimension option
|
|
15
|
-
* overridable (`
|
|
15
|
+
* overridable (`blockTypes`, `backend`, `add`, `remove`, ...), so the schema is the one of `advancedSchemaExtensions()`.
|
|
16
16
|
*/
|
|
17
17
|
export declare const advancedEditor: (options?: Partial<ComposeOptions<ReactComponent>>) => ComposedEditor<ReactComponent>;
|
|
18
18
|
//#endregion
|
package/dist/react/compose.js
CHANGED
|
@@ -39,7 +39,7 @@ const REACT_BINDINGS = {
|
|
|
39
39
|
const composeEditor = (options) => composeEditor$1(REACT_BINDINGS, options);
|
|
40
40
|
/**
|
|
41
41
|
* The advanced editor on the React surface: `{ content: 'rich', interaction: 'full', ai: true }`, every dimension option
|
|
42
|
-
* overridable (`
|
|
42
|
+
* overridable (`blockTypes`, `backend`, `add`, `remove`, ...), so the schema is the one of `advancedSchemaExtensions()`.
|
|
43
43
|
*/
|
|
44
44
|
const advancedEditor = (options = {}) => composeEditor({
|
|
45
45
|
content: "rich",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose.js","names":["compose"],"sources":["../../src/react/compose.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { ComponentType } from 'react'\nimport { coreUiFeature } from '../core/core-feature'\nimport { EditorCommandPalette } from './EditorCommandPalette'\nimport { aiFeature } from '../features/ai/react'\nimport { authorsFeature } from '../features/authors/react'\nimport { blockUiFeature } from '../features/block-ui/react'\nimport { collabFeature } from '../features/collab/react'\nimport { commentsFeature } from '../features/comments/react'\nimport { compositeFeature } from '../features/composites/react'\nimport { mediaFeature } from '../features/media/react'\nimport { themesFeature } from '../features/themes/react'\nimport { transferFeature } from '../features/transfer/react'\nimport { transcriptFeature } from '../features/transcript/react'\nimport { bulletsTransform, compositeAiFeature, summaryTransform } from '../integrations/composite-ai'\nimport { transcriptAiFeature } from '../integrations/transcript-ai'\nimport { type ComposedEditor, type ComposeOptions, composeEditor as compose, type UiBindings } from '../presets/compose'\n\ntype ReactComponent = ComponentType<{ editor: Editor }>\n\n/** The React bindings of every UI-bound catalog feature. */\nconst REACT_BINDINGS = {\n 'core-ui': () => coreUiFeature<ReactComponent>({ palette: EditorCommandPalette }),\n 'media': mediaFeature,\n 'transcript': transcriptFeature,\n 'composites': compositeFeature,\n 'authors': authorsFeature,\n 'comments': commentsFeature,\n 'ai': aiFeature,\n 'composite-ai': compositeAiFeature,\n 'transcript-ai': transcriptAiFeature,\n 'collab': collabFeature,\n 'block-ui': blockUiFeature,\n 'themes': themesFeature,\n 'transfer': transferFeature,\n 'transfer-ai': () => [summaryTransform, bulletsTransform],\n} satisfies UiBindings<ReactComponent>\n\n/**\n * `composeEditor` of `presets/compose` over the React bindings: the editor of the three dimensions (`content`,\n * `interaction`, `ai`), pruned by the capabilities of `options.backend`.\n */\nexport const composeEditor = (options: ComposeOptions<ReactComponent>): ComposedEditor<ReactComponent> => compose(REACT_BINDINGS, options)\n\n/**\n * The advanced editor on the React surface: `{ content: 'rich', interaction: 'full', ai: true }`, every dimension option\n * overridable (`
|
|
1
|
+
{"version":3,"file":"compose.js","names":["compose"],"sources":["../../src/react/compose.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { ComponentType } from 'react'\nimport { coreUiFeature } from '../core/core-feature'\nimport { EditorCommandPalette } from './EditorCommandPalette'\nimport { aiFeature } from '../features/ai/react'\nimport { authorsFeature } from '../features/authors/react'\nimport { blockUiFeature } from '../features/block-ui/react'\nimport { collabFeature } from '../features/collab/react'\nimport { commentsFeature } from '../features/comments/react'\nimport { compositeFeature } from '../features/composites/react'\nimport { mediaFeature } from '../features/media/react'\nimport { themesFeature } from '../features/themes/react'\nimport { transferFeature } from '../features/transfer/react'\nimport { transcriptFeature } from '../features/transcript/react'\nimport { bulletsTransform, compositeAiFeature, summaryTransform } from '../integrations/composite-ai'\nimport { transcriptAiFeature } from '../integrations/transcript-ai'\nimport { type ComposedEditor, type ComposeOptions, composeEditor as compose, type UiBindings } from '../presets/compose'\n\ntype ReactComponent = ComponentType<{ editor: Editor }>\n\n/** The React bindings of every UI-bound catalog feature. */\nconst REACT_BINDINGS = {\n 'core-ui': () => coreUiFeature<ReactComponent>({ palette: EditorCommandPalette }),\n 'media': mediaFeature,\n 'transcript': transcriptFeature,\n 'composites': compositeFeature,\n 'authors': authorsFeature,\n 'comments': commentsFeature,\n 'ai': aiFeature,\n 'composite-ai': compositeAiFeature,\n 'transcript-ai': transcriptAiFeature,\n 'collab': collabFeature,\n 'block-ui': blockUiFeature,\n 'themes': themesFeature,\n 'transfer': transferFeature,\n 'transfer-ai': () => [summaryTransform, bulletsTransform],\n} satisfies UiBindings<ReactComponent>\n\n/**\n * `composeEditor` of `presets/compose` over the React bindings: the editor of the three dimensions (`content`,\n * `interaction`, `ai`), pruned by the capabilities of `options.backend`.\n */\nexport const composeEditor = (options: ComposeOptions<ReactComponent>): ComposedEditor<ReactComponent> => compose(REACT_BINDINGS, options)\n\n/**\n * The advanced editor on the React surface: `{ content: 'rich', interaction: 'full', ai: true }`, every dimension option\n * overridable (`blockTypes`, `backend`, `add`, `remove`, ...), so the schema is the one of `advancedSchemaExtensions()`.\n */\nexport const advancedEditor = (options: Partial<ComposeOptions<ReactComponent>> = {}): ComposedEditor<ReactComponent> => composeEditor({ content: 'rich', interaction: 'full', ai: true, ...options })\n"],"mappings":";;;;;;;;;;;;;;;;;;AAqBA,MAAM,iBAAiB;CACrB,iBAAiB,cAA8B,EAAE,SAAS,qBAAqB,CAAC;CAChF,SAAS;CACT,cAAc;CACd,cAAc;CACd,WAAW;CACX,YAAY;CACZ,MAAM;CACN,gBAAgB;CAChB,iBAAiB;CACjB,UAAU;CACV,YAAY;CACZ,UAAU;CACV,YAAY;CACZ,qBAAqB,CAAC,kBAAkB,gBAAgB;AAC1D;;;;;AAMA,MAAa,iBAAiB,YAA4EA,gBAAQ,gBAAgB,OAAO;;;;;AAMzI,MAAa,kBAAkB,UAAmD,CAAC,MAAsC,cAAc;CAAE,SAAS;CAAQ,aAAa;CAAQ,IAAI;CAAM,GAAG;AAAQ,CAAC"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { EditorBackend } from "../core/backend.js";
|
|
2
2
|
import { BlockUiOptions } from "../core/extension-points.js";
|
|
3
|
+
import { Basket } from "../features/composites/baskets.js";
|
|
4
|
+
import { BlockType } from "../features/composites/block-types.js";
|
|
3
5
|
import { CoreContentOptions } from "../core/schema/index.js";
|
|
4
6
|
import { EditorSurfaceHandle, EditorSurfaceProps, ReactFeature } from "./EditorSurface.js";
|
|
5
|
-
import { CompositeKind } from "../features/composites/kinds.js";
|
|
6
|
-
import { Basket } from "../features/composites/baskets.js";
|
|
7
7
|
import { ComposedEditor, ContentLevel, FeatureId, InteractionLevel } from "../presets/compose.js";
|
|
8
8
|
import { Editor } from "@tiptap/core";
|
|
9
9
|
import { ComponentType } from "react";
|
|
@@ -35,9 +35,9 @@ export interface ComposedEditorProps extends Omit<EditorSurfaceProps, 'preset'>
|
|
|
35
35
|
remove?: readonly FeatureId[];
|
|
36
36
|
/** The backend the composition is pruned by (default: the editor context's backend). */
|
|
37
37
|
backend?: EditorBackend;
|
|
38
|
-
/**
|
|
39
|
-
|
|
40
|
-
/** Colour baskets a
|
|
38
|
+
/** Block types when `content` includes composites (default: `defaultBlockTypes(t)`). */
|
|
39
|
+
blockTypes?: readonly BlockType[];
|
|
40
|
+
/** Colour baskets a Typed block can sit in when `content` includes composites (default: `defaultBaskets(t)`). */
|
|
41
41
|
compositeBaskets?: readonly Basket[];
|
|
42
42
|
/** Which surfaces render block actions: the hover bar (default), the selected-block toolbar, `'both'` or `'none'` (`BlockUiOptions`). */
|
|
43
43
|
blockUi?: BlockUiOptions;
|
|
@@ -26,7 +26,7 @@ const ReadySurface = forwardRef(function ReadySurface({ preset, ...surface }, re
|
|
|
26
26
|
* then nothing renders. Passing the host's own `collaboration` session keeps `collab` and `comments` whatever the
|
|
27
27
|
* backend offers.
|
|
28
28
|
*/
|
|
29
|
-
const ComposedSurface = forwardRef(function ComposedSurface({ content, interaction, ai, add, remove, backend,
|
|
29
|
+
const ComposedSurface = forwardRef(function ComposedSurface({ content, interaction, ai, add, remove, backend, blockTypes, compositeBaskets, blockUi, coreContent, ...surface }, ref) {
|
|
30
30
|
const app = useEditorContext();
|
|
31
31
|
const [source] = useState(() => backend ?? app.backend);
|
|
32
32
|
const [compose] = useState(() => {
|
|
@@ -35,7 +35,7 @@ const ComposedSurface = forwardRef(function ComposedSurface({ content, interacti
|
|
|
35
35
|
interaction,
|
|
36
36
|
ai,
|
|
37
37
|
collaboration: surface.collaboration !== void 0,
|
|
38
|
-
...
|
|
38
|
+
...blockTypes && { blockTypes },
|
|
39
39
|
...compositeBaskets && { compositeBaskets },
|
|
40
40
|
...blockUi && { blockUi },
|
|
41
41
|
...coreContent && { coreContent },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composed-surface.js","names":[],"sources":["../../src/react/composed-surface.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { type ComponentType, forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react'\nimport type { EditorBackend } from '../core/backend'\nimport type { BlockUiOptions } from '../core/extension-points'\nimport type { Basket } from '../features/composites/baskets'\nimport type {
|
|
1
|
+
{"version":3,"file":"composed-surface.js","names":[],"sources":["../../src/react/composed-surface.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { type ComponentType, forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react'\nimport type { EditorBackend } from '../core/backend'\nimport type { BlockUiOptions } from '../core/extension-points'\nimport type { Basket } from '../features/composites/baskets'\nimport type { BlockType } from '../features/composites/block-types'\nimport type { CoreContentOptions } from '../core/schema'\nimport type { ComposedEditor, ContentLevel, FeatureId, InteractionLevel } from '../presets/compose'\nimport { composeEditor } from './compose'\nimport { useEditorContext } from './context'\nimport { EditorSurface, type EditorSurfaceHandle, type EditorSurfaceProps, type ReactFeature } from './EditorSurface'\n\n/** The preset a composed editor mounts: the three dimensions' features, with `omitted` listing what the backend or `remove` dropped. */\nexport type ReactComposedPreset = ComposedEditor<ComponentType<{ editor: Editor }>>\n\n/** The handle of a composed editor: the surface's (`editor`, `openSettings`) plus the preset it composed. */\nexport interface ComposedEditorHandle extends EditorSurfaceHandle {\n readonly preset: ReactComposedPreset\n}\n\n/**\n * The surface's own props (collaboration session or standalone `value`/`onChange`, metadata, abilities, extensions,\n * block actions, commands, `documentId`, `editable`, `settingsUi`, the open state of the sidebar and comments margin,\n * `onReady` and the other callbacks) except the preset, plus the composition. Every composition prop is read once at\n * mount; hosts remount (`key`) to change one.\n */\nexport interface ComposedEditorProps extends Omit<EditorSurfaceProps, 'preset'> {\n /** Document model: a level or the content feature ids to install. */\n content?: ContentLevel | readonly FeatureId[]\n /** Editing UX: a level or the interaction feature ids; `[]` = no interaction (a viewer). */\n interaction?: InteractionLevel | readonly FeatureId[]\n /** Installs the AI feature and the integrations whose content is present. */\n ai?: boolean\n /** Host features, appended after the catalog. */\n add?: readonly ReactFeature[]\n /** Features (catalog or host) left out, with the features that require them. */\n remove?: readonly FeatureId[]\n /** The backend the composition is pruned by (default: the editor context's backend). */\n backend?: EditorBackend\n /** Block types when `content` includes composites (default: `defaultBlockTypes(t)`). */\n blockTypes?: readonly BlockType[]\n /** Colour baskets a Typed block can sit in when `content` includes composites (default: `defaultBaskets(t)`). */\n compositeBaskets?: readonly Basket[]\n /** Which surfaces render block actions: the hover bar (default), the selected-block toolbar, `'both'` or `'none'` (`BlockUiOptions`). */\n blockUi?: BlockUiOptions\n /** Optional structures the content base drops from the schema: headings or heading levels, lists, blockquote, code block, rule (`CoreContentOptions`). */\n coreContent?: CoreContentOptions\n}\n\n/** `EditorSurface` over an already composed preset; hands out the preset through the ref. */\nconst ReadySurface = forwardRef<ComposedEditorHandle, Omit<EditorSurfaceProps, 'preset'> & { preset: ReactComposedPreset }>(function ReadySurface({ preset, ...surface }, ref) {\n const surfaceRef = useRef<EditorSurfaceHandle>(null)\n useImperativeHandle(ref, () => ({\n get editor() { return surfaceRef.current?.editor ?? null },\n openSettings: tab => surfaceRef.current?.openSettings(tab),\n preset,\n }), [preset])\n return <EditorSurface ref={surfaceRef} preset={preset} {...surface} />\n})\n\n/**\n * `EditorSurface` over the preset `composeEditor` builds from the composition props, at mount. A backend that probes\n * its capabilities (`backend.ready`) is awaited first, so the composition is pruned by what it really offers; until\n * then nothing renders. Passing the host's own `collaboration` session keeps `collab` and `comments` whatever the\n * backend offers.\n */\nexport const ComposedSurface = forwardRef<ComposedEditorHandle, ComposedEditorProps & Required<Pick<ComposedEditorProps, 'content' | 'interaction' | 'ai'>>>(function ComposedSurface(\n { content, interaction, ai, add, remove, backend, blockTypes, compositeBaskets, blockUi, coreContent, ...surface },\n ref,\n) {\n const app = useEditorContext()\n // Read once at mount, like every composition prop, although the preset may only be built after `backend.ready`.\n const [source] = useState(() => backend ?? app.backend)\n const [compose] = useState(() => {\n const options = {\n content,\n interaction,\n ai,\n collaboration: surface.collaboration !== undefined,\n ...(blockTypes && { blockTypes }),\n ...(compositeBaskets && { compositeBaskets }),\n ...(blockUi && { blockUi }),\n ...(coreContent && { coreContent }),\n ...(add && { add }),\n ...(remove && { remove }),\n }\n return () => composeEditor({ ...options, backend: source })\n })\n const [preset, setPreset] = useState<ReactComposedPreset | undefined>(() => source.ready ? undefined : compose())\n useEffect(() => {\n if (preset || !source.ready) return\n let live = true\n void source.ready.then(() => { if (live) setPreset(compose()) })\n return () => { live = false }\n }, [preset, source, compose])\n return preset ? <ReadySurface ref={ref} preset={preset} {...surface} /> : null\n})\n"],"mappings":";;;;;;;AAkDA,MAAM,eAAe,WAAuG,SAAS,aAAa,EAAE,QAAQ,GAAG,WAAW,KAAK;CAC7K,MAAM,aAAa,OAA4B,IAAI;CACnD,oBAAoB,YAAY;EAC9B,IAAI,SAAS;GAAE,OAAO,WAAW,SAAS,UAAU;EAAK;EACzD,eAAc,QAAO,WAAW,SAAS,aAAa,GAAG;EACzD;CACF,IAAI,CAAC,MAAM,CAAC;CACZ,OAAO,oBAAC,eAAD;EAAe,KAAK;EAAoB;EAAQ,GAAI;CAAU,CAAA;AACvE,CAAC;;;;;;;AAQD,MAAa,kBAAkB,WAA8H,SAAS,gBACpK,EAAE,SAAS,aAAa,IAAI,KAAK,QAAQ,SAAS,YAAY,kBAAkB,SAAS,aAAa,GAAG,WACzG,KACA;CACA,MAAM,MAAM,iBAAiB;CAE7B,MAAM,CAAC,UAAU,eAAe,WAAW,IAAI,OAAO;CACtD,MAAM,CAAC,WAAW,eAAe;EAC/B,MAAM,UAAU;GACd;GACA;GACA;GACA,eAAe,QAAQ,kBAAkB,KAAA;GACzC,GAAI,cAAc,EAAE,WAAW;GAC/B,GAAI,oBAAoB,EAAE,iBAAiB;GAC3C,GAAI,WAAW,EAAE,QAAQ;GACzB,GAAI,eAAe,EAAE,YAAY;GACjC,GAAI,OAAO,EAAE,IAAI;GACjB,GAAI,UAAU,EAAE,OAAO;EACzB;EACA,aAAa,cAAc;GAAE,GAAG;GAAS,SAAS;EAAO,CAAC;CAC5D,CAAC;CACD,MAAM,CAAC,QAAQ,aAAa,eAAgD,OAAO,QAAQ,KAAA,IAAY,QAAQ,CAAC;CAChH,gBAAgB;EACd,IAAI,UAAU,CAAC,OAAO,OAAO;EAC7B,IAAI,OAAO;EACX,OAAY,MAAM,WAAW;GAAE,IAAI,MAAM,UAAU,QAAQ,CAAC;EAAE,CAAC;EAC/D,aAAa;GAAE,OAAO;EAAM;CAC9B,GAAG;EAAC;EAAQ;EAAQ;CAAO,CAAC;CAC5B,OAAO,SAAS,oBAAC,cAAD;EAAmB;EAAa;EAAQ,GAAI;CAAU,CAAA,IAAI;AAC5E,CAAC"}
|
package/dist/server/ai.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ModelRole } from "../settings/values.js";
|
|
2
2
|
import "../settings/index.js";
|
|
3
|
-
import {
|
|
3
|
+
import { ModelPresetConfig, TranscriptionConfig } from "../config/index.js";
|
|
4
4
|
import { ModelProfile, ModelRef } from "../core/backend-types.js";
|
|
5
5
|
import { ChatMessage } from "../features/ai/protocol/generate.js";
|
|
6
6
|
import "../features/ai/protocol/index.js";
|
|
@@ -21,11 +21,11 @@ export type ChatTurnPart = {
|
|
|
21
21
|
/** Everything the AI endpoints need, passed explicitly: no runtime config, no globals. */
|
|
22
22
|
export interface AiModelsConfig {
|
|
23
23
|
/** Server-defined model presets, keyed by preset id. */
|
|
24
|
-
presets: Record<string,
|
|
24
|
+
presets: Record<string, ModelPresetConfig>;
|
|
25
25
|
/** Shared key of presets without their own. */
|
|
26
26
|
apiKey?: string;
|
|
27
|
-
/** Default preset per model
|
|
28
|
-
|
|
27
|
+
/** Default preset per model role, answered by `GET /api/ai/models`. */
|
|
28
|
+
roles?: Record<ModelRole, string>;
|
|
29
29
|
/** Speech-to-text for audio/video composites; absent = the transcription endpoint answers 501. */
|
|
30
30
|
transcription?: TranscriptionConfig;
|
|
31
31
|
/**
|
|
@@ -52,7 +52,7 @@ export interface AiModels {
|
|
|
52
52
|
* returned; the `listModels` hook supplies the list when it returns one (replacing the presets).
|
|
53
53
|
*/
|
|
54
54
|
listModels(user: object | null): Promise<ModelProfile[]>;
|
|
55
|
-
readonly
|
|
55
|
+
readonly roles: Record<ModelRole, string> | undefined;
|
|
56
56
|
readonly transcription: TranscriptionConfig | undefined;
|
|
57
57
|
streamChat: typeof streamChat;
|
|
58
58
|
streamChatTurn: typeof streamChatTurn;
|
|
@@ -83,5 +83,5 @@ export declare function streamChatTurn(opts: {
|
|
|
83
83
|
toolChoice?: ToolChoice<ToolSet>;
|
|
84
84
|
}): AsyncGenerator<ChatTurnPart>;
|
|
85
85
|
//#endregion
|
|
86
|
-
export type { ChatMessage,
|
|
86
|
+
export type { ChatMessage, ModelPresetConfig, TranscriptionConfig };
|
|
87
87
|
//# sourceMappingURL=ai.d.ts.map
|
package/dist/server/ai.js
CHANGED
package/dist/server/ai.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai.js","names":[],"sources":["../../src/server/ai.ts"],"sourcesContent":["import { createOpenAICompatible } from '@ai-sdk/openai-compatible'\nimport { APICallError, type LanguageModel, type ModelMessage, streamText, type ToolChoice, type ToolSet } from 'ai'\nimport type { ChatMessage, ModelProfile, ModelRef } from '../features/ai/protocol'\nimport type {
|
|
1
|
+
{"version":3,"file":"ai.js","names":[],"sources":["../../src/server/ai.ts"],"sourcesContent":["import { createOpenAICompatible } from '@ai-sdk/openai-compatible'\nimport { APICallError, type LanguageModel, type ModelMessage, streamText, type ToolChoice, type ToolSet } from 'ai'\nimport type { ChatMessage, ModelProfile, ModelRef } from '../features/ai/protocol'\nimport type { ModelRole } from '../settings'\nimport type { ModelPresetConfig, TranscriptionConfig } from '../config'\nimport { HttpError } from './errors'\n\nexport type { ChatMessage }\n\n/** A streamed text delta, or a finished tool call (`invalid`: unparsable input or unknown tool). */\nexport type ChatTurnPart =\n | { type: 'text', text: string }\n | { type: 'tool-call', toolCallId: string, toolName: string, input: unknown, invalid: boolean }\n\nexport type { ModelPresetConfig, TranscriptionConfig }\n\n/** Everything the AI endpoints need, passed explicitly: no runtime config, no globals. */\nexport interface AiModelsConfig {\n /** Server-defined model presets, keyed by preset id. */\n presets: Record<string, ModelPresetConfig>\n /** Shared key of presets without their own. */\n apiKey?: string\n /** Default preset per model role, answered by `GET /api/ai/models`. */\n roles?: Record<ModelRole, string>\n /** Speech-to-text for audio/video composites; absent = the transcription endpoint answers 501. */\n transcription?: TranscriptionConfig\n /**\n * The host's own language model for `ref` (`ModelProvider.languageModel`), consulted before the presets for every\n * model reference; `user` is what `authenticate` returned. `null` or nothing falls through to the presets.\n */\n languageModel?: (ref: ModelRef, user: object | null) => Promise<LanguageModel | null | undefined>\n /** The models listed for `user` instead of the presets (`ModelProvider.listModels`); `null` or nothing lists the presets. */\n listModels?: (user: object | null) => Promise<ModelProfile[] | null | undefined>\n /** Appended to the error of a preset without key, e.g. the environment variable names that set it. */\n missingKeyHint?: (presetId: string) => string\n}\n\nexport interface AiModels {\n /**\n * AI SDK language model for `ref` (an OpenAI-compatible chat completions endpoint), for direct `ai` calls. The\n * host's `languageModel(ref, user)` is asked first (`user`: what `authenticate` returned); a model it returns is\n * used as is, `null` (or no such hook) falls through to the configured presets. A preset uses its own key or the\n * shared `apiKey`; a user ref brings its own. Throws `HttpError` 400 for an unknown preset and 500 for a preset\n * without key, so routes can call it before streaming starts.\n */\n resolveModel(ref: ModelRef, user: object | null): Promise<LanguageModel>\n /**\n * The configured presets as the client may see them: without their keys. `user` is what the host's `authenticate`\n * returned; the `listModels` hook supplies the list when it returns one (replacing the presets).\n */\n listModels(user: object | null): Promise<ModelProfile[]>\n readonly roles: Record<ModelRole, string> | undefined\n readonly transcription: TranscriptionConfig | undefined\n streamChat: typeof streamChat\n streamChatTurn: typeof streamChatTurn\n}\n\n/** The AI model utilities over an explicit configuration. */\nexport function createAiModels(config: AiModelsConfig): AiModels {\n return {\n async resolveModel(ref, user) {\n const hosted = await config.languageModel?.(ref, user)\n if (hosted) return hosted\n if (!('preset' in ref)) return createOpenAICompatible({ name: 'tiptap-editor', baseURL: ref.endpoint, apiKey: ref.apiKey }).chatModel(ref.model)\n const preset = config.presets[ref.preset]\n if (!preset) throw new HttpError(400, 'Unbekanntes Modell-Preset')\n const apiKey = preset.apiKey || config.apiKey\n if (!apiKey) throw new HttpError(500, `API-Key für Preset „${ref.preset}“ fehlt${config.missingKeyHint?.(ref.preset) ?? ''}`)\n return createOpenAICompatible({ name: 'tiptap-editor', baseURL: preset.endpoint, apiKey }).chatModel(preset.model)\n },\n async listModels(user) {\n const listed = await config.listModels?.(user)\n if (listed) return listed\n return Object.entries(config.presets).map(([id, { label, endpoint, model }]) => ({ id, label, endpoint, model, source: 'preset' }))\n },\n roles: config.roles,\n transcription: config.transcription,\n streamChat,\n streamChatTurn,\n }\n}\n\nexport function upstreamError(error: unknown) {\n let detail: string\n if (APICallError.isInstance(error)) detail = [error.statusCode, error.responseBody || error.message].filter(Boolean).join(' ')\n else if (error instanceof Error) detail = error.message\n else detail = (error as { message?: string } | null)?.message ?? JSON.stringify(error)\n return new HttpError(502, `KI-Endpunkt: ${detail}`.slice(0, 500))\n}\n\n/**\n * Streams the text deltas of a chat completion (AI SDK `streamText`) on the resolved language model `model` (see\n * `resolveModel`). System messages may appear in `messages`; a trailing assistant message is a prefill the model\n * continues. Upstream failures throw a 502 `HttpError`; aborting `signal` cancels the upstream request and makes the\n * generator throw.\n */\nexport async function* streamChat(opts: { model: LanguageModel, messages: ChatMessage[], signal: AbortSignal }): AsyncGenerator<string> {\n for await (const part of streamChatTurn(opts)) {\n if (part.type === 'text') yield part.text\n }\n}\n\n/**\n * Like `streamChat`, with `tools` the model may call (tools without `execute`: the turn ends with the calls, which are\n * yielded for the caller to handle) and structured `messages` (tool calls and results in the history).\n */\nexport async function* streamChatTurn(opts: {\n model: LanguageModel\n messages: ModelMessage[]\n signal: AbortSignal\n tools?: ToolSet\n toolChoice?: ToolChoice<ToolSet>\n}): AsyncGenerator<ChatTurnPart> {\n const { model } = opts\n // Also cancels the upstream request when the consumer stops iterating early (break / return).\n const upstream = new AbortController()\n const onAbort = () => upstream.abort(opts.signal.reason)\n if (opts.signal.aborted) onAbort()\n else opts.signal.addEventListener('abort', onAbort, { once: true })\n try {\n const result = streamText({\n model,\n messages: opts.messages,\n tools: opts.tools,\n toolChoice: opts.toolChoice,\n allowSystemInMessages: true,\n abortSignal: upstream.signal,\n maxRetries: 0,\n // Errors surface as `error` parts below and are rethrown; the default handler would only log them.\n onError: () => {},\n })\n for await (const part of result.stream) {\n if (part.type === 'text-delta') {\n if (part.text) yield { type: 'text', text: part.text }\n }\n else if (part.type === 'tool-call') {\n yield { type: 'tool-call', toolCallId: part.toolCallId, toolName: part.toolName, input: part.input, invalid: part.invalid === true }\n }\n else if (part.type === 'error') {\n if (opts.signal.aborted) break\n throw upstreamError(part.error)\n }\n else if (part.type === 'abort') {\n break\n }\n }\n opts.signal.throwIfAborted()\n }\n finally {\n opts.signal.removeEventListener('abort', onAbort)\n upstream.abort()\n }\n}\n"],"mappings":";;;;;AA0DA,SAAgB,eAAe,QAAkC;CAC/D,OAAO;EACL,MAAM,aAAa,KAAK,MAAM;GAC5B,MAAM,SAAS,MAAM,OAAO,gBAAgB,KAAK,IAAI;GACrD,IAAI,QAAQ,OAAO;GACnB,IAAI,EAAE,YAAY,MAAM,OAAO,uBAAuB;IAAE,MAAM;IAAiB,SAAS,IAAI;IAAU,QAAQ,IAAI;GAAO,CAAC,CAAC,CAAC,UAAU,IAAI,KAAK;GAC/I,MAAM,SAAS,OAAO,QAAQ,IAAI;GAClC,IAAI,CAAC,QAAQ,MAAM,IAAI,UAAU,KAAK,2BAA2B;GACjE,MAAM,SAAS,OAAO,UAAU,OAAO;GACvC,IAAI,CAAC,QAAQ,MAAM,IAAI,UAAU,KAAK,uBAAuB,IAAI,OAAO,SAAS,OAAO,iBAAiB,IAAI,MAAM,KAAK,IAAI;GAC5H,OAAO,uBAAuB;IAAE,MAAM;IAAiB,SAAS,OAAO;IAAU;GAAO,CAAC,CAAC,CAAC,UAAU,OAAO,KAAK;EACnH;EACA,MAAM,WAAW,MAAM;GACrB,MAAM,SAAS,MAAM,OAAO,aAAa,IAAI;GAC7C,IAAI,QAAQ,OAAO;GACnB,OAAO,OAAO,QAAQ,OAAO,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,UAAU,cAAc;IAAE;IAAI;IAAO;IAAU;IAAO,QAAQ;GAAS,EAAE;EACpI;EACA,OAAO,OAAO;EACd,eAAe,OAAO;EACtB;EACA;CACF;AACF;AAEA,SAAgB,cAAc,OAAgB;CAC5C,IAAI;CACJ,IAAI,aAAa,WAAW,KAAK,GAAG,SAAS,CAAC,MAAM,YAAY,MAAM,gBAAgB,MAAM,OAAO,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;MACxH,IAAI,iBAAiB,OAAO,SAAS,MAAM;MAC3C,SAAU,OAAuC,WAAW,KAAK,UAAU,KAAK;CACrF,OAAO,IAAI,UAAU,KAAK,gBAAgB,SAAS,MAAM,GAAG,GAAG,CAAC;AAClE;;;;;;;AAQA,gBAAuB,WAAW,MAAsG;CACtI,WAAW,MAAM,QAAQ,eAAe,IAAI,GAC1C,IAAI,KAAK,SAAS,QAAQ,MAAM,KAAK;AAEzC;;;;;AAMA,gBAAuB,eAAe,MAML;CAC/B,MAAM,EAAE,UAAU;CAElB,MAAM,WAAW,IAAI,gBAAgB;CACrC,MAAM,gBAAgB,SAAS,MAAM,KAAK,OAAO,MAAM;CACvD,IAAI,KAAK,OAAO,SAAS,QAAQ;MAC5B,KAAK,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;CAClE,IAAI;EACF,MAAM,SAAS,WAAW;GACxB;GACA,UAAU,KAAK;GACf,OAAO,KAAK;GACZ,YAAY,KAAK;GACjB,uBAAuB;GACvB,aAAa,SAAS;GACtB,YAAY;GAEZ,eAAe,CAAC;EAClB,CAAC;EACD,WAAW,MAAM,QAAQ,OAAO,QAC9B,IAAI,KAAK,SAAS,cACZ;OAAA,KAAK,MAAM,MAAM;IAAE,MAAM;IAAQ,MAAM,KAAK;GAAK;EAAA,OAElD,IAAI,KAAK,SAAS,aACrB,MAAM;GAAE,MAAM;GAAa,YAAY,KAAK;GAAY,UAAU,KAAK;GAAU,OAAO,KAAK;GAAO,SAAS,KAAK,YAAY;EAAK;OAEhI,IAAI,KAAK,SAAS,SAAS;GAC9B,IAAI,KAAK,OAAO,SAAS;GACzB,MAAM,cAAc,KAAK,KAAK;EAChC,OACK,IAAI,KAAK,SAAS,SACrB;EAGJ,KAAK,OAAO,eAAe;CAC7B,UACQ;EACN,KAAK,OAAO,oBAAoB,SAAS,OAAO;EAChD,SAAS,MAAM;CACjB;AACF"}
|
package/dist/server/auth.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//#region src/server/auth.d.ts
|
|
2
|
-
/** What `
|
|
2
|
+
/** What `AccessControl.authenticate` gets: the headers of the request (the websocket upgrade for collaboration) and the connection's `token`. */
|
|
3
3
|
export interface AuthenticateRequest {
|
|
4
4
|
headers: Headers;
|
|
5
5
|
/** The collaboration client's token (`HocuspocusProvider` `token`, sent right after the socket opened); absent for plain HTTP requests and token-less clients. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/server/collab-state.d.ts
|
|
2
2
|
export interface CollabState {
|
|
3
|
-
/** `
|
|
3
|
+
/** `DocumentContentStore.contentVersion` of the content the update was stored with; `null` = none known (also: legacy payload). */
|
|
4
4
|
version: string | null;
|
|
5
5
|
update: Uint8Array;
|
|
6
6
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collab-state.js","names":[],"sources":["../../src/server/collab-state.ts"],"sourcesContent":["// Stored Yjs state payload and the re-seed decision of the collab server. Pure: no Hocuspocus, no adapter, no Yjs.\n//\n// The adapter stores opaque bytes (`loadState`/`storeState` keep their signature); the server prefixes the Yjs update\n// with the content version it was written against:\n//\n// [0xFF, 0x76] marker (cannot start a legacy payload: a Yjs update opens with the varuint number of client groups,\n// and two continuation bytes would mean 16384 or more clients)\n// utf8 version empty = `null`\n// 0x00 terminator, so a version never contains NUL\n// update bytes `Y.encodeStateAsUpdate`\n//\n// Payloads without the marker are legacy raw updates and decode as `version: null`.\n\nconst MARKER = [0xFF, 0x76] as const\nconst TERMINATOR = 0\n\nconst encoder = new TextEncoder()\nconst decoder = new TextDecoder()\n\nexport interface CollabState {\n /** `
|
|
1
|
+
{"version":3,"file":"collab-state.js","names":[],"sources":["../../src/server/collab-state.ts"],"sourcesContent":["// Stored Yjs state payload and the re-seed decision of the collab server. Pure: no Hocuspocus, no adapter, no Yjs.\n//\n// The adapter stores opaque bytes (`loadState`/`storeState` keep their signature); the server prefixes the Yjs update\n// with the content version it was written against:\n//\n// [0xFF, 0x76] marker (cannot start a legacy payload: a Yjs update opens with the varuint number of client groups,\n// and two continuation bytes would mean 16384 or more clients)\n// utf8 version empty = `null`\n// 0x00 terminator, so a version never contains NUL\n// update bytes `Y.encodeStateAsUpdate`\n//\n// Payloads without the marker are legacy raw updates and decode as `version: null`.\n\nconst MARKER = [0xFF, 0x76] as const\nconst TERMINATOR = 0\n\nconst encoder = new TextEncoder()\nconst decoder = new TextDecoder()\n\nexport interface CollabState {\n /** `DocumentContentStore.contentVersion` of the content the update was stored with; `null` = none known (also: legacy payload). */\n version: string | null\n update: Uint8Array\n}\n\nexport function encodeCollabState({ version, update }: CollabState): Uint8Array {\n const label = encoder.encode(version ?? '')\n if (label.includes(TERMINATOR)) throw new Error('tiptap-editor: contentVersion darf kein NUL-Zeichen enthalten')\n const out = new Uint8Array(MARKER.length + label.length + 1 + update.length)\n out.set(MARKER, 0)\n out.set(label, MARKER.length)\n out[MARKER.length + label.length] = TERMINATOR\n out.set(update, MARKER.length + label.length + 1)\n return out\n}\n\nexport function decodeCollabState(payload: Uint8Array): CollabState {\n if (payload[0] !== MARKER[0] || payload[1] !== MARKER[1]) return { version: null, update: payload }\n const end = payload.indexOf(TERMINATOR, MARKER.length)\n // A marker without terminator is no payload this module wrote: treat it as an opaque legacy update.\n if (end === -1) return { version: null, update: payload }\n const label = decoder.decode(payload.subarray(MARKER.length, end))\n return { version: label === '' ? null : label, update: payload.subarray(end + 1) }\n}\n\n/**\n * Whether stored collaborative state is stale against the content behind it. Only hosts that implement\n * `contentVersion` opt in (`live === undefined`: the adapter has no such method, state is never discarded). A legacy\n * payload (`stored: null`) against a known live version counts as stale: it cannot prove it matches the content.\n */\nexport function isStateStale(stored: string | null, live: string | null | undefined): boolean {\n return live !== undefined && stored !== live\n}\n"],"mappings":";AAaA,MAAM,SAAS,CAAC,KAAM,GAAI;AAC1B,MAAM,aAAa;AAEnB,MAAM,UAAU,IAAI,YAAY;AAChC,MAAM,UAAU,IAAI,YAAY;AAQhC,SAAgB,kBAAkB,EAAE,SAAS,UAAmC;CAC9E,MAAM,QAAQ,QAAQ,OAAO,WAAW,EAAE;CAC1C,IAAI,MAAM,SAAS,UAAU,GAAG,MAAM,IAAI,MAAM,+DAA+D;CAC/G,MAAM,MAAM,IAAI,WAAW,OAAO,SAAS,MAAM,SAAS,IAAI,OAAO,MAAM;CAC3E,IAAI,IAAI,QAAQ,CAAC;CACjB,IAAI,IAAI,OAAO,OAAO,MAAM;CAC5B,IAAI,OAAO,SAAS,MAAM,UAAU;CACpC,IAAI,IAAI,QAAQ,OAAO,SAAS,MAAM,SAAS,CAAC;CAChD,OAAO;AACT;AAEA,SAAgB,kBAAkB,SAAkC;CAClE,IAAI,QAAQ,OAAO,OAAO,MAAM,QAAQ,OAAO,OAAO,IAAI,OAAO;EAAE,SAAS;EAAM,QAAQ;CAAQ;CAClG,MAAM,MAAM,QAAQ,QAAQ,YAAY,OAAO,MAAM;CAErD,IAAI,QAAQ,IAAI,OAAO;EAAE,SAAS;EAAM,QAAQ;CAAQ;CACxD,MAAM,QAAQ,QAAQ,OAAO,QAAQ,SAAS,OAAO,QAAQ,GAAG,CAAC;CACjE,OAAO;EAAE,SAAS,UAAU,KAAK,OAAO;EAAO,QAAQ,QAAQ,SAAS,MAAM,CAAC;CAAE;AACnF;;;;;;AAOA,SAAgB,aAAa,QAAuB,MAA0C;CAC5F,OAAO,SAAS,KAAA,KAAa,WAAW;AAC1C"}
|
package/dist/server/collab.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AccessControl, DocumentContentStore, EditorPorts } from "./ports.js";
|
|
2
2
|
import { AnyExtension, JSONContent } from "@tiptap/core";
|
|
3
3
|
import { Schema } from "@tiptap/pm/model";
|
|
4
4
|
import { Configuration, Hocuspocus, WebSocketLike } from "@hocuspocus/server";
|
|
@@ -6,14 +6,14 @@ import { Configuration, Hocuspocus, WebSocketLike } from "@hocuspocus/server";
|
|
|
6
6
|
/** Y.XmlFragment the TipTap Collaboration extension binds to (its default `field`). */
|
|
7
7
|
export declare const COLLAB_FIELD = "default";
|
|
8
8
|
export interface CollabServerOptions {
|
|
9
|
-
/**
|
|
9
|
+
/** Access control, documents and Yjs state of the editor backend; `collabState` is required. */
|
|
10
10
|
ports: EditorPorts;
|
|
11
11
|
/** TipTap extensions of the collaboration schema; default `advancedSchemaExtensions()`. Host-defined nodes and marks: `() => [...advancedSchemaExtensions(), HostNode]` (Vue-free node files only, no node views). */
|
|
12
12
|
schema?: () => AnyExtension[];
|
|
13
13
|
/** Per-document access and content versioning; each defaults to the port's method of the same name. */
|
|
14
14
|
hooks?: {
|
|
15
|
-
authorize?: NonNullable<
|
|
16
|
-
contentVersion?: NonNullable<
|
|
15
|
+
authorize?: NonNullable<AccessControl['authorize']>;
|
|
16
|
+
contentVersion?: NonNullable<DocumentContentStore['contentVersion']>;
|
|
17
17
|
};
|
|
18
18
|
/** Further Hocuspocus configuration (`debounce`, `timeout`, `quiet`, …); the editor's hooks win over equally named ones. */
|
|
19
19
|
configuration?: Partial<Configuration>;
|
package/dist/server/collab.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { assignBlockIds } from "../core/schema/block-ids.js";
|
|
2
|
+
import { isOldPersistedNode } from "../core/schema/persisted-names.js";
|
|
2
3
|
import { EMPTY_EDITOR_CONTENT } from "../core/schema/index.js";
|
|
3
|
-
import { migrateLegacyContent } from "../features/composites/legacy.js";
|
|
4
|
+
import { hasFlatTranscript, migrateLegacyContent } from "../features/composites/legacy.js";
|
|
4
5
|
import { advancedSchemaExtensions } from "../schema/advanced.js";
|
|
5
6
|
import { decodeCollabState, encodeCollabState, isStateStale } from "./collab-state.js";
|
|
6
7
|
import { getSchema } from "@tiptap/core";
|
|
@@ -17,19 +18,19 @@ const UNAUTHORIZED = {
|
|
|
17
18
|
};
|
|
18
19
|
/** Context key under which `handleConnection` hands the connection's socket closer to the `onAuthenticate` hook. */
|
|
19
20
|
const REJECT = Symbol("collab.reject");
|
|
20
|
-
/** ProseMirror document of stored JSON content: legacy nodes migrated, empty content replaced by the empty document, block IDs assigned. */
|
|
21
|
+
/** ProseMirror document of stored JSON content: old persisted names and legacy nodes migrated, empty content replaced by the empty document, block IDs assigned. */
|
|
21
22
|
function contentNode(schema, loaded) {
|
|
22
23
|
const content = migrateLegacyContent(loaded);
|
|
23
24
|
const node = schema.nodeFromJSON(content.type === "doc" && content.content?.length ? content : EMPTY_EDITOR_CONTENT);
|
|
24
25
|
return assignBlockIds(node) ?? node;
|
|
25
26
|
}
|
|
26
|
-
/** Whether
|
|
27
|
-
function
|
|
28
|
-
return !fragment.createTreeWalker((node) => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
/** Whether the stored Yjs content still uses an old persisted name (the names listed in `persisted-names.ts`); the current schema does not know those elements. */
|
|
28
|
+
function hasOldPersistedNames(fragment) {
|
|
29
|
+
return !fragment.createTreeWalker((node) => node instanceof Y.XmlElement && isOldPersistedNode(node.nodeName, node.getAttributes(), { earliest: true })).next().done;
|
|
30
|
+
}
|
|
31
|
+
/** Whether a Typed block of the stored Yjs content still carries the flat `meta.transcript` that `migrateLegacyContent` turns into a `rendition` child; its Block type does not matter. */
|
|
32
|
+
function hasFlatTranscriptBlock(fragment) {
|
|
33
|
+
return !fragment.createTreeWalker((node) => node instanceof Y.XmlElement && node.nodeName === "typedBlock" && hasFlatTranscript(node.getAttribute("meta"))).next().done;
|
|
33
34
|
}
|
|
34
35
|
/** Hocuspocus answers a thrown error's `reason` as permission-denied. */
|
|
35
36
|
const denied = (message, reason) => Object.assign(new Error(message), { reason });
|
|
@@ -110,16 +111,20 @@ function createCollabServer(options) {
|
|
|
110
111
|
const doc = new Y.Doc();
|
|
111
112
|
Y.applyUpdate(doc, stored);
|
|
112
113
|
const fragment = doc.getXmlFragment(COLLAB_FIELD);
|
|
113
|
-
if (
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (withIds) {
|
|
118
|
-
prosemirrorToYXmlFragment(withIds, fragment);
|
|
119
|
-
await persist(doc);
|
|
120
|
-
}
|
|
114
|
+
if (hasOldPersistedNames(fragment)) {
|
|
115
|
+
const migrated = contentNode(currentSchema, yDocToProsemirrorJSON(doc, COLLAB_FIELD));
|
|
116
|
+
prosemirrorToYXmlFragment(migrated, fragment);
|
|
117
|
+
await persist(doc);
|
|
121
118
|
return doc;
|
|
122
119
|
}
|
|
120
|
+
const current = yXmlFragmentToProsemirror(currentSchema, fragment);
|
|
121
|
+
const migrated = hasFlatTranscriptBlock(fragment) ? currentSchema.nodeFromJSON(migrateLegacyContent(current.toJSON())) : current;
|
|
122
|
+
const withIds = assignBlockIds(migrated) ?? (migrated === current ? null : migrated);
|
|
123
|
+
if (withIds) {
|
|
124
|
+
prosemirrorToYXmlFragment(withIds, fragment);
|
|
125
|
+
await persist(doc);
|
|
126
|
+
}
|
|
127
|
+
return doc;
|
|
123
128
|
}
|
|
124
129
|
const loaded = await documents.loadContent(documentName);
|
|
125
130
|
if (!loaded) throw new Error("Dokument nicht gefunden");
|