@ecsplico/editor 2.1.2 → 3.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 +78 -1
- package/README.md +39 -156
- package/dist/adapters/comments/drizzle.d.ts +1 -1
- package/dist/adapters/comments/record.d.ts +15 -0
- package/dist/adapters/comments/{client.js → rest-model.js} +3 -3
- package/dist/adapters/comments/rest-model.js.map +1 -0
- package/dist/adapters/comments/server.d.ts +2 -1
- package/dist/adapters/comments/server.js +2 -1
- package/dist/adapters/comments/server.js.map +1 -1
- package/dist/adapters/comments/types.d.ts +2 -2
- package/dist/adapters/document-state.d.ts +23 -0
- package/dist/adapters/document-state.js +66 -0
- package/dist/adapters/document-state.js.map +1 -0
- package/dist/adapters/documents.js +14 -11
- package/dist/adapters/documents.js.map +1 -1
- package/dist/adapters/drizzle.d.ts +2 -2
- package/dist/adapters/drizzle.js +97 -88
- package/dist/adapters/drizzle.js.map +1 -1
- package/dist/adapters/forge.d.ts +12 -7
- package/dist/adapters/forge.js +38 -45
- package/dist/adapters/forge.js.map +1 -1
- package/dist/adapters/http.d.ts +20 -0
- package/dist/adapters/http.js +68 -0
- package/dist/adapters/http.js.map +1 -0
- package/dist/adapters/index.d.ts +5 -5
- package/dist/adapters/json.d.ts +3 -3
- package/dist/adapters/json.js +58 -49
- package/dist/adapters/json.js.map +1 -1
- package/dist/adapters/memory.d.ts +21 -0
- package/dist/adapters/memory.js +53 -0
- package/dist/adapters/memory.js.map +1 -0
- package/dist/adapters/nitro.d.ts +27 -20
- package/dist/adapters/nitro.js +59 -163
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/adapters/react.d.ts +55 -0
- package/dist/adapters/react.js +209 -0
- package/dist/adapters/react.js.map +1 -0
- package/dist/adapters/shared.d.ts +15 -21
- package/dist/adapters/shared.js +10 -8
- package/dist/adapters/shared.js.map +1 -1
- package/dist/adapters/vue.d.ts +15 -30
- package/dist/adapters/vue.js +36 -87
- package/dist/adapters/vue.js.map +1 -1
- package/dist/code/CodeSurface.vue.d.ts +2 -2
- package/dist/config/index.d.ts +105 -0
- package/dist/config/index.js +95 -0
- package/dist/config/index.js.map +1 -0
- package/dist/core/abilities.js +1 -0
- package/dist/core/abilities.js.map +1 -1
- package/dist/{adapters/routes.js → core/api-routes.js} +5 -3
- package/dist/core/api-routes.js.map +1 -0
- package/dist/core/backend-capability.d.ts +7 -0
- package/dist/core/backend-capability.js +17 -0
- package/dist/core/backend-capability.js.map +1 -0
- package/dist/core/backend-types.d.ts +245 -0
- package/dist/core/backend-types.js +17 -0
- package/dist/core/backend-types.js.map +1 -0
- package/dist/core/backend.d.ts +108 -0
- package/dist/core/backend.js +14 -0
- package/dist/core/backend.js.map +1 -0
- package/dist/core/block-convert.d.ts +7 -5
- package/dist/core/block-convert.js +28 -5
- package/dist/core/block-convert.js.map +1 -1
- package/dist/core/command-types.d.ts +96 -0
- package/dist/core/commands.d.ts +40 -0
- package/dist/core/commands.js +151 -0
- package/dist/core/commands.js.map +1 -0
- package/dist/core/context.d.ts +17 -20
- package/dist/core/context.js +24 -21
- package/dist/core/context.js.map +1 -1
- package/dist/core/core-feature.d.ts +22 -7
- package/dist/core/core-feature.js +51 -18
- package/dist/core/core-feature.js.map +1 -1
- package/dist/core/define-editor.d.ts +4 -3
- package/dist/core/define-editor.js +14 -7
- package/dist/core/define-editor.js.map +1 -1
- package/dist/core/document-markdown.js +12 -3
- package/dist/core/document-markdown.js.map +1 -1
- package/dist/core/editor-ui.d.ts +8 -1
- package/dist/core/editor-ui.js +9 -8
- package/dist/core/editor-ui.js.map +1 -1
- package/dist/core/extension-points.d.ts +3 -15
- package/dist/core/feature-context.d.ts +8 -7
- package/dist/core/feature-context.js +12 -11
- 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.d.ts +2 -1
- package/dist/core/fences.js +3 -2
- package/dist/core/fences.js.map +1 -1
- package/dist/core/fetch-error.d.ts +1 -1
- package/dist/core/fetch-error.js +3 -1
- package/dist/core/fetch-error.js.map +1 -1
- package/dist/core/hash.d.ts +5 -0
- package/dist/core/hash.js +11 -0
- package/dist/core/hash.js.map +1 -0
- package/dist/core/http-backend.d.ts +11 -0
- package/dist/core/http-backend.js +195 -0
- package/dist/core/http-backend.js.map +1 -0
- package/dist/core/index.d.ts +15 -9
- package/dist/core/index.js +13 -9
- package/dist/core/palette.d.ts +48 -0
- package/dist/core/palette.js +95 -0
- package/dist/core/palette.js.map +1 -0
- package/dist/core/schema/abilities.d.ts +2 -1
- package/dist/core/schema/abilities.js +5 -1
- package/dist/core/schema/abilities.js.map +1 -1
- package/dist/core/schema/index.d.ts +11 -5
- package/dist/core/schema/index.js +13 -8
- package/dist/core/schema/index.js.map +1 -1
- package/dist/core/schema/mark-flags.d.ts +8 -1
- package/dist/core/schema/of-features.d.ts +13 -0
- package/dist/core/schema/of-features.js +14 -0
- package/dist/core/schema/of-features.js.map +1 -0
- package/dist/core/slash.d.ts +8 -6
- package/dist/core/slash.js +24 -16
- package/dist/core/slash.js.map +1 -1
- package/dist/core/surface-session.js +15 -5
- package/dist/core/surface-session.js.map +1 -1
- package/dist/core/toolbar-items.d.ts +10 -4
- package/dist/core/toolbar-items.js +269 -195
- package/dist/core/toolbar-items.js.map +1 -1
- package/dist/core/transaction-guards.d.ts +21 -0
- package/dist/core/transaction-guards.js +49 -0
- package/dist/core/transaction-guards.js.map +1 -0
- package/dist/core/util.js +11 -0
- package/dist/core/util.js.map +1 -0
- package/dist/document/DocumentSurface.d.ts +1 -1
- package/dist/document/DocumentSurface.vue.d.ts +2 -2
- package/dist/features/ai/agent-op-review.d.ts +1 -1
- package/dist/features/ai/agent-op-review.js +1 -1
- package/dist/features/ai/agent-ops.js +1 -1
- package/dist/features/ai/ai-apply.d.ts +2 -2
- package/dist/features/ai/ai-apply.js +1 -1
- package/dist/features/ai/ai-review.js +1 -1
- package/dist/features/ai/ai-sse.d.ts +6 -6
- package/dist/features/ai/ai-sse.js +20 -63
- package/dist/features/ai/ai-sse.js.map +1 -1
- package/dist/features/ai/assistant.d.ts +8 -7
- package/dist/features/ai/assistant.js +3 -3
- package/dist/features/ai/assistant.js.map +1 -1
- package/dist/features/ai/block-actions.d.ts +3 -2
- package/dist/features/ai/block-actions.js +3 -2
- package/dist/features/ai/block-actions.js.map +1 -1
- package/dist/features/ai/components/AiSelectionMenu.js +1 -1
- package/dist/features/ai/components/DocumentChatAnswer.js +1 -1
- package/dist/features/ai/components/DocumentChatOps.vue.d.ts +1 -1
- package/dist/features/ai/components/SettingsModelProfiles.js +8 -8
- package/dist/features/ai/components/SettingsModelProfiles.js.map +1 -1
- package/dist/features/ai/document-chat-model.d.ts +8 -7
- 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 +1 -1
- package/dist/features/ai/feature.js +27 -14
- package/dist/features/ai/feature.js.map +1 -1
- package/dist/features/ai/ghost-autocomplete.d.ts +7 -6
- package/dist/features/ai/ghost-autocomplete.js +6 -9
- package/dist/features/ai/ghost-autocomplete.js.map +1 -1
- package/dist/features/ai/index.d.ts +4 -3
- package/dist/features/ai/index.js +10 -10
- package/dist/features/ai/model-profiles.d.ts +5 -4
- package/dist/features/ai/model-profiles.js +2 -2
- package/dist/features/ai/model-profiles.js.map +1 -1
- package/dist/features/ai/protocol/block-lines.js +1 -1
- package/dist/features/ai/protocol/block-lines.js.map +1 -1
- package/dist/features/ai/protocol/chat.js +6 -2
- package/dist/features/ai/protocol/chat.js.map +1 -1
- package/dist/features/ai/protocol/index.d.ts +3 -2
- package/dist/features/ai/protocol/models.d.ts +2 -16
- package/dist/features/ai/protocol/models.js.map +1 -1
- package/dist/features/ai/rate-limit.d.ts +1 -1
- package/dist/features/ai/rate-limit.js +3 -1
- package/dist/features/ai/rate-limit.js.map +1 -1
- package/dist/features/ai/react/AiSelectionMenu.js +2 -2
- package/dist/features/ai/react/AiSidebar.js +4 -4
- package/dist/features/ai/react/DocumentChatAnswer.js +1 -1
- package/dist/features/ai/react/DocumentChatOps.d.ts +1 -1
- package/dist/features/ai/react/DocumentChatOps.js +1 -1
- package/dist/features/ai/react/SettingsModelProfiles.js +8 -10
- 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 +3 -3
- package/dist/features/ai/react/use-ai-assistant.js.map +1 -1
- package/dist/features/ai/react/use-document-chat.js +2 -2
- package/dist/features/ai/react/use-document-chat.js.map +1 -1
- package/dist/features/ai/react/use-model-profiles.d.ts +2 -1
- package/dist/features/ai/selection-flow.d.ts +1 -1
- package/dist/features/ai/selection-flow.js +1 -1
- package/dist/features/ai/sidebar-flow.d.ts +1 -1
- package/dist/features/ai/sidebar-flow.js +1 -1
- package/dist/features/ai/use-ai-assistant.d.ts +1 -1
- package/dist/features/ai/use-ai-assistant.js +3 -3
- package/dist/features/ai/use-ai-assistant.js.map +1 -1
- package/dist/features/ai/use-document-chat.js +2 -2
- package/dist/features/ai/use-document-chat.js.map +1 -1
- package/dist/features/ai/use-model-profiles.d.ts +2 -1
- package/dist/features/authors/attribution.d.ts +1 -1
- package/dist/features/authors/feature.js +12 -11
- package/dist/features/authors/feature.js.map +1 -1
- package/dist/features/block-ui/block-actions.d.ts +1 -1
- package/dist/features/block-ui/block-actions.js +1 -1
- package/dist/features/block-ui/block-actions.js.map +1 -1
- package/dist/features/block-ui/components/BlockUi.js +1 -1
- package/dist/features/block-ui/feature.js +1 -0
- package/dist/features/block-ui/feature.js.map +1 -1
- package/dist/features/block-ui/react/BlockUi.js +1 -1
- package/dist/features/collab/anchor-resolver.js +1 -1
- package/dist/features/collab/feature.js +2 -0
- package/dist/features/collab/feature.js.map +1 -1
- package/dist/features/comments/components/CommentThreadView.vue.d.ts +2 -1
- package/dist/features/comments/feature.js +12 -11
- package/dist/features/comments/feature.js.map +1 -1
- package/dist/features/comments/index.d.ts +3 -2
- package/dist/features/comments/index.js +1 -1
- package/dist/features/comments/margin-layout.d.ts +3 -2
- package/dist/features/comments/model.d.ts +3 -67
- package/dist/features/comments/model.js +2 -2
- package/dist/features/comments/model.js.map +1 -1
- package/dist/features/comments/react/CommentThreadView.d.ts +3 -2
- package/dist/features/comments/react/use-comments.d.ts +2 -1
- package/dist/features/comments/react.d.ts +1 -1
- package/dist/features/comments/schema.d.ts +2 -52
- package/dist/features/comments/schema.js.map +1 -1
- package/dist/features/comments/snapshot-equality.js.map +1 -1
- package/dist/features/comments/use-comments.d.ts +3 -2
- package/dist/features/comments/vue.d.ts +1 -1
- package/dist/features/composites/accepted-children.d.ts +1 -0
- package/dist/features/composites/accepted-children.js +16 -1
- package/dist/features/composites/accepted-children.js.map +1 -1
- package/dist/features/composites/ai-brief.js +39 -0
- package/dist/features/composites/ai-brief.js.map +1 -1
- package/dist/features/composites/bibliography-command.d.ts +11 -0
- package/dist/features/composites/bibliography-form.js +90 -0
- package/dist/features/composites/bibliography-form.js.map +1 -0
- package/dist/features/composites/bibliography.d.ts +33 -0
- package/dist/features/composites/bibliography.js +120 -0
- package/dist/features/composites/bibliography.js.map +1 -0
- package/dist/features/composites/components/BibliographyEditor.js +261 -0
- package/dist/features/composites/components/BibliographyEditor.js.map +1 -0
- package/dist/features/composites/components/CompositeChrome.js +78 -29
- 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 +46 -11
- package/dist/features/composites/components/CompositeDetails.js.map +1 -1
- package/dist/features/composites/components/CompositeDetails.vue.d.ts +2 -1
- package/dist/features/composites/components/CompositeFieldEditor.js +64 -5
- package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
- package/dist/features/composites/components/CompositeInspector.js +20 -7
- package/dist/features/composites/components/CompositeInspector.js.map +1 -1
- package/dist/features/composites/components/CompositeTable.js +13 -4
- package/dist/features/composites/components/CompositeTable.js.map +1 -1
- package/dist/features/composites/components/CompositeTagsEditor.js +1 -1
- package/dist/features/composites/components/CompositeView.js +11 -1
- package/dist/features/composites/components/CompositeView.js.map +1 -1
- package/dist/features/composites/components/DerivationBadge.js +103 -0
- package/dist/features/composites/components/DerivationBadge.js.map +1 -0
- package/dist/features/composites/components/ReferenceFieldSelect.js +60 -0
- package/dist/features/composites/components/ReferenceFieldSelect.js.map +1 -0
- package/dist/features/composites/components/ReferenceView.js +122 -0
- package/dist/features/composites/components/ReferenceView.js.map +1 -0
- package/dist/features/composites/components/ReferenceView.vue.d.ts +96 -0
- package/dist/features/composites/components/SettingsEditingTab.js +1 -1
- package/dist/features/composites/convert.js +2 -2
- package/dist/features/composites/convert.js.map +1 -1
- package/dist/features/composites/derivation.d.ts +61 -0
- package/dist/features/composites/derivation.js +98 -0
- package/dist/features/composites/derivation.js.map +1 -0
- package/dist/features/composites/derived-chrome.js +69 -0
- package/dist/features/composites/derived-chrome.js.map +1 -0
- package/dist/features/composites/feature.js +159 -109
- package/dist/features/composites/feature.js.map +1 -1
- package/dist/features/composites/fences.d.ts +4 -3
- package/dist/features/composites/fences.js +51 -7
- package/dist/features/composites/fences.js.map +1 -1
- package/dist/features/composites/index.d.ts +12 -3
- package/dist/features/composites/index.js +15 -6
- package/dist/features/composites/inspector-model.d.ts +4 -1
- package/dist/features/composites/inspector-model.js +8 -4
- package/dist/features/composites/inspector-model.js.map +1 -1
- package/dist/features/composites/kinds.d.ts +16 -2
- package/dist/features/composites/kinds.js +145 -6
- package/dist/features/composites/kinds.js.map +1 -1
- package/dist/features/composites/legacy.d.ts +4 -1
- package/dist/features/composites/legacy.js +56 -1
- package/dist/features/composites/legacy.js.map +1 -1
- package/dist/features/composites/meta-display.js +45 -2
- package/dist/features/composites/meta-display.js.map +1 -1
- package/dist/features/composites/meta-keys.d.ts +7 -0
- package/dist/features/composites/meta-keys.js +21 -0
- package/dist/features/composites/meta-keys.js.map +1 -0
- package/dist/features/composites/node-views.d.ts +6 -3
- package/dist/features/composites/node-views.js +7 -3
- package/dist/features/composites/node-views.js.map +1 -1
- package/dist/features/composites/nodes.d.ts +6 -1
- package/dist/features/composites/nodes.js +33 -7
- package/dist/features/composites/nodes.js.map +1 -1
- package/dist/features/composites/react/BibliographyEditor.js +229 -0
- package/dist/features/composites/react/BibliographyEditor.js.map +1 -0
- package/dist/features/composites/react/CompositeChrome.js +67 -19
- package/dist/features/composites/react/CompositeChrome.js.map +1 -1
- package/dist/features/composites/react/CompositeDetails.d.ts +2 -1
- package/dist/features/composites/react/CompositeDetails.js +45 -6
- package/dist/features/composites/react/CompositeDetails.js.map +1 -1
- package/dist/features/composites/react/CompositeFieldEditor.d.ts +1 -1
- package/dist/features/composites/react/CompositeFieldEditor.js +43 -1
- package/dist/features/composites/react/CompositeFieldEditor.js.map +1 -1
- package/dist/features/composites/react/CompositeInspector.js +12 -6
- package/dist/features/composites/react/CompositeInspector.js.map +1 -1
- package/dist/features/composites/react/CompositeStatusMenu.js +1 -1
- package/dist/features/composites/react/CompositeSummaryEditor.js +1 -1
- package/dist/features/composites/react/CompositeTable.js +16 -2
- package/dist/features/composites/react/CompositeTable.js.map +1 -1
- package/dist/features/composites/react/CompositeTagsEditor.js +2 -2
- package/dist/features/composites/react/CompositeView.js +6 -1
- package/dist/features/composites/react/CompositeView.js.map +1 -1
- package/dist/features/composites/react/DerivationBadge.js +116 -0
- package/dist/features/composites/react/DerivationBadge.js.map +1 -0
- package/dist/features/composites/react/ReferenceFieldSelect.js +52 -0
- package/dist/features/composites/react/ReferenceFieldSelect.js.map +1 -0
- package/dist/features/composites/react/ReferenceView.d.ts +11 -0
- package/dist/features/composites/react/ReferenceView.js +115 -0
- package/dist/features/composites/react/ReferenceView.js.map +1 -0
- package/dist/features/composites/react/SettingsEditingTab.js +2 -2
- package/dist/features/composites/react.d.ts +2 -1
- package/dist/features/composites/react.js +7 -3
- package/dist/features/composites/react.js.map +1 -1
- package/dist/features/composites/reference-ai.js +16 -0
- package/dist/features/composites/reference-ai.js.map +1 -0
- package/dist/features/composites/reference-label.d.ts +19 -0
- package/dist/features/composites/reference-label.js +58 -0
- package/dist/features/composites/reference-label.js.map +1 -0
- package/dist/features/composites/reference-suggestion.d.ts +10 -0
- package/dist/features/composites/reference-suggestion.js +41 -0
- package/dist/features/composites/reference-suggestion.js.map +1 -0
- package/dist/features/composites/reference-text.d.ts +18 -0
- package/dist/features/composites/reference-text.js +89 -0
- package/dist/features/composites/reference-text.js.map +1 -0
- package/dist/features/composites/reference.d.ts +44 -0
- package/dist/features/composites/reference.js +148 -0
- package/dist/features/composites/reference.js.map +1 -0
- package/dist/features/composites/reveal-source.d.ts +32 -0
- package/dist/features/composites/reveal-source.js +89 -0
- package/dist/features/composites/reveal-source.js.map +1 -0
- package/dist/features/composites/rows.d.ts +25 -3
- package/dist/features/composites/rows.js +72 -10
- package/dist/features/composites/rows.js.map +1 -1
- package/dist/features/composites/schema.d.ts +9 -3
- package/dist/features/composites/schema.js +11 -4
- package/dist/features/composites/schema.js.map +1 -1
- package/dist/features/composites/table-model.js +12 -21
- package/dist/features/composites/table-model.js.map +1 -1
- package/dist/features/composites/vue.d.ts +3 -2
- package/dist/features/composites/vue.js +8 -4
- package/dist/features/composites/vue.js.map +1 -1
- package/dist/features/media/assets.d.ts +2 -0
- package/dist/features/media/assets.js +3 -2
- package/dist/features/media/assets.js.map +1 -1
- package/dist/features/media/components/FileView.js +13 -4
- package/dist/features/media/components/FileView.js.map +1 -1
- package/dist/features/media/feature.d.ts +3 -3
- package/dist/features/media/feature.js +21 -28
- package/dist/features/media/feature.js.map +1 -1
- package/dist/features/media/file-import.js +2 -2
- package/dist/features/media/file-import.js.map +1 -1
- package/dist/features/media/index.d.ts +2 -2
- package/dist/features/media/index.js +3 -3
- package/dist/features/media/react/AudioRecorderModal.js +1 -1
- package/dist/features/media/react/FileView.js +19 -2
- package/dist/features/media/react/FileView.js.map +1 -1
- package/dist/features/media/react.js +1 -1
- package/dist/features/media/schema.d.ts +8 -0
- package/dist/features/media/schema.js +126 -11
- package/dist/features/media/schema.js.map +1 -1
- package/dist/features/media/upload.d.ts +16 -14
- package/dist/features/media/upload.js +13 -19
- package/dist/features/media/upload.js.map +1 -1
- package/dist/features/mentions/index.d.ts +4 -3
- package/dist/features/mentions/index.js +4 -1
- package/dist/features/mentions/index.js.map +1 -1
- package/dist/features/mentions/mention-text.d.ts +1 -1
- package/dist/features/mentions/mention-text.js.map +1 -1
- package/dist/features/mentions/mention.d.ts +0 -6
- package/dist/features/mentions/mention.js.map +1 -1
- package/dist/features/mentions/metadata-defaults.d.ts +2 -2
- package/dist/features/mentions/metadata-defaults.js +3 -9
- package/dist/features/mentions/metadata-defaults.js.map +1 -1
- package/dist/features/mentions/schema.d.ts +2 -1
- package/dist/features/mentions/schema.js.map +1 -1
- package/dist/features/tables/feature.d.ts +2 -1
- package/dist/features/tables/feature.js +90 -70
- package/dist/features/tables/feature.js.map +1 -1
- package/dist/features/themes/components/SettingsAppearanceTab.js +6 -9
- package/dist/features/themes/components/SettingsAppearanceTab.js.map +1 -1
- package/dist/features/themes/feature.js +2 -0
- package/dist/features/themes/feature.js.map +1 -1
- package/dist/features/themes/index.d.ts +2 -1
- package/dist/features/themes/react/SettingsAppearanceTab.js +7 -10
- package/dist/features/themes/react/SettingsAppearanceTab.js.map +1 -1
- package/dist/features/themes/schema.d.ts +2 -6
- package/dist/features/themes/schema.js.map +1 -1
- package/dist/features/themes/theme-runtime.d.ts +1 -1
- package/dist/features/themes/theme-runtime.js +4 -2
- package/dist/features/themes/theme-runtime.js.map +1 -1
- package/dist/features/transcript/TranscriptSegmentView.js +48 -28
- package/dist/features/transcript/TranscriptSegmentView.js.map +1 -1
- package/dist/features/transcript/feature.js +21 -19
- package/dist/features/transcript/feature.js.map +1 -1
- package/dist/features/transcript/react/TranscriptSegmentView.js +55 -36
- package/dist/features/transcript/react/TranscriptSegmentView.js.map +1 -1
- package/dist/features/transcript/segment-node.d.ts +2 -0
- package/dist/features/transcript/segment-node.js +35 -7
- package/dist/features/transcript/segment-node.js.map +1 -1
- package/dist/i18n/de/composites.js +91 -1
- package/dist/i18n/de/composites.js.map +1 -1
- package/dist/i18n/de/integrations.js +49 -8
- package/dist/i18n/de/integrations.js.map +1 -1
- package/dist/i18n/de/media.js +0 -1
- package/dist/i18n/de/media.js.map +1 -1
- package/dist/i18n/de/palette.js +22 -0
- package/dist/i18n/de/palette.js.map +1 -0
- package/dist/i18n/de/tables.js +0 -1
- package/dist/i18n/de/tables.js.map +1 -1
- package/dist/i18n/de/transcript.js +2 -1
- package/dist/i18n/de/transcript.js.map +1 -1
- package/dist/i18n/de/tree.js +3 -0
- package/dist/i18n/de/tree.js.map +1 -1
- package/dist/i18n/de.d.ts +157 -11
- package/dist/i18n/de.js +3 -1
- package/dist/i18n/de.js.map +1 -1
- package/dist/i18n/en/composites.js +89 -1
- package/dist/i18n/en/composites.js.map +1 -1
- package/dist/i18n/en/integrations.js +49 -8
- package/dist/i18n/en/integrations.js.map +1 -1
- package/dist/i18n/en/media.js +0 -1
- package/dist/i18n/en/media.js.map +1 -1
- package/dist/i18n/en/palette.js +22 -0
- package/dist/i18n/en/palette.js.map +1 -0
- package/dist/i18n/en/tables.js +0 -1
- package/dist/i18n/en/tables.js.map +1 -1
- package/dist/i18n/en/transcript.js +2 -1
- package/dist/i18n/en/transcript.js.map +1 -1
- package/dist/i18n/en/tree.js +3 -0
- package/dist/i18n/en/tree.js.map +1 -1
- package/dist/i18n/en.js +3 -1
- package/dist/i18n/en.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/integrations/composite-ai/bibliography-fetch.d.ts +31 -0
- package/dist/integrations/composite-ai/bibliography-fetch.js +159 -0
- package/dist/integrations/composite-ai/bibliography-fetch.js.map +1 -0
- package/dist/integrations/composite-ai/composite-fill.d.ts +30 -8
- package/dist/integrations/composite-ai/composite-fill.js +97 -56
- package/dist/integrations/composite-ai/composite-fill.js.map +1 -1
- package/dist/integrations/composite-ai/composite-summary.d.ts +4 -12
- package/dist/integrations/composite-ai/composite-summary.js +7 -26
- package/dist/integrations/composite-ai/composite-summary.js.map +1 -1
- package/dist/integrations/composite-ai/derive.d.ts +29 -0
- package/dist/integrations/composite-ai/derive.js +173 -0
- package/dist/integrations/composite-ai/derive.js.map +1 -0
- package/dist/integrations/composite-ai/index.d.ts +11 -7
- package/dist/integrations/composite-ai/index.js +72 -14
- package/dist/integrations/composite-ai/index.js.map +1 -1
- package/dist/integrations/composite-ai/rendition.d.ts +45 -0
- package/dist/integrations/composite-ai/rendition.js +314 -0
- package/dist/integrations/composite-ai/rendition.js.map +1 -0
- package/dist/integrations/composite-media/index.d.ts +7 -5
- package/dist/integrations/composite-media/index.js +86 -13
- package/dist/integrations/composite-media/index.js.map +1 -1
- package/dist/integrations/transcript-ai/index.d.ts +1 -1
- package/dist/integrations/transcript-ai/index.js +5 -2
- package/dist/integrations/transcript-ai/index.js.map +1 -1
- package/dist/integrations/transcript-ai/protocol.d.ts +2 -12
- package/dist/integrations/transcript-ai/protocol.js +0 -2
- package/dist/integrations/transcript-ai/protocol.js.map +1 -1
- package/dist/integrations/transcript-ai/transcript-cleanup.d.ts +5 -5
- package/dist/integrations/transcript-ai/transcript-cleanup.js +7 -10
- package/dist/integrations/transcript-ai/transcript-cleanup.js.map +1 -1
- package/dist/markdown/MarkdownSurface.vue.d.ts +12 -11
- package/dist/markdown/MarkdownSurface2.js +3 -6
- package/dist/markdown/MarkdownSurface2.js.map +1 -1
- package/dist/markdown/document.js +1 -1
- package/dist/markdown/source-mode.d.ts +1 -1
- package/dist/nuxt/module.d.ts +1402 -54
- package/dist/nuxt/module.js +6 -49
- package/dist/nuxt/module.js.map +1 -1
- package/dist/nuxt/runtime/install-context.d.ts +7 -3
- package/dist/nuxt/runtime/install-context.js +14 -8
- package/dist/nuxt/runtime/install-context.js.map +1 -1
- package/dist/nuxt/runtime/plugins/editor-context-nuxt-ui.client.ts +2 -2
- package/dist/nuxt/runtime/server/plugins/editor-server.js +20 -12
- package/dist/nuxt/runtime/server/plugins/editor-server.js.map +1 -1
- package/dist/presets/compose.d.ts +94 -0
- package/dist/presets/compose.js +164 -0
- package/dist/presets/compose.js.map +1 -0
- package/dist/react/AdvancedEditor.d.ts +15 -15
- package/dist/react/AdvancedEditor.js +15 -13
- package/dist/react/AdvancedEditor.js.map +1 -1
- package/dist/react/EditorCommandPalette.d.ts +13 -0
- package/dist/react/EditorCommandPalette.js +118 -0
- package/dist/react/EditorCommandPalette.js.map +1 -0
- package/dist/react/EditorSettingsModal.d.ts +5 -5
- package/dist/react/EditorSettingsModal.js +7 -4
- package/dist/react/EditorSettingsModal.js.map +1 -1
- package/dist/react/EditorSettingsPanel.d.ts +7 -7
- package/dist/react/EditorSettingsPanel.js +8 -5
- package/dist/react/EditorSettingsPanel.js.map +1 -1
- package/dist/react/EditorSurface.d.ts +7 -7
- package/dist/react/EditorSurface.js +10 -6
- package/dist/react/EditorSurface.js.map +1 -1
- package/dist/react/EditorToolbar.d.ts +4 -6
- package/dist/react/EditorToolbar.js +29 -37
- package/dist/react/EditorToolbar.js.map +1 -1
- package/dist/react/SimpleEditor.d.ts +22 -23
- package/dist/react/SimpleEditor.js +21 -7
- package/dist/react/SimpleEditor.js.map +1 -1
- package/dist/react/advanced.d.ts +4 -3
- package/dist/react/advanced.js +2 -2
- package/dist/react/compose.d.ts +20 -0
- package/dist/react/compose.js +49 -0
- package/dist/react/compose.js.map +1 -0
- package/dist/react/composed-surface.d.ts +39 -0
- package/dist/react/composed-surface.js +71 -0
- package/dist/react/composed-surface.js.map +1 -0
- package/dist/react/context.js +6 -2
- package/dist/react/context.js.map +1 -1
- package/dist/react/index.d.ts +2 -1
- package/dist/react/index.js +2 -1
- package/dist/react/key-labels.js +15 -0
- package/dist/react/key-labels.js.map +1 -0
- package/dist/react/settings.d.ts +1 -1
- package/dist/react/simple.d.ts +2 -2
- package/dist/react/ui/command.js +36 -1
- package/dist/react/ui/command.js.map +1 -1
- package/dist/schema/advanced.d.ts +6 -6
- package/dist/schema/advanced.js +26 -29
- package/dist/schema/advanced.js.map +1 -1
- package/dist/server/ai.d.ts +5 -16
- package/dist/server/ai.js.map +1 -1
- package/dist/server/auth.d.ts +9 -0
- package/dist/server/collab-state.d.ts +1 -1
- package/dist/server/collab-state.js.map +1 -1
- package/dist/server/collab.d.ts +13 -13
- package/dist/server/collab.js +34 -18
- package/dist/server/collab.js.map +1 -1
- package/dist/server/crossref.js +78 -0
- package/dist/server/crossref.js.map +1 -0
- package/dist/server/errors.d.ts +1 -1
- package/dist/server/errors.js +1 -1
- package/dist/server/errors.js.map +1 -1
- package/dist/server/extract.js +308 -0
- package/dist/server/extract.js.map +1 -0
- package/dist/server/h3.d.ts +8 -0
- package/dist/{nuxt/runtime/server/utils/editor-route.js → server/h3.js} +8 -16
- package/dist/server/h3.js.map +1 -0
- package/dist/server/handlers/ai.d.ts +32 -10
- package/dist/server/handlers/ai.js +172 -37
- package/dist/server/handlers/ai.js.map +1 -1
- package/dist/server/handlers/context.d.ts +12 -5
- package/dist/server/handlers/context.js +10 -4
- package/dist/server/handlers/context.js.map +1 -1
- package/dist/server/handlers/editor.d.ts +19 -13
- package/dist/server/handlers/editor.js +49 -38
- package/dist/server/handlers/editor.js.map +1 -1
- package/dist/server/handlers/index.d.ts +4 -4
- package/dist/server/handlers/index.js +4 -4
- package/dist/server/host.d.ts +16 -25
- package/dist/server/host.js +58 -41
- package/dist/server/host.js.map +1 -1
- package/dist/server/index.d.ts +6 -4
- package/dist/server/index.js +3 -2
- package/dist/server/pdf.js +97 -0
- package/dist/server/pdf.js.map +1 -0
- package/dist/server/{adapter.d.ts → ports.d.ts} +81 -30
- package/dist/server/ports.js +29 -0
- package/dist/server/ports.js.map +1 -0
- package/dist/server/routes.d.ts +22 -0
- package/dist/server/routes.js +144 -0
- package/dist/server/routes.js.map +1 -0
- package/dist/settings/index.d.ts +1 -1
- package/dist/settings/index.js.map +1 -1
- package/dist/styles/composites.css +25 -0
- package/dist/tree/DocumentTree.js +56 -29
- package/dist/tree/DocumentTree.js.map +1 -1
- package/dist/tree/react/DocumentTree.js +23 -0
- package/dist/tree/react/DocumentTree.js.map +1 -1
- package/dist/tree/tree-host.js +2 -2
- package/dist/tree/tree-items.js +1 -1
- package/dist/vue/AdvancedEditor.js +30 -9
- package/dist/vue/AdvancedEditor.js.map +1 -1
- package/dist/vue/AdvancedEditor.vue.d.ts +32 -12
- package/dist/vue/SimpleEditor.js +62 -16
- package/dist/vue/SimpleEditor.js.map +1 -1
- package/dist/vue/SimpleEditor.vue.d.ts +39 -9
- package/dist/vue/advanced.d.ts +3 -2
- package/dist/vue/advanced.js +2 -2
- package/dist/vue/components/EditorCommandPalette.js +91 -0
- package/dist/vue/components/EditorCommandPalette.js.map +1 -0
- package/dist/vue/components/EditorCommandPalette.vue.d.ts +15 -0
- package/dist/vue/components/EditorSettingsModal.js +10 -6
- package/dist/vue/components/EditorSettingsModal.js.map +1 -1
- package/dist/vue/components/EditorSettingsModal.vue.d.ts +4 -4
- package/dist/vue/components/EditorSettingsPanel.js +10 -6
- package/dist/vue/components/EditorSettingsPanel.js.map +1 -1
- package/dist/vue/components/EditorSettingsPanel.vue.d.ts +6 -6
- package/dist/vue/components/EditorSurface.js +11 -6
- package/dist/vue/components/EditorSurface.js.map +1 -1
- package/dist/vue/components/EditorSurface.vue.d.ts +11 -11
- package/dist/vue/components/EditorToolbar.js +41 -49
- package/dist/vue/components/EditorToolbar.js.map +1 -1
- package/dist/vue/components/EditorToolbar.vue.d.ts +2 -4
- package/dist/vue/compose.d.ts +17 -0
- package/dist/vue/compose.js +51 -0
- package/dist/vue/compose.js.map +1 -0
- package/dist/vue/context-key.d.ts +6 -0
- package/dist/vue/context-key.js +6 -0
- package/dist/vue/context-key.js.map +1 -0
- package/dist/vue/context.d.ts +8 -6
- package/dist/vue/context.js +6 -5
- package/dist/vue/context.js.map +1 -1
- package/dist/vue/index.d.ts +10 -8
- package/dist/vue/index.js +10 -8
- package/dist/vue/kit/index.d.ts +2 -2
- package/dist/vue/kit/nuxt-ui.js +23 -0
- package/dist/vue/kit/nuxt-ui.js.map +1 -1
- package/dist/vue/kit/types.d.ts +40 -1
- package/package.json +30 -16
- package/dist/adapters/comments/client.d.ts +0 -64
- package/dist/adapters/comments/client.js.map +0 -1
- package/dist/adapters/routes.js.map +0 -1
- package/dist/core/toolbar.d.ts +0 -74
- package/dist/core/toolbar.js +0 -45
- package/dist/core/toolbar.js.map +0 -1
- package/dist/integrations/composite-ai/document-transcribe.d.ts +0 -14
- package/dist/integrations/composite-ai/document-transcribe.js +0 -89
- package/dist/integrations/composite-ai/document-transcribe.js.map +0 -1
- package/dist/nuxt/runtime/server/api/ai/chat.post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/ai/chat.post.js +0 -8
- package/dist/nuxt/runtime/server/api/ai/chat.post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/ai/complete.post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/ai/complete.post.js +0 -8
- package/dist/nuxt/runtime/server/api/ai/complete.post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/ai/generate.post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/ai/generate.post.js +0 -8
- package/dist/nuxt/runtime/server/api/ai/generate.post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/ai/models.get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/ai/models.get.js +0 -8
- package/dist/nuxt/runtime/server/api/ai/models.get.js.map +0 -1
- package/dist/nuxt/runtime/server/api/ai/transcribe.post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/ai/transcribe.post.js +0 -8
- package/dist/nuxt/runtime/server/api/ai/transcribe.post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js +0 -8
- package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/assets/[id].post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/settings.get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/settings.get.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/settings.get.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/settings.put.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/settings.put.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/settings.put.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/tags.get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/tags.get.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/tags.get.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/themes/[id].get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/themes/index.get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/themes/index.get.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/themes/index.get.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/themes/index.post.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/themes/index.post.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/themes/index.post.js.map +0 -1
- package/dist/nuxt/runtime/server/api/editor/users.get.d.ts +0 -5
- package/dist/nuxt/runtime/server/api/editor/users.get.js +0 -8
- package/dist/nuxt/runtime/server/api/editor/users.get.js.map +0 -1
- package/dist/nuxt/runtime/server/plugins/collab.d.ts +0 -5
- package/dist/nuxt/runtime/server/plugins/collab.js +0 -10
- package/dist/nuxt/runtime/server/plugins/collab.js.map +0 -1
- package/dist/nuxt/runtime/server/routes/collab/[id].d.ts +0 -5
- package/dist/nuxt/runtime/server/routes/collab/[id].js +0 -35
- package/dist/nuxt/runtime/server/routes/collab/[id].js.map +0 -1
- package/dist/nuxt/runtime/server/utils/editor-route.d.ts +0 -11
- package/dist/nuxt/runtime/server/utils/editor-route.js.map +0 -1
- package/dist/presets/advanced.d.ts +0 -33
- package/dist/presets/advanced.js +0 -50
- package/dist/presets/advanced.js.map +0 -1
- package/dist/presets/simple.d.ts +0 -9
- package/dist/presets/simple.js +0 -12
- package/dist/presets/simple.js.map +0 -1
- package/dist/react/advanced-preset.d.ts +0 -11
- package/dist/react/advanced-preset.js +0 -31
- package/dist/react/advanced-preset.js.map +0 -1
- package/dist/vue/advanced-preset.d.ts +0 -13
- package/dist/vue/advanced-preset.js +0 -33
- package/dist/vue/advanced-preset.js.map +0 -1
- package/docs/extending.md +0 -538
- package/docs/integration.md +0 -632
- package/docs/llms.md +0 -383
- package/docs/usage.md +0 -1076
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,82 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.1.0
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Composites: field type `multiselect` (`CompositeMetaField`; `options` required, value stored as `string[]`; the key is removed when none is chosen). It is rendered in the details popover and inspector (Vue `InputMenu`, React checkbox list), in table cells and sort keys, in the AI brief and in the chat block model.
|
|
8
|
+
- Composites: `CompositeKind.chrome?: { tags?: boolean }`; `chrome: { tags: false }` hides that kind's tag chips, `+` chip and inspector tags field (`CompositeRow.tagsVisible`).
|
|
9
|
+
- `EditorFeature.transactionGuards(ctx)` and the `TransactionGuard` type: features can refuse a whole document-changing transaction by returning a notice string. The first refusal wins and the string is shown through `notify`. The `TransactionGuards` extension and `transactionGuardExtensions(preset, ctx)` are exported from `core`.
|
|
10
|
+
- `EditorServerOptions.routes` (`installEditorServer`): a function that filters or reorders the route table before it is mounted, so a host that serves some paths itself (for example `/api/editor/assets/*`) can drop them. The `RouteDef` type is exported from `@ecsplico/editor/server/nitro`.
|
|
11
|
+
- `@ecsplico/editor/comments/server` exports the pure discussion operations `createThread`, `addComment`, `editComment`, `removeComment`, `setThreadStatus`, `updateAnchor`, `removeThread` and `emptyDiscussion`, so a host `CommentStore` over its own database applies them to a stored `Discussion` instead of reimplementing the rules (guide „Storage adapters“, section „Your own store“).
|
|
12
|
+
|
|
13
|
+
## 3.0.0
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- Asset hashes: `POST /api/editor/assets/:id` answers `{ url, name, sha256 }` and stores `sha256` in the `AssetRecord`; `backend.assets.upload` may resolve `{ url, sha256? }`. Image, audio, video and file nodes have a `hash` attribute (`data-hash`), set by every upload path; the memory backend leaves it empty. `composite-media` imports audio/video as `recording`, images as `figure`, other files as `document`, and adds the block action „Quelle ersetzen“ (`source-replace`).
|
|
18
|
+
- Source-holding Bausteine: the composite kinds `recording` (audio/video; `recordedAt`, `participants`, `durationSeconds`), `paper` and `book` (PDF; `bib`, `doi` / `isbn`), `figure` (image; `credit`) and `rendition` („Lesefassung“: derived readable content; `derivation`, `language`), next to `document`. `CompositeKind.source` (with `SOURCE_MEDIA_TYPES`) names the media block types of a source-holding kind; `sourceOf(composite, kinds)` finds the source block (`{ node, index, asset, hash }`), `renditionsOf(composite)` its derived children. The source is the `audio|video|image|file` block in the Baustein's body, the readable form a child `rendition` Baustein whose body is the derived block tree (chapters as nested `section` Bausteine in composite structure). No new container node and no new feature.
|
|
19
|
+
- Provenance: `meta.derivation` (`Derivation`: `from` (`{ asset }` or `{ block }`), `method`, `model?`, `createdAt`, `inputHash`, `outputHash`, `output?`) on any Baustein, with `DERIVATION_KEY`, `derivationOf`, `derivationState` (`stale`/`edited`), `bodyMarkdown` and `sha256Hex` (`core`, pure JS via `@noble/hashes`). A derived Baustein starts collapsed to a faded preview (chevron with `aria-expanded`, expands with the caret), shows an „abgeleitet“ badge and, for an asset source, „Quelle geändert“ when the source block's `hash` differs from `inputHash`; the details card adds method, model, date, „bearbeitet“ (body differs from `outputHash`), „Quelle geändert“ for block-derived Bausteine (the source block's Markdown hash differs from `inputHash`) and a link to the stored raw output. Provenance and `bib` survive Markdown fences of every kind.
|
|
20
|
+
- Bibliographic data: `meta.bib` as CSL-JSON (`CslItem`, `CslName`, `CslDate`, `CslType`, `CSL_TYPES`, `BIB_KEY`) with `bibOf`, `cslOf`, `citeShort` („Doe et al. 2024“), `citeFull`, `bibtexOf`, `yearOf`, `cslTypeOptions`. The Baustein title is the work's title; `bib` never stores one. Block action „Literaturangabe exportieren (BibTeX)“ (`.bib` download) on every Baustein with `bib`.
|
|
21
|
+
- Composite field types `reference` (a Baustein of the document, optionally restricted by `CompositeMetaField.targets`), `bibliography` (form editor for `meta.bib` with „BibTeX kopieren“ and, with the AI capability, „DOI abrufen“) and `derivation` (read-only provenance), in the Baustein table, the details card (Vue and React), the AI brief (`compositeAiBrief`) and the chat prompt.
|
|
22
|
+
- Inline `reference` chip (`ReferenceNode`, `REFERENCE_NODE`, ability `insert.reference`, `/verweis`): `[@` opens a suggestion over the document's Bausteine; the chip shows the live `citeShort` (or the title), has a „Stelle“ locator (`S. 12`, `3:07`) and reveals the target on click. Markdown is `[@<block id>]` or `[@<block id>, <locator>]` (`referencesFromText`, `normalizeReferences`, `compositeIdsOf`); AI-written `[@id]` text becomes chips through the `normalize` stage, and the chat knows the syntax. The details card lists backlinks („Verweise“: `compositeBacklinks`, `CompositeBacklink`, `CompositeReference`).
|
|
23
|
+
- Markdown fences carry the block id of a referenced Baustein: `::: kind #<block id> {meta}` is written only for Bausteine that a `reference` chip or field points at, so `[@id]` survives a Markdown round trip (source mode, import); other fences are unchanged. The pre-pass runs through the new `NodeConfig.markdownPrepare(json, editor)` hook of the document Markdown serializer.
|
|
24
|
+
- Transcript segments carry `start`/`end` (seconds; `data-start`/`data-end`, JSON/Yjs only, not in Markdown); the segment shows a `mm:ss` button that seeks and plays the source audio/video. `revealSource(editor, targetId, locator)`, `seekSource`, `parseLocator`, `SourceLocator` and the `SourceReveal` extension (command `seekSource`) show a Baustein's source at a locator: a time seeks the media, a page opens the PDF viewer at `#page=N`; a `reference` chip with a locator does this on click.
|
|
25
|
+
- `POST /api/ai/extract` (`extractPost`, `extractBodySchema`) and `backend.ai.extract(body, signal)`: one route for the readable form of a stored asset, `method` `auto` (by MIME type), `transcription` (timestamped segments, `verbose_json`), `pdf-text` (pdf.js, page markers `<!-- page N -->`), `ocr` (rasterised pages through the `generate` model; falls back to the text layer with `warnings: ['ocr-unavailable']`), `description` (image) or `bibliography` (Crossref by DOI, else model extraction); the response carries `markdown`, `segments?`, `bib?`, `inputHash`, `outputHash` and the asset name of the stored raw output (`output`), plus `warnings`. New dependencies `pdfjs-dist` and `@noble/hashes`, optional dependency `@napi-rs/canvas` (OCR page rasterisation).
|
|
26
|
+
- Deepgram speech-to-text: `TranscriptionConfig.provider: 'deepgram'` sends the raw audio to `<endpoint>/listen` (e.g. `https://api.deepgram.com/v1`, model `nova-3`, key as `Token`) and turns Deepgram's utterances into the timed transcript segments; `'openai'` (default) keeps the OpenAI-compatible `/audio/transcriptions`. `TranscriptionConfig.language` fixes the spoken language (else OpenAI guesses and Deepgram detects it). `ExtractResponse.model` names the speech-to-text model, which `meta.derivation.model` of a transcript records; the PDF text layer records no model. The repository's Nuxt host enables Deepgram when `NUXT_TIPTAP_EDITOR_AI_TRANSCRIPTION_API_KEY` is set.
|
|
27
|
+
- `composite-ai` actions (all behind the ability `composite.derive`): „Lesefassung erzeugen“ (`createRendition`, `canCreateRendition`: a new `rendition` child after the source block, transcript segments with timestamps, structured full text, or an image description; fills an empty `bib` and title from `bibliography`), „Neu erzeugen (ersetzen)“ (`regenerateRendition`, `canRegenerateRendition`, `RenditionOptions`; warns when the body was edited since generation, keeps the block id), „Ableiten (KI)“ (`deriveComposite`, `canDeriveAfter`, `derivableKindsOf`, `isDerivableSource`: a sibling Baustein of any kind with `ai` generated from the Baustein's body, `derivation.from.block`, so a translation or summary is a rendition of a rendition) and „Literaturangaben abrufen“ (`fetchBibliography`, `canFetchBibliography`, `doiOf`; the editor command `fetchCompositeBibliography` is behind the bibliography editor's „DOI abrufen“). `generateCompositeBody` is the request part of `fillComposite`, reused by `deriveComposite`.
|
|
28
|
+
- The ⌘K command palette: `core-ui` binds `Mod-k` and mounts `EditorCommandPalette` (`@ecsplico/editor/vue` on Nuxt UI `UCommandPalette` in a `UModal`, `@ecsplico/editor/react` on shadcn `CommandDialog`) as an overlay of the surface. It lists every command with `palette !== false` (features' and the host's `commands` transformer), grouped like the toolbar (`ToolbarGroupDef.labelKey` names the heading's i18n key), disabled where `commandState` disables it, filtered by label or id; a `menu` command opens its rows as a second level; selecting runs the command and closes. `coreUiFeature(ui?: CoreUi<C>)` takes the palette component (`advancedEditor()`, `composeEditor()` of `/vue/advanced` and `/react/advanced`, `SimpleEditor` and `AdvancedEditor` pass it; the framework-free `simpleEditor()` has no palette); `EditorUi` gains `togglePalette()` and `paletteOpen` (implemented by the Vue and React `EditorSurface`, exposed by `useEditorUi`); the framework-free model is `paletteGroupsOf`/`filterPalette` (`core`). The Nuxt UI kit gains the `CommandPalette` widget (`VueUiKit.CommandPalette`, `CommandPaletteProps`). Message keys `palette.*` (de/en).
|
|
29
|
+
- The client port `EditorBackend` (`core`: `EditorBackend`, `BackendCapability`, `BackendError`, `AiStreamEvent`, `CollaborationToken`) and its HTTP adapter `createHttpBackend({ fetch?, base? })` (`/adapters/http`), which owns the editor's paths. `createEditorContext({ backend })` and `FeatureContext.backend` carry it (default: the HTTP backend over `fetch`); the Nuxt module installs it over `$fetch`.
|
|
30
|
+
- Bundle-isolation fixture `adapters-http`.
|
|
31
|
+
- The in-memory backend `createMemoryBackend({ documents?, users?, tags? })` (`/adapters/memory`, name `'memory'`): documents, `blob:` asset URLs, seeded `@`/`#` lookups and settings, for hosts without a data layer; the simple and markdown examples run on it without any `/api` request. Bundle-isolation fixture `adapters-memory`.
|
|
32
|
+
- `EditorFeature.backend`: the backend capabilities a feature cannot work without (`ai`: `ai`, `media`: `assets`, `themes`: `themes`, `collab`: `collaboration`). A surface session over a backend that lacks one throws `feature "<id>" needs backend capability "<cap>", which "<name>" lacks` (the collaboration capability is never required by a session: the surface only consumes the session the host opened, through its own provider or `useEditorDocument`).
|
|
33
|
+
- `serverRoutesOf(ports, { ai })` (`server/routes.ts`): the editor's HTTP routes as one table, each served only when its port is present; `installEditorServer` mounts it for Nuxt and plain Nitro hosts alike. `collab.authenticateUpgrade` (refuse the `/collab/:id` upgrade with HTTP 401) is available on `installEditorServer`.
|
|
34
|
+
- One editor configuration with three views (`/config`): `defineEditorConfig(input)` applies every default once (locale `'de'`, the `sonnet` and `flashLite` OpenRouter presets and their slots, 30 AI requests per user and minute, `collab.authenticateUpgrade: false`, empty `apiKey`s so env variables can override them); `serverConfig(config)` is the server view (presets with keys, shared key, slots, transcription, rate limit, collab; spread it into `installEditorServer`), `publicConfig(config)` the browser view (locale, messages, slots, `transcription` flag; `createEditor({ ...publicConfig })`). `PresetConfig`/`TranscriptionConfig` live there (the server entry re-exports them); `EditorAiConfig` is `EditorPublicConfig['ai']`. The Nuxt module options are `EditorConfigInput` and both runtime configs come from the two views, so `ai.transcription` is typed without a cast. The rate limit now sits at `runtimeConfig.tiptapEditor.rateLimit` (was `…ai.rateLimit`; the module option stays `ai.rateLimit`).
|
|
35
|
+
- `useEditorDocument` for React (`/adapters/react`, the twin of the Vue composable: `modelValue`, `onChange`, `ready`, `dirty`, `save`, `reload`, `error`, `collaboration`, `comments`, `bind`), reading its backend from `EditorContextProvider`; a `null`/`undefined` id keeps it idle. Bundle-isolation fixture `adapters-react`; the entry name is no longer reserved. The react-advanced example opens its collaboration session with it.
|
|
36
|
+
- `GET /api/editor/capabilities` (`CAPABILITIES_ROUTE`, handler `capabilitiesGet`): lists what the installed server serves (`serverCapabilities(ports, { ai?, collaboration? })`: `ai` and `collaboration` follow what the installer really mounted), behind `authenticate`. `createHttpBackend({ probe: true })` asks it once, drops the capabilities the server lacks and exposes the request as `EditorBackend.ready`, which `createEditorContext` awaits before its `ready` store turns true; a failed probe keeps every capability and warns once. Default `probe: false` (no request). The Nuxt module installs its backend with `probe: true`, and its client plugin finishes only after the probe, so no editor mounts before the capabilities are known. `BACKEND_CAPABILITIES` (`core/backend-capability`) lists the capability names.
|
|
37
|
+
- `AdvancedEditor` (Vue and React) takes the composition: `content`, `interaction`, `ai`, `add`, `remove`, `backend` (defaults `'rich'`/`'full'`/`true`; `backend` defaults to the editor context's), builds its preset with `composeEditor` once at setup and exposes it (`preset` on the Vue component instance, on the React ref handle `AdvancedEditorHandle`, with `omitted`). `<AdvancedEditor :remove="['tables']" />` and `<AdvancedEditor content="basic" interaction="minimal" :ai="true" />` need no hand-built preset. `SimpleEditor` takes `add` (host features after `core-content` and `core-ui`, e.g. `aiFeature()`) and exposes the `preset` it mounts (React: `SimpleEditorHandle`); it does not use `composeEditor`, which keeps the simple entry's bundle free of every catalog feature.
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- Documentation moved to https://skaile-ai.github.io/skaile-editor/; the package no longer ships `docs/`.
|
|
42
|
+
- `composeEditor` takes `collaboration?: boolean`: with a host-supplied collaboration session (the surface's `collaboration` prop; `AdvancedEditor` on Vue and React sets it itself) `collab` and `comments` stay whatever capabilities the backend offers, so a host with its own Hocuspocus provider works over the default backend. Without it a backend lacking `collaboration` still prunes both (`omitted`).
|
|
43
|
+
- The comment mark belongs to the document model: `composeEditor` adds `CommentMark` (schema and extension, inert) to the `authors` feature when the final list has no `comments`, so every rich composition, including viewers and ones over a backend without collaboration, loads documents that carry comments and has the schema of the server. The features themselves stay independent: `authors` does not import the comments feature.
|
|
44
|
+
- `composeEditor` throws `"core-content" cannot be removed` instead of silently ignoring `remove: ['core-content']`.
|
|
45
|
+
- The React `AdvancedEditor` waits for `backend.ready` before composing and renders nothing until then, like the Vue surface and the Nuxt plugin.
|
|
46
|
+
- Settings persistence, the media upload, `@`/`#` lookups and the theme list, stylesheet, upload and delete go through the backend (`settings`, `assets`, `users`, `tags`, `themes`) instead of `ctx.fetch`; a backend without a capability offers no mention suggestions.
|
|
47
|
+
- The Nuxt module no longer ships per-route files (`runtime/server/api/**`, `routes/collab/[id].ts`); its server plugin calls `installEditorServer` on first request (after the host's plugins have registered the ports). Nuxt hosts now answer `GET`/`PUT /api/editor/documents/:id` and, with a `comments` port, `GET`/`POST /api/editor/comments/:id`. Routes of a port the host did not register are no longer mounted (404) instead of answering 501.
|
|
48
|
+
- The process-wide server of `@ecsplico/editor/server` is what `installEditorServer` adopted: `configureEditorServer` and `EditorServerConfig` are gone (pass `ai`/`rateLimit`/`collab` to `installEditorServer`, e.g. `...serverConfig(defineEditorConfig(...))`). `useCollabServer`, `useAiModels`, `useRateLimiter`, `resolveModel`, `listAiModels`, `enforceAiRateLimit`, `liveContent`, `collabStats` and `collabContentChanged` throw `@ecsplico/editor: server not installed` before installation; `useAiModels`/`useRateLimiter` also throw when it was installed without `ai`, `useCollabServer` with `collab: false`. `setEditorPorts` only records the ports (and schema) a later installer reads. `installEditorServer`'s rate-limit default is the one of `defineEditorConfig`.
|
|
49
|
+
- `useEditorDocument` (`/adapters/vue`) loads, saves, connects collaboration and builds the comments model through the backend: `useEditorDocument(id, { backend?, user?, canComment?, collaboration?: boolean | { token? } })`, the backend defaulting to the editor context's. The `fetch` option and the `collaboration: { url, token }` option are gone (the HTTP backend derives the websocket URL from its `base`). The default context backend has neither collaboration nor comments: install `createHttpBackend()` (`createEditor({ backend })`) or pass `backend`.
|
|
50
|
+
- `ai.transcribe` is replaced by `ai.extract` (see Removed); `EditorPublicConfig.ai.transcription` stays the „transcription configured“ signal and gates „Lesefassung erzeugen“ for audio/video.
|
|
51
|
+
- Imported audio/video land in a `recording` Baustein and images in a `figure` Baustein (before: `document` for every file); PDFs and other files stay `document` until the user switches the kind to `paper` or `book`. `document` accepts every source media type.
|
|
52
|
+
- „Zusammenfassung erzeugen (KI)“ (`compositeSourceText`) summarises the Baustein body only, which now holds the rendition children, instead of falling back to a transcript field.
|
|
53
|
+
|
|
54
|
+
### Removed (breaking)
|
|
55
|
+
|
|
56
|
+
- `@ecsplico/editor/presets/simple` and `@ecsplico/editor/presets/advanced` are one module now: import `composeEditor`, `simpleEditor`, `CONTENT`, `INTERACTION`, `AI` and the types from `@ecsplico/editor/presets/compose`. `simpleEditor` is no longer re-exported by `@ecsplico/editor/vue/advanced` or `/react/advanced`.
|
|
57
|
+
|
|
58
|
+
- `EditorContextOptions.fetch`, `EditorContextOptions.settings.remote`, `EditorContext.fetch` and `FeatureContext.fetch`: pass `backend` instead (`createEditorContext({ backend })`, `createEditor({ backend })`; to send through your own HTTP client use `createHttpBackend({ fetch })`). Settings sync per account whenever the backend offers `settings` (the default backend does); use `createMemoryBackend()` for local-only settings.
|
|
59
|
+
- `FeatureContext.upload`, `FeatureContextOptions.upload`, `UploadFn` and the `upload` prop of `EditorSurface`, `AdvancedEditor` (Vue and React): uploads go through `backend.assets.upload(documentId, file)`; provide it in a custom `EditorBackend`.
|
|
60
|
+
- `createRestCommentsModel` and the entry `@ecsplico/editor/comments/client` (with its fixture `headless-comments-client`): the REST comments model is `backend.comments(documentId, …)` of `createHttpBackend()` (`/adapters/http`).
|
|
61
|
+
- The `preset` prop of `EditorToolbar`, `EditorSettingsPanel` and `EditorSettingsModal` (Vue and React): they take the `editor` (from the surface's `ready`/`onReady`) and read its preset through the registered editor entry. Without an editor the toolbar renders no groups and the panel/modal nothing (before, `preset` rendered a disabled toolbar). The `preset` prop of `SimpleEditor` and `AdvancedEditor` is gone as well (compose with the dimension props, or mount an `EditorSurface` over `advancedEditor(...)`).
|
|
62
|
+
- `EditorFeature.toolbar`, `EditorFeature.slashCommands`, the surface prop `slashCommands` (now `commands`), `ToolbarItem`, `ToolbarItemBase`, `SlashCommandItem`, `commandItem`, `mergeToolbarGroups` and the adapter `core/legacy-commands.ts`: a feature contributes `commands(ctx)` (`CommandDef`, one declaration per command with `toolbar: { group, order? }` and/or `slash: { id? }` placements, `creates`, `ability`, `can`) plus `toolbarGroups`; build chain commands with `command({ ..., command: chain => ... })`. Every built-in feature (composites, tables, media, transcript, ai, comments, authors, composite-media) and the app callout are migrated; the callout's toolbar button and `/hinweis` entry are one command. Host commands that were `SlashCommandItem`s become `CommandDef`s with `slash: {}`.
|
|
63
|
+
- `ai.transcribe`, `POST /api/ai/transcribe` (`transcribePost`, `transcribeBodySchema`) and `transcribeDocument`: use `backend.ai.extract({ documentId, name, method: 'transcription', model })` / `POST /api/ai/extract` (the HTTP backend maps it; a custom `EditorBackend` or server must provide `extract`). `mediaAssetOf` is gone as well: `sourceOf(composite, kinds)` finds the source block by the kind's `source` types, not by position.
|
|
64
|
+
- The `transcript` field of the `document` kind (`meta.transcript`): stored documents are migrated on load (`migrateLegacyContent`) into a `rendition` child titled „Transkript“ with `meta.derivation` (`method: 'transcription'`, the source asset's name, empty hashes) and one paragraph per blank-line-separated chunk; the summary no longer reads the field.
|
|
65
|
+
- The ability `composite.transcribe` (`ABILITY.compositeTranscribe`) is renamed `composite.derive` (`ABILITY.compositeDerive`); hosts that grant or deny it through `abilities` must use the new id.
|
|
66
|
+
|
|
67
|
+
### Changed (commands)
|
|
68
|
+
|
|
69
|
+
- Creating a Baustein respects Accepted children everywhere: the composites feature contributes an insert guard over `kindAccepts` (the rule `AcceptedChildren` enforces on transactions), so `/` lists no Baustein kind a parent refuses (inside an `Aufgabe`, for example) and the toolbar greys the insert button there. Commands with `creates` (tables, task lists, composites, callout, core blocks) are also greyed or hidden where the schema does not allow the node, e.g. `Tabelle einfügen` inside a table. `canGroup`/`canFlatten` are defined once for the toolbar menu and `/` entries.
|
|
70
|
+
- The surface session warns once per command, when it mounts, whose `ability` is neither in `ROOT_ABILITIES` nor granted by `abilities.root` (`@ecsplico/editor: command "<id>" needs ability "<a>", ...`); such a command never shows.
|
|
71
|
+
- „In Baustein umwandeln“ follows the same rule: `convertBlockTo` (and with it the toolbar's and the palette's „In Baustein umwandeln“ menu and the block action) refuses a Baustein kind the parent Baustein does not accept (`guardsAccept`, exported from `core/commands`, runs the registered insert guards for the node the target creates). The conversion of a Baustein with nested Bausteine into a kind that refuses them is still caught only by `AcceptedChildren` on the transaction.
|
|
72
|
+
- Two commands with the same `id` in one editor now fail at session creation (`@ecsplico/editor: command "<id>" is declared by "<a>" and "<b>"`; a command added by the host's `commands` transformer counts as `"host"`).
|
|
73
|
+
- The Vue ⌘K palette filters with `filterPalette` like the React one (prefix matches first, then substring, on label and command id; no search in `description`) instead of Nuxt UI's own matching: `CommandPaletteGroup.ignoreFilter` and `CommandPaletteProps.searchTerm` are new on the Vue kit contract.
|
|
74
|
+
|
|
75
|
+
### Changed (transport)
|
|
76
|
+
|
|
77
|
+
- The default backend (`createFetchBackend`, `createHttpBackend`) sends through the platform `fetch` and no longer imports `ofetch`; a host hands in `$fetch` explicitly (`createHttpBackend({ fetch })`, as the Nuxt plugin does). The `simple` entries fixture asserts its bundle holds no `ofetch`.
|
|
78
|
+
- Core no longer imports features, integrations or adapters: the wire and model types `EditorBackend` names (`MentionUser`, `ModelProfile`, `ModelRef`, `ThemeRecord`, the transcript-cleanup request/response, the comment thread and `CommentsModel` types) are defined in `core/backend-types.ts` and exported by the same public entries as before (`/mentions/schema`, `/ai/protocol`, `/themes/schema`, `/comments/schema`, `/integrations/transcript-ai/protocol`); the route constants moved from `adapters/routes` to `core/api-routes`, and `server/adapter.ts` (only `AuthenticateRequest`) to `server/auth.ts`. The `setEditorPorts` error reads `@ecsplico/editor: setEditorPorts() was not called`.
|
|
79
|
+
|
|
3
80
|
## 2.1.2
|
|
4
81
|
|
|
5
82
|
### Added
|
|
@@ -17,7 +94,7 @@
|
|
|
17
94
|
|
|
18
95
|
### Added
|
|
19
96
|
|
|
20
|
-
- The storage and connection layer of the former `@ecsplico/editor-adapters`, as 11 subpath entries (guide:
|
|
97
|
+
- The storage and connection layer of the former `@ecsplico/editor-adapters`, as 11 subpath entries (guide: https://skaile-ai.github.io/skaile-editor/guides/storage-adapters): `@ecsplico/editor/adapters` (types only), `/adapters/json`, `/adapters/drizzle`, `/adapters/forge`, `/adapters/vue` (`useEditorDocument`), `/anchors`, `/comments/server`, `/comments/json`, `/comments/drizzle`, `/comments/client` and `/server/nitro` (`installEditorServer`, the Nuxt-free Nitro host). Exported names are unchanged.
|
|
21
98
|
- Optional peer dependency `drizzle-orm` (`^0.45.0`), needed only by `/adapters/drizzle` and `/comments/drizzle`.
|
|
22
99
|
- Bundle-isolation fixtures `adapters-node`, `adapters-drizzle`, `adapters-nitro`, `adapters-vue` and `headless-comments-client`: Vue is reachable only from `/adapters/vue`, Nitro only from `/server/nitro`, drizzle only from the two drizzle entries, React from none.
|
|
23
100
|
- Example `examples/vue-nitro-json` (`bun run proto:vue-nitro-json`): a Vue editor on a bare Nitro server with JSON-file storage.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @ecsplico/editor
|
|
2
2
|
|
|
3
|
-
A Vue and React editor library on TipTap v3. Editors are assembled from **features**: the *simple* editor is the core
|
|
3
|
+
A Vue and React editor library on TipTap v3. Editors are assembled from **features**: the *simple* editor is the core features alone (formatting, headings, lists, quotes, code, undo/redo) and needs no backend, no Yjs and no feature code; the *advanced* editor composes every feature (media, mentions, transcripts, composites, authors, comments, AI, collaboration, block UI, site-wide Obsidian themes and their integrations) on both surfaces. The framework-free `./core` holds the feature model, and every feature's logic is framework-free too (`./<feature>`): a feature is built from a typed **UI binding** (`<x>FeatureCore(ui)`) that the Vue layer (`./<feature>/vue`, Nuxt UI chrome) and the React layer (`./<feature>/react`, shadcn/ui on Radix and Tailwind) fill with their components, node views and notice seam. Toolbar, settings panel and modal, outline, AI sidebar, comments margin, composite table and inspector, and the file browser are components you place anywhere beside an editor; both layers ship the simple editor (`./vue/simple`, `./react/simple`) and the advanced editor (`./vue/advanced`, `./react/advanced`).
|
|
4
4
|
|
|
5
5
|
## Prerequisites
|
|
6
6
|
|
|
@@ -52,38 +52,45 @@ const content = ref()
|
|
|
52
52
|
</template>
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
The module's API routes call the host's `
|
|
55
|
+
The module's API routes call the host's `EditorPorts` (identity first, then one port per capability: `documents`, `collabState`, `directory`, `assets`, `settings`, `themes`, `models`, `comments`). Register them in a Nitro plugin; without them the client logs „Einstellungen konnten nicht geladen werden“ and every route answers 500. A route whose port you leave out answers 501. These minimal ports keep everything in memory and let any visitor in (replace `authenticate` and the storage with yours):
|
|
56
56
|
|
|
57
57
|
```ts
|
|
58
58
|
// server/plugins/editor-adapter.ts
|
|
59
59
|
import type { JSONContent } from '@tiptap/core'
|
|
60
|
-
import { type
|
|
60
|
+
import { type AssetStore, setEditorPorts } from '@ecsplico/editor/server'
|
|
61
61
|
|
|
62
62
|
export default defineNitroPlugin(() => {
|
|
63
63
|
const contents = new Map<string, JSONContent>()
|
|
64
64
|
const states = new Map<string, Uint8Array>()
|
|
65
|
-
const assets = new Map<string, Parameters<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
65
|
+
const assets = new Map<string, Parameters<AssetStore['storeAsset']>[1]>()
|
|
66
|
+
setEditorPorts({
|
|
67
|
+
// `null` = 401 on API routes; on /collab the socket is closed with 4401 (HTTP 401 at the upgrade with `collab.authenticateUpgrade`)
|
|
68
|
+
identity: { authenticate: async () => ({ id: 'demo', username: 'demo' }) },
|
|
69
|
+
documents: {
|
|
70
|
+
loadContent: async id => contents.get(id) ?? null,
|
|
71
|
+
storeContent: async (id, content) => { contents.set(id, content) },
|
|
72
|
+
listContents: async () => [...contents].map(([id, content]) => ({ id, content })),
|
|
73
|
+
},
|
|
74
|
+
collabState: {
|
|
75
|
+
loadState: async id => states.get(id) ?? null,
|
|
76
|
+
storeState: async (id, state) => { states.set(id, state) },
|
|
77
|
+
removeState: async (id) => { states.delete(id) },
|
|
78
|
+
},
|
|
79
|
+
directory: { listUsers: async () => [] },
|
|
80
|
+
assets: {
|
|
81
|
+
storeAsset: async (id, asset) => { assets.set(`${id}/${asset.name}`, asset) },
|
|
82
|
+
loadAsset: async (id, name) => {
|
|
83
|
+
const asset = assets.get(`${id}/${name}`)
|
|
84
|
+
if (!asset) return null
|
|
85
|
+
const { data, ...record } = asset
|
|
86
|
+
return { record, data }
|
|
87
|
+
},
|
|
81
88
|
},
|
|
82
89
|
})
|
|
83
90
|
})
|
|
84
91
|
```
|
|
85
92
|
|
|
86
|
-
The advanced editor, every adapter method, collaboration and AI are covered in the [
|
|
93
|
+
The advanced editor, every adapter method, collaboration and AI are covered in the [Nuxt quick start](https://skaile-ai.github.io/skaile-editor/getting-started/quick-start-nuxt) and the [`EditorPorts` guide](https://skaile-ai.github.io/skaile-editor/guides/editor-ports).
|
|
87
94
|
|
|
88
95
|
### Building and developing in this repository
|
|
89
96
|
|
|
@@ -91,144 +98,20 @@ The advanced editor, every adapter method, collaboration and AI are covered in t
|
|
|
91
98
|
|
|
92
99
|
Each `exports` entry carries a custom **`skaile-source`** condition first (pointing at `src`) followed by `types`/`import` (or `default`) pointing into `dist`. This repository's Nuxt app (`nuxt.config.ts`) and the examples (`examples/*/vite.config.ts`, `tsconfig.json#customConditions`) enable that condition for Vite, Nitro and the type checker, so **editing the library needs no build step in dev**. Consumers outside the repository never set the condition and get `dist`. `bun run check:editor-entries` builds first and judges the **built** output through `exports` (no `skaile-source`), so it proves what is published; `bun run check:editor-composition` builds first and loads the built entries; `bun run typecheck:editor` resolves through `src` (`customConditions: ["skaile-source"]` in `packages/editor/tsconfig.json`).
|
|
93
100
|
|
|
94
|
-
##
|
|
95
|
-
|
|
96
|
-
Every entry is an explicit subpath of `package.json#exports`; there is no wildcard into internal folders and no runtime umbrella barrel. Importing an entry registers nothing globally.
|
|
97
|
-
|
|
98
|
-
| Import | Contents |
|
|
99
|
-
|---|---|
|
|
100
|
-
| `@ecsplico/editor` | Type-only: `EditorSettings`, `EditorFeature`, `EditorPreset`, `FeatureContext`, `AnchorResolver`, `ToolbarGroup`, `ToolbarItem`, `BlockAction`, `SlashCommandItem`, `AbilitiesOptions`, `EditorMetadata`, `MetadataItem`, `AuthorIdentity`, … |
|
|
101
|
-
| `@ecsplico/editor/vue` | The Vue layer (Nuxt UI chrome): `createEditor` (Vue plugin around `createEditorContext`), `EDITOR_CONTEXT`, `useEditorContext`, `useEditorSettings`, `useNotifier`, `trackedStore`, `useStoreRef`, `useWritableStoreRef`, `storeFromRef`, `EDITOR_UI`, `useEditorUi` (`openSettings`, `toggleSidebar`, `toggleComments`, `commentsOpen`), `vueSuggestionRenderer`, the components `EditorSurface`, `EditorToolbar`, `EditorSettingsPanel`, `EditorSettingsModal`, `SettingsSection`, `SuggestionList`, and the types `VueFeature`, `VuePreset` (the preset components are the two entries below) |
|
|
102
|
-
| `@ecsplico/editor/vue/simple` | `SimpleEditor` component |
|
|
103
|
-
| `@ecsplico/editor/vue/advanced` | `AdvancedEditor` component (every feature, optional collaboration session) and `advancedEditor(options): VuePreset` (the preset for `EditorToolbar`/`EditorSettingsPanel`/`EditorSettingsModal` beside it, and the base for own feature lists) |
|
|
104
|
-
| `@ecsplico/editor/react` | The React layer (shadcn/ui chrome; Vue-free): `EditorContextProvider`, `useEditorContext`, the components `EditorSurface` (ref handle `EditorSurfaceHandle`: `editor`, `openSettings`), `EditorToolbar`, `EditorSettingsPanel`, `EditorSettingsModal`, `SettingsSection`, `SuggestionList`, `Icon`, the hooks `useEditorSettings` (`settings`, `update`, `set`, `ready`, `synced`), `useEditorUi`, `useNotifier`, `useStore`, `EditorUiContext`, `reactSuggestionRenderer`, the notice seam `reactNotifier` and sonner's `Toaster` (mount it once per page), the `cn` class helper, and the types `ReactFeature`, `ReactPreset`, `EditorSurfaceProps`, `EditorSurfaceHandle`, `SuggestionListHandle`. Presets are `defineEditor({ features })` from `/core` over the `/<feature>/react` bindings and framework-free features, or `advancedEditor()` from `/react/advanced` |
|
|
105
|
-
| `@ecsplico/editor/react/simple` | `SimpleEditor` component (core feature only), `SimpleEditorProps` |
|
|
106
|
-
| `@ecsplico/editor/react/advanced` | `AdvancedEditor` component (every feature and integration with its React binding, optional collaboration session; props `AdvancedEditorProps` = `EditorSurface`'s except `preset`, plus `compositeKinds`) and `advancedEditor(options): ReactPreset`; mount `Toaster` from `/react` beside it |
|
|
107
|
-
| `@ecsplico/editor/react/styles/ui-vars.css` | Maps the shadcn tokens (`--primary`, `--background`, …) to the `--ui-*` variables the feature sheets read; import it before `core.css` |
|
|
108
|
-
| `@ecsplico/editor/react/styles/advanced.css` | One import for React hosts of the advanced editor: `ui-vars.css`, `core.css`, every feature sheet and `themes.css` (with the shadcn bridge for Obsidian themes), in the order the Nuxt module registers them |
|
|
109
|
-
| `@ecsplico/editor/presets/simple` | `simpleEditor(): EditorPreset` (core feature only) |
|
|
110
|
-
| `@ecsplico/editor/presets/advanced` | Framework-free: `ADVANCED_FEATURE_IDS` (feature ids in schema order: `core`, `media`, `transcript`, `composites`, `mentions`, `authors`, `comments`, `ai`, `collab`, `block-ui`, `composite-media`, `composite-ai`, `transcript-ai`, `themes`), `advancedEditorCore(bound, options)` (assembles that list: the layer binds only the UI-bound features, `AdvancedFeatures<C>`; core, mentions and the three integrations are added here), `AdvancedEditorOptions`. The ready presets are `advancedEditor` of `/vue/advanced` and `/react/advanced` |
|
|
111
|
-
| `@ecsplico/editor/core` | Framework-free (Tiptap/ProseMirror only; imports no `vue`, `@tiptap/vue-3`, `@nuxt/ui` or React): `defineEditor`, `coreFeature`, `createEditorContext` (settings context and the translator `ctx.t`, options `locale: 'de' | 'en'` and partial `messages`; with `createStore` `createStore`, `derived`, `Store`, `ReadonlyStore`), the notice seam (`Notice`, `Notifier`, `silentNotifier`), the suggestion renderer seam (`SuggestionPopup`, `suggestionPopupOf`, `SuggestionListProps`, `SuggestionPopupHandle`, `SuggestionPopupRenderer`), `registerEditor`, `Abilities` and ability helpers, `BlockFlash`, `SlashCommand`, `Metadata`, `parseBlocks` / `DEFAULT_BLOCK_PIPELINE`, generic helpers `downloadText` and `fetchErrorMessage`, the feature/toolbar/extension-point types (`EditorFeature<C>`, `FeatureContext`, `ToolbarItem`, `MenuItem`, …), `commandItem` / `mergeToolbarGroups`, and the block-conversion engine for own features (`ConversionProvider`, `ConvertTarget` with its `custom` member for host blocks, `createConverter`, `convertCoreBlocks`, `finishConversion`) |
|
|
112
|
-
| `@ecsplico/editor/core/schema` | Vue-free base schema: `coreSchemaExtensions()`, `EMPTY_EDITOR_CONTENT`, `StrikeX`, `BlockId` helpers (`BLOCK_ID_TYPES`, `blockIdOf`, `findBlockById`, `assignBlockIds`), `NodeFlags` (copies the node flags `editorBlockContainer`, `editorChrome` and `editorBlock` onto the node spec; `editorBlock: true` gives an own node block IDs), `isEditorBlock`, `isBlockContainer`, `isChromeNode`, the ability vocabulary (`ABILITY`, `ROOT_ABILITIES`) |
|
|
113
|
-
| `@ecsplico/editor/schema/simple` | Vue-free `simpleSchemaExtensions()` for servers and validators |
|
|
114
|
-
| `@ecsplico/editor/settings` | `EditorSettings`, `EDITOR_SETTINGS_VERSION`, `EDITOR_SETTINGS_DEFAULTS`, `editorSettingsSchema`, `parseEditorSettings`, inert value constants (`MODEL_SLOTS`, `STRUCTURE_MODES`, `TREE_ROOTS`, `KIND_ICON_VISIBILITIES`, `DRAG_HANDLE_VISIBILITIES`, `AI_LANGUAGES`, `AUTHOR_COLOR_STYLES`, `COMMENTS_LAYOUTS`, …) |
|
|
115
|
-
| `@ecsplico/editor/outline`, `/outline/vue`, `/outline/react` | `/vue` and `/react`: `EditorOutline`; framework-free: `headingOutline`, `revealBlockInEditor`, `HeadingOutlineNode` (imports no tree and no composite code) |
|
|
116
|
-
| `@ecsplico/editor/tree`, `/tree/vue`, `/tree/react`, `/tree/types` | File browser. `/vue` and `/react`: `DocumentTree` (Vue: props `store`, `editor`, `v-model:selectedFolder`, slot `document-actions`; React: props `store`, `editor`, `selectedFolder`/`onSelectedFolderChange` (uncontrolled when omitted), `documentActions`, `className`; needs `EditorContextProvider` and a mounted `Toaster`), `useTreeView` (Vue: `nodeFilters`/`expanded` as refs; React: as values); framework-free: `DocumentStore` (store-based: `tree`, `documents`, `activeId` are `ReadonlyStore`s plus the host's operations), `createTreeView`, `treeView(context)` (the per-app view state: node filters, expanded folders), `TreeViewModel`, `NodeFilters`, `TreeFolder`, `DocumentSummary`; `/vue` also `useStoreRef` and `storeFromRef` (adapters from Vue refs to the store shape). Depends on core, outline, composites and media; see the [integration guide](./docs/integration.md#10-the-file-browser-and-documentstore). `/tree/types` has the `TreeFolder`/`DocumentSummary` types alone, for servers whose typecheck has no DOM |
|
|
117
|
-
| `@ecsplico/editor/media`, `/media/vue`, `/media/react`, `/media/schema` | `/vue` and `/react`: `mediaFeature`, `useFileImport`, `AudioRecorderModal`, `useAudioRecorder`; framework-free: `mediaFeatureCore`, `fileImport`, `createAudioRecorder`, `pickFiles`, `openAudioRecorder`, `postUpload`, `mediaSchemaExtensions()`, `MEDIA_TYPES`, `MAX_MEDIA_BYTES`, asset helpers |
|
|
118
|
-
| `@ecsplico/editor/mentions`, `/mentions/schema` | `mentionsFeature`, `mentionSuggestion`, `tagSuggestion`; Vue-free: `mentionsSchemaExtensions()`, `MentionNode`, `TagNode`, `mentionsFromText`, `tagsFromText`, `normalizeTagName` |
|
|
119
|
-
| `@ecsplico/editor/tables`, `/tables/schema` | `tablesFeature()` (GFM tables and task lists: the nodes, toolbar group `table` with insert 3×3, add/delete row, add/delete column, delete table, slash entries `table.insert` and `task.insert`; no components, so it fits both framework layers); Vue-free: `tablesSchemaExtensions()` (also part of `/schema/simple` and `/schema/advanced`) |
|
|
120
|
-
| `@ecsplico/editor/markdown`, `/markdown/vue`, `/markdown/react` | Framework-free: `splitFrontmatter(text)` / `joinFrontmatter(frontmatter, body)` (YAML block at offset 0 only, kept verbatim), `markdownToContent(editor, body, { policy? }): { content, diagnostics }` (policy `{ allowHtml?, allowDataUrls? }`: raw HTML, links and media with unsafe URLs are dropped and reported as `MarkdownDiagnostic`s — `raw-html`, `unsafe-url`, `unknown-fence` (info), `unclosed-fence` and `invalid-fence-meta` (errors); `hasFatalDiagnostics`), `contentToMarkdown(editor)`, `MarkdownClipboard.configure({ policy })` (an extension: pastes `text/markdown` and plain text with block syntax as blocks, sanitizes pasted HTML, copies and cuts as `text/markdown` next to `text/html` and `text/plain`), `createSourceMode({ getEditor, toMarkdown?, fromMarkdown?, policy? }): SourceMode` (`state` store `{ mode: 'visual' \| 'source', source, diagnostics }`, `enter()`, `edit(text)`, `commit(): boolean` — false with the editor untouched on a fatal diagnostic or a document the schema rejects —, `cancel()`). Unknown `::: kind` fences are `OpaqueFence` nodes (in `coreSchemaExtensions()`) that are written back byte for byte; kinds a composite feature registers parse first. Vue: `MarkdownSurface` (`v-model` is the Markdown string, frontmatter included; props, emits and slots of `EditorSurface` forwarded; an incoming value equal to the last emitted one is ignored; prop `policy` (also configures the `MarkdownClipboard` it installs), prop `sourceMode` (a `SourceMode`: while its state is `source` the surface shows the draft in a text area with the diagnostics of a rejected commit and Apply/Cancel, `sourceLabels` for their texts), event `diagnostics`). React: `MarkdownSurface` (`value` / `onChange` / `onFrontmatterChange` / `onDiagnostics`, prop `policy` (also configures the installed `MarkdownClipboard`), the `EditorSurface` props forwarded, same semantics; no source view). Neither imports CodeMirror |
|
|
121
|
-
| `@ecsplico/editor/code`, `/code/vue`, `/code/react` | CodeMirror 6 on a string, themed by the shared `--sk-*` tokens (`styles/tokens.css`; fallbacks are the token defaults). Framework-free: `createCodeEditor({ parent, doc?, readOnly?, wordWrap?, language?, onSaveShortcut?, onChange? })`, `setReadOnly`, `setWordWrap`, `setLanguage(view, support)`, `loadLanguage(view, id)`, `setDocument(view, text)` (a host text, not an edit), `registerLanguage(id, loader, { core? })` / `resolveLanguage(id)` / `isCoreLang(id)` (language packs are the host's: register the `@codemirror/lang-*` packs you depend on; `jsonl` is built in), `formatJsonInEditor(view)`, `formatJsonText`, `jsonlLanguage`, `kindOf(path, mime?)` (`'markdown' \| 'code' \| 'binary'`), `languageOf(path)`. `/code/vue`: `CodeSurface` (`v-model` string, `editable`, `language`, `wordWrap`; emits `update:modelValue`, `save` on Mod-S, `ready(view)`). `/code/react`: `CodeSurface` (`value`, `onChange`, `onSave`, `onReady`, same flags). No ProseMirror or TipTap is reachable from these entries |
|
|
122
|
-
| `@ecsplico/editor/document/vue`, `/document/react` | `DocumentSurface`: `MarkdownSurface` for `kindOf(path, mime) === 'markdown'` (props `markdown`: the Markdown surface's own props, `preset` at least), `CodeSurface` for text (language from `languageOf(path)` unless `language` is given), a `binary` slot (Vue) / `binary(path)` render prop (React) otherwise. `ready` carries `{ kind: 'markdown', editor }` or `{ kind: 'code', view }`. These entries reach both editors; use `/markdown/*` or `/code/*` alone to keep one out of a bundle |
|
|
123
|
-
| `@ecsplico/editor/transcript`, `/transcript/vue`, `/transcript/react`, `/transcript/schema` | `/vue` and `/react`: `transcriptFeature`, `TranscriptSegmentView`; framework-free: `transcriptFeatureCore`, `transcriptSegment`, `speakerConversions`, `segmentSpeakerLines`, `transcriptSchemaExtensions()`, `speakerParagraphsToSegments`, `lastSpeaker`, `speakersIn` |
|
|
124
|
-
| `@ecsplico/editor/authors`, `/authors/vue`, `/authors/react`, `/authors/schema` | `/vue` and `/react`: `authorsFeature`, `AuthorColorsPanel`, `AuthorColorsButton`, `SettingsAuthorsTab`; framework-free: `authorsFeatureCore`, `currentAuthor`, `AuthorAttribution`, `authorsSchemaExtensions()`, `AuthorMark`, `documentAuthors`, `AuthorIdentity`, `AUTHOR_COLOR_STYLES`, `AuthorColorStyle` |
|
|
125
|
-
| `@ecsplico/editor/themes`, `/themes/vue`, `/themes/react`, `/themes/schema` | `/vue` and `/react`: `themesFeature()` (site-wide Obsidian themes: its `setup` hook starts the theme runtime and returns its teardown, its `appearance` settings tab picks the theme), `SettingsAppearanceTab`; framework-free: `themesFeatureCore`, `startObsidianTheme(ctx)` (reference-counted per app, returns the release), `scopeThemeCss`, `THEME_SCOPE_CLASS`; Vue-free schema: `ThemeRecord`, `ThemeManifest`, `themeManifestSchema`, `THEME_ID`, `MAX_THEME_BYTES`. Needs an adapter with `listThemes`/`loadTheme`; see the [usage guide](./docs/usage.md#themes-obsidian) |
|
|
126
|
-
| `@ecsplico/editor/comments`, `/comments/vue`, `/comments/react`, `/comments/schema` | `/vue` and `/react`: `commentsFeature` (requires `collab`), `useComments`, `CommentsMargin`, `CommentsPopover`, `CommentsListMenu`, `CommentThreadView`, `CommentComposer`, `CommentBubble`, `SettingsCommentsTab` (`/vue` also the type `CommentsStore`); framework-free: `commentsFeatureCore`, `createCommentsModel`, `Comments` plugin helpers, `commentsSchemaExtensions()`, `CommentMark`, `CommentThread`, `CommentReply`, `COMMENT_LIMITS`, `COMMENTS_LAYOUTS`, `CommentsLayout`, and the margin's layout (the active thread pinned to its text's line, the others one-line cards out of its way): `layoutMargin(entries, activeId, { gap, minTop })` (with `MarginEntry`, `MarginLayout`, `MARGIN_GAP`), `marginCards` (with `MarginCard`, `DRAFT_CARD`; an orphaned thread sits at its deletion point, `CommentsSnapshot.orphanAt`, which host models may omit), `createMarginController` (with `MarginController`, `MarginSource`, `MarginState`: measuring and scheduling for both `CommentsMargin`s) |
|
|
127
|
-
| `@ecsplico/editor/composites/vue`, `/composites/react` | `compositeFeature()` (Vue: Nuxt UI, React: shadcn), the host-placed `CompositeTable` and `CompositeInspector`, `SettingsEditingTab`, `CompositeChrome`, `CompositeDetails`, `CompositeView` and editors, `useCompositeRows`, `useCompositeAnchors` |
|
|
128
|
-
| `@ecsplico/editor/composites`, `/composites/schema` | Framework-free: `compositeFeatureCore`, `Composite`, `defaultCompositeKinds`, `compositeKind`, `kindAccepts` (the kinds' accepted children, `CompositeKind.accepts`), `AcceptedChildren` (the editor extension that enforces them; registered by `compositeFeatureCore`), `compositeOutline`, `moveBlockInto` (returns whether the document changed), `moveIntoVerdict(editor, id, targetId, t)` (with `MoveVerdict`: `{ ok: true }` or `{ ok: false, reason }` in the language of `t`), `canMoveBlockInto` (`moveIntoVerdict(...).ok`), `headingsMarkdown`, `documentCompositeMarkdown`, `Structure`, `createCompositeRows`, `createCompositeInspector`, `compositeFieldText`, `observeCompositeAnchors`, `compositeRows`, `setCompositeMetaField`, `setCompositeTags`, `setCompositeDescription`, `compositeDescriptionText`, `compositeSchemaExtensions()`, `compositeJSON`, `blocksFromMarkdown`, `splitCompositeFences`, `migrateLegacyContent`, conversions and heading↔composite transforms |
|
|
129
|
-
| `@ecsplico/editor/ai`, `/ai/protocol` | Framework-free: `aiFeatureCore`, `modelProfiles(app)`, `createAiAssistant`, `createDocumentChat`, `createAiSelectionFlow` (with `AI_SELECTION_MENU_KEY`), `createAgentOpReview({ notify, t })` (host-driven agent edit review), `notifyAiRateLimited(notify, t)`, review/apply helpers (`startAiReview`, `applyAiResult`, …) and the protocol (`AI_TASKS`, `ModelRef`, `AGENT_OP_TYPES`, `AGENT_OP_OUTCOMES`, `CHAT_LIMITS`, …), importable alone from `/ai/protocol`; the model-facing agent texts (`checkAgentOps`, `agentShownMessage`, `agentFeedbackText`, `agentRetryMessage`) take a `locale: 'de' \| 'en'` option (default `de`), and `agentRetryMessage(problems, scoped, { locale, tool })` names the `tool` the model must call again (default `edit_document`). The `[id]` line format of the chat's document text has one owner there, `block-lines`: writer helpers (`blockLine`, `singleBlockLine`, `nestedLinePrefix`, `quoteLinePrefix`, `listLinePrefix`, `continuedLinePrefix`, `compositeChromePart`, `compositeLineHeader`, `compositeLineClose`, `TRUNCATED_LINE`), the reader `readBlockLines` (the block ids and which blocks lie inside which; lines in fenced code are not block lines; type `BlockLines`), the echo strippers `stripBlockLineEcho` and `stripListMarkerEcho`, and the (German, model-facing) prompt texts `BLOCK_LINES_LABEL`, `BLOCK_LINE_INTRO`, `BLOCK_LINE_MARKERS`, `BLOCK_LINE_LIST_TEXT`, `BLOCK_LINE_HOST_TEXT`, `BLOCK_LINE_COMPOSITE_TEXT`, `BLOCK_LINE_ECHO_TEXT`, `BLOCK_LINE_IDS_HINT` with the example (`BLOCK_LINE_EXAMPLE`, `BLOCK_LINE_EXAMPLE_ID`, `BLOCK_LINE_EXAMPLE_TEXT`) |
|
|
130
|
-
| `@ecsplico/editor/ai/vue`, `/ai/react` | `aiFeature()`, `AiSidebar`, `ModelQuickSwitch`, `AiReviewBar`, `AiSelectionMenu`, `SettingsAiTab`, `SettingsModelProfiles`; `/ai/vue` also `useAiAssistant`, `useDocumentChat`, `useModelProfiles` (thin hooks over the models) |
|
|
131
|
-
| `@ecsplico/editor/integrations/composite-ai` | Framework-free: `compositeAiFeature` (requires `composites`, `ai`, `media`), `fillComposite`, `summarizeComposite`, `transcribeDocument`, `compositeSourceText`, `mediaAssetOf` |
|
|
132
|
-
| `@ecsplico/editor/integrations/composite-media` | Framework-free: `compositeMediaFeature` (requires `composites`, `media`): imported files become `document` composites |
|
|
133
|
-
| `@ecsplico/editor/integrations/transcript-ai`, `/transcript-ai/protocol` | Framework-free: `transcriptAiFeature` (requires `transcript`, `ai`), `createTranscriptCleanup`, `hasTranscriptSegments`; server contract: `TRANSCRIPT_CLEANUP_LIMITS`, `transcriptCleanupRequestSchema`, `transcriptCleanupMessages`, `transcriptCleanupChunks`, `parseTranscriptCleanup` |
|
|
134
|
-
| `@ecsplico/editor/collab`, `/collab/vue`, `/collab/react` | Framework-free: `collabFeatureCore(ui?)` (Yjs `Collaboration`/`CollaborationCaret`, active only with a `collaboration` session on the surface), `yjsAnchorResolver`; `/vue` and `/react`: `collabFeature()` (the Vue one adds the `@tiptap/vue-3` state-sync workaround, the React one needs none) |
|
|
135
|
-
| `@ecsplico/editor/block-ui`, `/block-ui/vue`, `/block-ui/react` | `/vue` and `/react`: `blockUiFeature()`, `BlockUi`, `BlockActionsOverlay`; framework-free: `blockUiFeatureCore`, `blockActionsFor`, `effectiveTarget`, `BLOCK_CORNER_ATTR` and `blockCornerOf` (a node view marks its own top-right icons with `data-block-corner`; the hover bar docks left of them): drag handle, hover targeting and block actions (opt-in; the simple editor never includes it) |
|
|
136
|
-
| `@ecsplico/editor/schema/advanced` | Vue-free `advancedSchemaExtensions()`: the advanced schema for servers, validators and migrations |
|
|
137
|
-
| `@ecsplico/editor/server`, `/server/handlers`, `/server/node`, `/nuxt` | Server side without a web framework: `createCollabServer`, `createAiModels`, `createRateLimiter`, `EditorAdapter`, one request handler per route (`/server/handlers`), `listenCollab` for a plain Node script (`/server/node`); the Nitro registry `setEditorAdapter`, `forgetCollabDocument`, `liveContent`, `collabStats`; the Nuxt module (config key `tiptapEditor`) wraps the same core. See the [integration guide](./docs/integration.md) |
|
|
138
|
-
| `@ecsplico/editor/styles/core.css` (required), `/composites.css`, `/media.css`, `/mentions.css`, `/tables.css`, `/authors.css`, `/comments.css`, `/transcript.css`, `/ai.css`, `/collab.css`, `/block-ui.css`, `/themes.css` | Feature CSS (import after Tailwind, Nuxt UI (Vue) or `ui-vars.css` (React) and `core.css`; `themes.css` after the feature sheets). The Nuxt module adds all of them itself |
|
|
139
|
-
|
|
140
|
-
Nuxt apps use the same entries; the Nuxt client plugin (`src/nuxt/runtime/plugins/editor-context-nuxt-ui.client.ts`) installs the editor context with account-synced settings.
|
|
141
|
-
|
|
142
|
-
## Presets and features
|
|
143
|
-
|
|
144
|
-
| Preset | Features | Backend / Yjs | Bundle isolation (`check:editor-entries`) |
|
|
145
|
-
|---|---|---|---|
|
|
146
|
-
| `simple` (`SimpleEditor`, `simpleEditor()`) | `core` | none | no feature, integration, AI SDK, Yjs, y-tiptap, Hocuspocus, Nuxt or server modules in the emitted chunks |
|
|
147
|
-
| React `SimpleEditor` + `EditorToolbar` (`./react/simple`, `./react`) | `core` | none | no `vue`, `@vue`, `@tiptap/vue-3`, Nuxt UI or Vue-layer module in the emitted chunks (`react-simple` fixture); the headless core (`core-headless` fixture) contains no Vue, React or layer module at all |
|
|
148
|
-
| `core` + `mediaFeature()` | `core`, `media` | uploads only (or a host `upload` function) | no composite, AI, Yjs, Nuxt or sibling-feature modules |
|
|
149
|
-
| `core` + `mentionsFeature()` | `core`, `mentions` | built-in `@`/`#` lists only (or host lists) | same |
|
|
150
|
-
| `core` + `transcriptFeature()` | `core`, `transcript` | none | same |
|
|
151
|
-
| `core` + `authorsFeature()` | `core`, `authors` | none | same |
|
|
152
|
-
| `core` + `themesFeature()` | `core`, `themes` | `/api/editor/themes[/:id]` (adapter `listThemes`/`loadTheme`) | no composite, AI, media, mentions, transcript, authors, comments, collaboration, block-UI, integration, Yjs or Nuxt modules |
|
|
153
|
-
| `core` + `collabFeature()` + `commentsFeature()` | `core`, `collab`, `comments` | `/collab/:id` websocket (comments live in the Y.Doc) | no composite, AI, media, mentions, transcript, authors, block-UI, integration or Nuxt modules; Yjs is bundled |
|
|
154
|
-
| `core` + `aiFeature()` | `core`, `ai` | `/api/ai/{models,generate,chat,complete}` (see the usage guide) | no composite, transcript, media, mentions, collaboration, integration, Yjs or Nuxt modules |
|
|
155
|
-
| `core` + `media` + `composites` + `aiFeature()` + `compositeAiFeature()` | `core`, `media`, `composites`, `ai`, `composite-ai` | AI endpoints plus `/api/ai/transcribe` | no transcript, mentions, collaboration, other integration, Yjs or Nuxt modules |
|
|
156
|
-
| `core` + `transcriptFeature()` + `aiFeature()` + `transcriptAiFeature()` | `core`, `transcript`, `ai`, `transcript-ai` | AI endpoints plus `/api/ai/transcript-cleanup` | no composites, media, mentions, collaboration, other integration, Yjs or Nuxt modules |
|
|
157
|
-
| `core` + `collabFeature()` | `core`, `collab` | `/collab/:id` websocket (Nuxt module) or any Hocuspocus server on the advanced schema | no composite, AI, media, mentions, block-UI, integration or Nuxt modules; Yjs is bundled |
|
|
158
|
-
| `core` + `blockUiFeature()` | `core`, `block-ui` | none | no composite, AI, media, mentions, collab-feature or Nuxt modules (the drag handle's upstream package bundles Yjs support code) |
|
|
159
|
-
| `core` + `compositeFeature()` | `core`, `composites` | none | no AI, media, transcript, mentions, collaboration, block-UI, integration, Yjs or Nuxt modules |
|
|
160
|
-
| `core` + `media` + `composites` + `compositeMediaFeature()` | `core`, `media`, `composites`, `composite-media` | uploads only | no AI, transcript, mentions, collaboration, other integration, Yjs or Nuxt modules |
|
|
161
|
-
| `DocumentTree` (`./tree/vue` or `./tree/react`) beside `core` + `media` + `composites` | tree, `core`, `media`, `composites` | the host's `DocumentStore` | no AI, transcript, mentions, collaboration, block-UI, integration, Yjs or Nuxt modules; the `simple` bundle never contains the tree; the React tree contains no Vue module (`tree-react` fixture), the framework-free `./tree` no Vue and no React (`headless-tree` fixture) |
|
|
162
|
-
| `advancedEditor()` / `AdvancedEditor` (`./vue/advanced`) | every feature (including `themes`) and integration, Vue bindings | `/collab/:id`, AI endpoints, assets, users/tags, themes (Nuxt module plus a host adapter, or a host server) | requires all feature and integration modules; no React, `sonner`, Nuxt, `nitropack`, `h3`, vue-router or server code in the browser bundle (`advanced` fixture) |
|
|
163
|
-
| `advancedEditor()` / `AdvancedEditor` (`./react/advanced`) | every feature (including `themes`) and integration, React bindings | the same endpoints, through the Nuxt host or a host server (`examples/react-advanced` proxies `/api` and `/collab` to the Nuxt app) | requires all feature and integration modules; no `vue`, `@vue`, `@tiptap/vue-3`, Nuxt UI, Vue-layer or `.vue` module, no Nuxt or server code (`advanced-react` fixture) |
|
|
164
|
-
| Any feature on one layer (`<x>/vue`, `<x>/react`, `<x>` alone) | `core` + that feature | as listed above | `<x>-react` fixtures contain no Vue or Nuxt UI module; the Vue fixtures no React, `react-dom` or `sonner`; the framework-free `headless-<x>` fixtures neither framework |
|
|
165
|
-
|
|
166
|
-
Settings are stored as one inert, versioned JSON object shared by all editors of an app (`EditorSettings`); a simple editor installs no feature that reads the non-core parts.
|
|
167
|
-
|
|
168
|
-
## CSS and UI-provider requirements
|
|
169
|
-
|
|
170
|
-
- Design tokens: `@ecsplico/editor/styles/tokens.css` declares the shared `--sk-*` variables (`--sk-bg`, `--sk-fg`, `--sk-muted`, `--sk-border`, `--sk-primary`, `--sk-primary-fg`, `--sk-success`, `--sk-warning`, `--sk-danger`, `--sk-radius`, `--sk-font`) with light defaults under `:where(:root)` and dark values under `:where(.dark)`. Every feature stylesheet reads them; a UI kit maps them onto its own variables (Nuxt UI: `vue/kit/nuxt-ui.css`, React/shadcn: `react/styles/ui-vars.css`), a host may override them once.
|
|
171
|
-
|
|
172
|
-
- Vue UI kit: the Vue binding is built on Nuxt UI. The chrome renders through the kit handed to `createEditor({ kit })`; `kit` is optional and defaults to `nuxtUiKit()` (`@ecsplico/editor/vue/kit/nuxt-ui`, needs `@nuxt/ui`, stylesheet `@ecsplico/editor/vue/kit/nuxt-ui.css`). `@ecsplico/editor/vue/kit` holds the `VueUiKit` contract and `useUiKit()`; pass your own `VueUiKit` only to render the chrome with another library. Only the `nuxt-ui` kit entry imports `@nuxt/ui`. The Nuxt module has no `kit` option: it always adds `vue/kit/nuxt-ui.css`, patches Nuxt UI's `ui.css` so Tailwind scans the package (`@nuxt/ui` must be registered before the module) and installs the Nuxt UI context plugin.
|
|
173
|
-
|
|
174
|
-
- Import the core CSS **after** Tailwind and Nuxt UI, and let Tailwind see the library's classes:
|
|
175
|
-
|
|
176
|
-
```css
|
|
177
|
-
@import "tailwindcss";
|
|
178
|
-
@import "@nuxt/ui";
|
|
179
|
-
@import "@ecsplico/editor/styles/core.css";
|
|
180
|
-
@source "../../../packages/editor/src"; /* relative path from this CSS file to the package's src */
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
The Nuxt module needs none of this: it adds `core.css` and every feature sheet to `css` (`themes.css` last) and appends the package to Tailwind's `@source` list. In plain Vue also import the sheet of each feature you use, e.g. `@ecsplico/editor/styles/media.css`, after `core.css`.
|
|
184
|
-
|
|
185
|
-
- Plain Vue: Vite plugins `vue()` and `ui({ router: false })` from `@nuxt/ui/vite`, `app.use(ui)` with `import ui from '@nuxt/ui/vue-plugin'`, and the editor context `app.use(createEditor())` (`createEditor` from `@ecsplico/editor/vue`). Wrap the page in `<UApp>` (overlays, toasts, tooltips).
|
|
186
|
-
- React: Vite with `@vitejs/plugin-react` and `@tailwindcss/vite`. The CSS needs Tailwind, `tw-animate-css`, `@ecsplico/editor/react/styles/ui-vars.css`, `core.css` (plus the sheet of each feature you use, e.g. `mentions.css`), the shadcn theme block (`:root`/`.dark` tokens and `@theme inline`; `bunx shadcn@latest init` generates it) and `@source` for the library's `src/react`. For the advanced editor import `@ecsplico/editor/react/styles/advanced.css` instead of those three library sheets: it bundles `ui-vars.css`, `core.css`, every feature sheet and `themes.css` (last). Preload the icons with `addCollection(lucide)` from `@iconify/react`, wrap the tree in `<EditorContextProvider context={createEditorContext({ notify: reactNotifier })}>` and mount `<Toaster />` (sonner, from `@ecsplico/editor/react`) once so notices show up; see the [usage guide](./docs/usage.md#simple-editor-in-react), [Advanced editor in React](./docs/usage.md#advanced-editor-in-react), [`examples/react-simple`](../../examples/react-simple) and [`examples/react-advanced`](../../examples/react-advanced).
|
|
187
|
-
- Icons: Nuxt UI resolves `i-lucide-*` names at build time. A workspace library lies outside the Vite root that Nuxt UI scans, so list its icons for the client bundle (see how `examples/vue-simple/vite.config.ts` collects them) to avoid Iconify API requests at runtime.
|
|
188
|
-
- The editor context is mandatory: Vue `EditorSurface`, `SimpleEditor` and `EditorToolbar` throw a descriptive error without `createEditor()`, the React components without `<EditorContextProvider>`. Both wrap the framework-free `createEditorContext()` from `@ecsplico/editor/core`; the host owns the React context and may call `context.dispose()` itself.
|
|
189
|
-
|
|
190
|
-
## Runnable examples
|
|
191
|
-
|
|
192
|
-
- **Plain Vue, no backend:** [`examples/vue-simple`](../../examples/vue-simple) — `SimpleEditor` with a sibling toolbar and heading outline, JSON `v-model`, read-only toggle, external replacement, host `/datum` command and an own block, the „Hinweis“ callout, added through the `extensions` and `slashCommands` props (`/hinweis`, `Mod-Shift-h`, tone select, `!!!` Markdown form). A sample picker loads five demo documents (Start, Formatierung, Gliederung, Hinweise, and „Ungültig (Baustein-JSON)“, which the simple schema rejects through `contentError`); next to the editor the JSON (with block IDs) and the Markdown of the document are shown.
|
|
193
|
-
- **Plain React, no backend:** [`examples/react-simple`](../../examples/react-simple) — the same document picker, read-only toggle and JSON/Markdown panes with the React layer: `EditorToolbar` beside `EditorSurface` over `defineEditor({ features: [coreFeature(), mentionsFeature()] })`, the host `/` commands, `@` mentions from `metadata`, and rejected content through `onContentError`. Vite, Tailwind 4 and shadcn tokens, no Nuxt UI.
|
|
194
|
-
- **Advanced, Nuxt:** this repository's application (`bun run dev`, port 3031) — collaborative documents under switchable demo users (no login: `server/middleware/demo-session.ts` signs every API request into a demo user, `server/api/auth/switch.post.ts` switches it; `app/pages/documents/[id].vue`), the file drawer with `DocumentTree` and a host `DocumentStore` (`app/components/AppDocumentTree.vue`, `app/composables/useDocumentStore.ts`), and a playground with two independent editors, switched in the page header together with the shown editor's sample (`app/pages/playground.vue`, panes in `app/components/PlaygroundPane.vue`, each opening its settings in the `EditorSettingsModal` popup). Editor A is an `AdvancedEditor` with host props (metadata, abilities, a hover action, a `/` command, an own composite kind) on the „Überblick“, „Gliederung“, „Transkript“ and „Leer“ samples; Editor B is an `EditorSurface` on `advancedEditor().features` plus an own feature, the callout (`app/editor/callout/`: toolbar button, `/hinweis`, a tone menu on hover, „Umwandeln in Hinweis“, Markdown form), with a „Markdown einfügen“ button. The „Darstellung“ settings tab switches the whole site between „Standard“ and the seven builtin Obsidian themes (`server/themes/`: Nord, Things, Minimal, Catppuccin, Border, Blue Topaz, Tokyo Night) or an uploaded one, served by the adapter in `server/plugins/editor-adapter.ts`. Walkthrough: [Advanced Nuxt example](./docs/usage.md#advanced-nuxt-example). How to add a block of your own: the [extending guide](./docs/extending.md).
|
|
195
|
-
- **Advanced, React:** [`examples/react-advanced`](../../examples/react-advanced) (`bun run --cwd examples/react-advanced dev`, port 3043; needs the Nuxt app running, Vite proxies `/api` and `/collab` to it) — the React counterpart of the Nuxt document page: a document picker over the host's `/api/documents`, a collaborative `AdvancedEditor` over `HocuspocusProvider` as the demo session's user, `EditorToolbar`, `EditorSettingsModal`, `CommentsMargin`, `CompositeTable`/`CompositeInspector`, `EditorOutline`, `AiSidebar`, `DocumentTree` over an `/api` adapter of `DocumentStore`, and `Toaster`. Vite, Tailwind 4 and shadcn tokens, no Nuxt UI, no Vue.
|
|
196
|
-
|
|
197
|
-
## Commands
|
|
198
|
-
|
|
199
|
-
From the repository root, after `bun install`:
|
|
200
|
-
|
|
201
|
-
```sh
|
|
202
|
-
bun run dev # Nuxt demo app, http://localhost:3031
|
|
203
|
-
bun run typecheck # nuxt typecheck of the demo app
|
|
204
|
-
bun run --cwd examples/vue-simple dev # http://localhost:3040
|
|
205
|
-
bun run --cwd examples/vue-simple build # prepares the Nuxt UI theme aliases the library typecheck needs
|
|
206
|
-
bun run --cwd examples/vue-simple typecheck
|
|
207
|
-
bun run --cwd examples/react-simple dev # http://localhost:3041
|
|
208
|
-
bun run --cwd examples/react-simple typecheck
|
|
209
|
-
bun run --cwd examples/react-advanced dev # http://localhost:3043, needs `bun run dev` (Nuxt host, port 3031)
|
|
210
|
-
bun run --cwd examples/react-advanced typecheck
|
|
211
|
-
bun run --cwd examples/vue-markdown dev # http://localhost:3045, MarkdownSurface with frontmatter, tables and source mode
|
|
212
|
-
bun run typecheck:editor # vue-tsc --noEmit -p packages/editor/tsconfig.json (no Nuxt globals)
|
|
213
|
-
bun run check:editor-entries # production build per fixture, module-graph isolation rules
|
|
214
|
-
bun run check:editor-markdown-clipboard # MarkdownClipboard paste/copy cases (HTML, Markdown, plain text, data-URL opt-in) in happy-dom
|
|
215
|
-
bun run check:editor-composition # defineEditor rejects missing `requires`; accepted compositions; one formatAiResult contributor
|
|
216
|
-
bun run test:editor # bun test over packages/editor/test: framework-free models on a mounted editor (happy-dom)
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
On a clean checkout run the example build once before `typecheck:editor`.
|
|
220
|
-
|
|
221
|
-
### Bundle isolation proof
|
|
101
|
+
## Documentation
|
|
222
102
|
|
|
223
|
-
|
|
103
|
+
The documentation lives at **https://skaile-ai.github.io/skaile-editor/** (the package itself no longer ships guides):
|
|
224
104
|
|
|
225
|
-
|
|
105
|
+
- [Getting started](https://skaile-ai.github.io/skaile-editor/getting-started/introduction): what the package is, installation, quick starts for Nuxt, plain Vue and React, glossary.
|
|
106
|
+
- [Tutorial](https://skaile-ai.github.io/skaile-editor/tutorial/overview): build one editor step by step, including an own block, the backend, AI and the React surface.
|
|
107
|
+
- [Guides](https://skaile-ai.github.io/skaile-editor/guides/composition): feature composition, Nuxt module, `EditorPorts`, collaboration, AI, themes, composites, file browser, production, storage adapters, migration.
|
|
108
|
+
- [Reference](https://skaile-ai.github.io/skaile-editor/reference/exports): every public export, presets and features, the feature contract, CSS and UI-provider requirements, dependency rules, commands, changelog.
|
|
109
|
+
- [AI agents](https://skaile-ai.github.io/skaile-editor/ai-agents): how coding agents read these docs, integrate and extend the editor, invariants and verification.
|
|
226
110
|
|
|
227
|
-
|
|
111
|
+
Machine-readable entry points: [`llms.txt`](https://skaile-ai.github.io/skaile-editor/llms.txt), [`llms-full.txt`](https://skaile-ai.github.io/skaile-editor/llms-full.txt), and an installable Agent Skill:
|
|
228
112
|
|
|
229
|
-
|
|
113
|
+
```sh
|
|
114
|
+
npx skills add https://skaile-ai.github.io/skaile-editor
|
|
115
|
+
```
|
|
230
116
|
|
|
231
|
-
|
|
232
|
-
- [Integration guide](./docs/integration.md): feature composition and the per-feature entries, the UI binding contract, notices and `setup` teardown, browser versus schema/server entries, settings persistence and app lifetime, Nuxt module, `EditorAdapter`, routes and authentication, storage ownership, AI secrets and env names, collaboration on the client, block UI, the Vue-free advanced schema, the file browser and `DocumentStore`, production, migration from `#tiptap-editor` and the dependency rules.
|
|
233
|
-
- [Extending guide](./docs/extending.md): add a block of your own, with the runnable „Hinweis“ callout as the example — through the `extensions`/`slashCommands` props or as a full feature (toolbar, `/` command, hover action, „Umwandeln in …“, Markdown form), what the `editorBlock` flag and custom abilities do, and what collaboration servers and AI need.
|
|
234
|
-
- [Usage guide](./docs/usage.md): plain Vue setup and the `SimpleEditor`, the React setup (`EditorContextProvider`, `EditorSurface`, `EditorToolbar`, `SimpleEditor`, `Toaster`), media/mentions/transcript, authors and comments, themes, composites and the settings UI, file import, AI and its integrations, the file browser, the advanced editor in React (`./react/advanced`), and the Advanced Nuxt example (a walkthrough of this repository's app).
|
|
117
|
+
Runnable examples live in the repository: [`examples/`](https://github.com/skaile-ai/skaile-editor/tree/main/examples) and the Nuxt app (`bun run dev`, port 3056). To work on the documentation site from a checkout of the repository, run `bun run docs:dev` (development server) or `bun run docs:build` (static build); see [`docs/README.md`](https://github.com/skaile-ai/skaile-editor/blob/main/docs/README.md).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PortableAnchor } from "../anchors.js";
|
|
2
|
-
import { EditorDb } from "../drizzle.js";
|
|
3
2
|
import { CommentStore } from "./types.js";
|
|
3
|
+
import { EditorDb } from "../drizzle.js";
|
|
4
4
|
import { SQLiteColumn } from "drizzle-orm/sqlite-core";
|
|
5
5
|
//#region src/adapters/comments/drizzle.d.ts
|
|
6
6
|
declare const COMMENT_TABLES: {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Annotation, Comment, CommentThread, Discussion, NewThread, ThreadStatus } from "./types.js";
|
|
2
|
+
//#region src/adapters/comments/record.d.ts
|
|
3
|
+
export declare const emptyDiscussion: () => Discussion;
|
|
4
|
+
export declare function createThread(record: Discussion, input: NewThread): {
|
|
5
|
+
annotation: Annotation;
|
|
6
|
+
thread: CommentThread;
|
|
7
|
+
};
|
|
8
|
+
export declare function addComment(record: Discussion, threadId: string, comment: Comment): CommentThread;
|
|
9
|
+
export declare function editComment(record: Discussion, threadId: string, commentId: string, body: string, editedAt: string): CommentThread;
|
|
10
|
+
export declare function removeComment(record: Discussion, threadId: string, commentId: string): CommentThread;
|
|
11
|
+
export declare function setThreadStatus(record: Discussion, threadId: string, status: ThreadStatus): CommentThread;
|
|
12
|
+
export declare function updateAnchor(record: Discussion, annotation: Annotation): Annotation;
|
|
13
|
+
export declare function removeThread(record: Discussion, threadId: string): void;
|
|
14
|
+
//#endregion
|
|
15
|
+
//# sourceMappingURL=record.d.ts.map
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { captureAnchor, capturePoint, mapAnchor, resolveAnchor } from "../anchors.js";
|
|
2
2
|
import { createStore } from "../../core/store.js";
|
|
3
3
|
import { releaseRanges, resolveRange } from "../../core/doc-anchors.js";
|
|
4
|
-
import { COMMENT_LIMITS } from "../../features/comments/schema.js";
|
|
5
4
|
import { cancelCommentDraft, commentsKey, setActiveComment, startCommentDraft } from "../../features/comments/comments-plugin.js";
|
|
5
|
+
import { COMMENT_LIMITS } from "../../features/comments/schema.js";
|
|
6
6
|
import { EMPTY_SNAPSHOT, NO_POSITIONS, NO_RANGES, sameOrphanAt, sameRange, sameRanges, sameUser } from "../../features/comments/snapshot-equality.js";
|
|
7
|
-
//#region src/adapters/comments/
|
|
7
|
+
//#region src/adapters/comments/rest-model.ts
|
|
8
8
|
/** Neutral colour of authors that stored no colour. */
|
|
9
9
|
const FALLBACK_COLOR = "#6b7280";
|
|
10
10
|
/** Characters of context that must agree for an orphan to be re-attached on load. */
|
|
@@ -533,4 +533,4 @@ function createRestCommentsModel(options) {
|
|
|
533
533
|
//#endregion
|
|
534
534
|
export { createRestCommentsModel };
|
|
535
535
|
|
|
536
|
-
//# sourceMappingURL=
|
|
536
|
+
//# sourceMappingURL=rest-model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rest-model.js","names":[],"sources":["../../../src/adapters/comments/rest-model.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { Transaction } from '@tiptap/pm/state'\nimport { type AuthorIdentity, createStore, releaseRanges, resolveRange } from '../../core'\nimport { cancelCommentDraft, COMMENT_LIMITS, type CommentReply, type CommentsModel, type CommentsSnapshot, type CommentThread as EditorThread, commentsKey, type DocRange, setActiveComment, startCommentDraft } from '../../features/comments'\nimport { EMPTY_SNAPSHOT, NO_POSITIONS, NO_RANGES, NO_THREADS, sameOrphanAt, sameRange, sameRanges, sameUser } from '../../features/comments/snapshot-equality'\nimport { captureAnchor, capturePoint, type PortableAnchor, resolveAnchor, mapAnchor } from '../anchors'\nimport type { Annotation, Comment, CommentAction, CommentThread, Discussion } from './types'\n\n// A `CommentsModel` for the editor's comments feature (`commentsFeature({ model })`) whose threads live behind a REST\n// endpoint (`handleCommentsRequest` serves it) instead of the document's Y.Doc. The text a thread hangs on is a\n// portable anchor (`../anchors`), not a `comment` mark: anchors are resolved against the document when the threads\n// load, follow every edit of the editor, and are written back to the endpoint when they moved. Not an entry of its own:\n// hosts get it as `createHttpBackend().comments(documentId, …)` (`../http`).\n\n/** The part of a `Response` the model reads; `globalThis.fetch` fits. */\nexport interface CommentsFetchResponse {\n ok: boolean\n status: number\n json(): Promise<unknown>\n}\n\nexport type CommentsFetch = (url: string, init?: { method?: string, headers?: Record<string, string>, body?: string }) => Promise<CommentsFetchResponse>\n\nexport interface RestCommentsModelOptions {\n /** How requests are sent: `globalThis.fetch`, or a wrapper that adds the base URL and credentials. */\n fetch: CommentsFetch\n /** The document the threads belong to. */\n documentId: string\n /** The document's comments endpoint (`GET` → `Discussion`, `POST` → `CommentAction`); default `/comments/<encoded documentId>`. */\n endpoint?: string\n /** Who writes: the author of new comments and the only one who may edit or delete them; `null` while nobody is signed in (no comments then). */\n user: AuthorIdentity | null | (() => AuthorIdentity | null)\n /** Whether the user may compose and change comments now; readers of a read-only document may be allowed. */\n canComment: boolean | (() => boolean)\n /** The editor the threads belong to; may return no editor yet or a destroyed one. */\n getEditor: () => Editor | undefined\n /** Milliseconds a changed anchor waits before it is written back (typing moves many); default 500. `idle()` writes at once. */\n persistDelay?: number\n /** Called with every failed request; the model reloads the threads afterwards, so the local state falls back to the server's. */\n onError?: (error: Error) => void\n}\n\nexport interface RestCommentsModel extends CommentsModel {\n /** Fetches the threads again and resolves their anchors against the current document. */\n reload(): Promise<void>\n /** Resolves once every change made so far has been sent (and the threads loaded, if a load was requested). */\n idle(): Promise<void>\n}\n\n/** Neutral colour of authors that stored no colour. */\nconst FALLBACK_COLOR = '#6b7280'\n/** Characters of context that must agree for an orphan to be re-attached on load. */\nconst REATTACH_CONTEXT = 24\n\nconst newId = (prefix: string) => `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`\n/** The `error` message of a refused request's JSON body. */\nfunction errorOf(body: unknown): unknown {\n return typeof body === 'object' && body !== null && 'error' in body ? body.error : undefined\n}\n\nfunction isDiscussion(value: unknown): value is Discussion {\n return typeof value === 'object' && value !== null && 'annotations' in value && Array.isArray(value.annotations) && 'threads' in value && Array.isArray(value.threads)\n}\n\nconst sameJson = (a: unknown, b: unknown) => JSON.stringify(a) === JSON.stringify(b)\n\nconst authorOf = (comment: Comment): EditorThread['author'] => ({ id: comment.authorId, name: comment.authorName ?? comment.authorId, color: comment.authorColor ?? FALLBACK_COLOR })\n\nfunction quoteOf(anchor: PortableAnchor | undefined): string {\n if (!anchor) return ''\n if (anchor.kind === 'range') return anchor.quote\n if (anchor.kind === 'orphan') return anchor.quote ?? (anchor.previous.kind === 'range' ? anchor.previous.quote : '')\n return ''\n}\n\nfunction viewOf(thread: CommentThread, anchor: PortableAnchor | undefined): EditorThread {\n const [first, ...replies] = thread.comments\n return {\n id: thread.id,\n author: first ? authorOf(first) : { id: '', name: '', color: FALLBACK_COLOR },\n text: first?.body ?? '',\n createdAt: first?.createdAt ?? '',\n ...(first?.editedAt !== undefined && { editedAt: first.editedAt }),\n quote: quoteOf(anchor),\n resolved: thread.status === 'resolved',\n replies: replies.map((reply): CommentReply => ({\n id: reply.id,\n author: authorOf(reply),\n text: reply.body,\n createdAt: reply.createdAt,\n ...(reply.editedAt !== undefined && { editedAt: reply.editedAt }),\n })),\n }\n}\n\nfunction rangeOf(anchor: PortableAnchor | undefined): DocRange | null {\n if (!anchor || anchor.kind === 'orphan') return null\n return anchor.kind === 'range' ? { from: anchor.from, to: anchor.to } : { from: anchor.position, to: anchor.position }\n}\n\n/** A document is \"empty\" while the host has not put its content in yet: nothing to resolve anchors against. */\nconst isBlank = (doc: { textContent: string }) => doc.textContent === ''\n\n/** Whether the text at `candidate` still reads like the context `previous` was written in (one side suffices). */\nfunction contextAgrees(candidate: PortableAnchor, previous: PortableAnchor): boolean {\n if (candidate.kind === 'orphan' || previous.kind === 'orphan') return false\n const before = previous.contextBefore?.slice(-REATTACH_CONTEXT)\n const after = previous.contextAfter?.slice(0, REATTACH_CONTEXT)\n if (!before && !after) return true\n return (!!before && !!candidate.contextBefore?.endsWith(before)) || (!!after && !!candidate.contextAfter?.startsWith(after))\n}\n\n/**\n * The comments of one editor over a REST endpoint, as a `CommentsModel` (the host passes `() => model` as the\n * `model` factory of `commentsFeature`/`commentsFeatureCore`; one instance serves the plugin and every hook).\n *\n * - **Load.** `refresh()` (called by the feature once the editor exists) fetches `GET endpoint`; each annotation's\n * anchor is resolved against the document (exact offsets, else quote and context search). An anchor that moved is\n * re-captured and written back; an anchor whose text is gone becomes an `orphan` (the thread stays, without a range)\n * and an orphan whose text is back with the same surroundings is re-attached. While the document is still empty the\n * resolving waits for its content.\n * - **Edits.** Every transaction carries all anchors with it (`mapAnchor`), so ranges, quotes and contexts follow the\n * text; changed anchors are written back after `persistDelay`. Text deleted under an anchor orphans it for good (it is\n * never silently re-attached to other text during editing; `reload()` re-attaches it when its text and context\n * are found again, e.g. after the content was replaced).\n * - **Writes** are applied locally at once and sent in order; a failed request is reported to `onError` and the threads\n * are reloaded. Without a `user` or while `canComment` is false nothing is written. Only the author may edit or\n * delete a comment.\n * - **Lifecycle.** The model follows the editor `getEditor` names until that editor is destroyed; `dispose()` writes\n * pending anchor changes and does not stop it (the feature and its hooks share the instance and dispose it on their\n * own schedule).\n */\nexport function createRestCommentsModel(options: RestCommentsModelOptions): RestCommentsModel {\n const { fetch, documentId, getEditor, onError } = options\n const endpoint = options.endpoint ?? `/comments/${encodeURIComponent(documentId)}`\n const persistDelay = options.persistDelay ?? 500\n const store = createStore<CommentsSnapshot>(EMPTY_SNAPSHOT)\n\n const userNow = () => (typeof options.user === 'function' ? options.user() : options.user)\n const canCommentNow = () => (typeof options.canComment === 'function' ? options.canComment() : options.canComment)\n /** Editors that announced their destruction: their view is still alive while `destroy` is emitted. */\n const gone = new WeakSet<Editor>()\n const current = () => {\n const instance = getEditor()\n return instance && !instance.isDestroyed && !gone.has(instance) ? instance : undefined\n }\n\n // -- Data: what the endpoint holds (annotation anchors are the local truth until written back) -----------------------\n let threads: readonly CommentThread[] = []\n let anchors = new Map<string, PortableAnchor>()\n /** The anchor each annotation has on the server, serialised. */\n const persisted = new Map<string, string>()\n const dirty = new Set<string>()\n /**\n * Where the text of an annotation that became an orphan during this session was: the deletion point, mapped through\n * every later edit. Keyed by annotation id (`orphanAt` in the snapshot is keyed by thread id; `orphanPositions` translates).\n * Deletion points are session-local: `load()` clears them, and an anchor that arrives already orphaned has none, because\n * the server stores no deletion point. Such threads get no `orphanAt` entry and sit after the placed ones in the margin.\n */\n const deletedAt = new Map<string, number>()\n /** Anchors wait for the document content (resolve on load) before they get a range. */\n let unresolved = false\n /** A load was requested / the first one succeeded: writes wait for it, so a load never overwrites a newer local change. */\n let loaded = false\n let ready = false\n\n // -- Requests: one queue, so a reply never overtakes its thread's creation ---------------------------------------------\n let chain: Promise<void> = Promise.resolve()\n let timer: ReturnType<typeof setTimeout> | undefined\n\n function enqueue(task: () => Promise<void>, reloadOnError = true): void {\n chain = chain.then(task).catch((error: unknown) => {\n onError?.(error instanceof Error ? error : new Error(String(error)))\n if (reloadOnError) enqueue(load, false)\n })\n }\n\n async function request(init?: { method: string, body: CommentAction }): Promise<unknown> {\n const response = await fetch(endpoint, init && { method: init.method, headers: { 'content-type': 'application/json' }, body: JSON.stringify(init.body) })\n if (!response.ok) {\n const detail = await response.json().then(errorOf, () => undefined)\n throw new Error(`@ecsplico/editor: comments request ${init?.method ?? 'GET'} ${endpoint} failed: ${response.status}${typeof detail === 'string' ? ` ${detail}` : ''}`)\n }\n return response.json()\n }\n\n const send = (body: CommentAction) => enqueue(async () => void await request({ method: 'POST', body }))\n\n function writeAnchors(): void {\n timer = undefined\n if (!userNow() || !ready || !canCommentNow()) {\n dirty.clear()\n return\n }\n for (const id of dirty) {\n const anchor = anchors.get(id)\n const threadId = threads.find(thread => thread.annotationId === id)?.id\n if (!anchor || !threadId || persisted.get(id) === JSON.stringify(anchor)) continue\n persisted.set(id, JSON.stringify(anchor))\n send({ action: 'update-annotation', annotation: { id, threadId, anchor } })\n }\n dirty.clear()\n }\n\n function markDirty(id: string): void {\n dirty.add(id)\n if (timer === undefined) timer = setTimeout(writeAnchors, persistDelay)\n }\n\n function flush(): void {\n clearTimeout(timer)\n writeAnchors()\n }\n\n // -- Anchors ------------------------------------------------------------------------------------------------------------\n\n /** `anchor` read against `editor`'s document: the moved/re-captured anchor, an orphan, or the same object. */\n function resolveOne(editor: Editor, anchor: PortableAnchor): PortableAnchor {\n const live = anchor.kind === 'orphan' ? anchor.previous : anchor\n const found = resolveAnchor(editor.state.doc, live)\n if (!found) {\n return anchor.kind === 'orphan'\n ? anchor\n : { kind: 'orphan', previous: anchor, quote: quoteOf(anchor) || undefined, contextBefore: anchor.contextBefore, contextAfter: anchor.contextAfter, reason: 'unresolvable' }\n }\n const next = live.kind === 'range' ? captureAnchor(editor, found) : capturePoint(editor, found.from)\n if (anchor.kind === 'orphan' && !contextAgrees(next, live)) return anchor\n return sameJson(next, anchor) ? anchor : next\n }\n\n function resolveAll(editor: Editor): void {\n if (isBlank(editor.state.doc)) {\n unresolved = anchors.size > 0\n return\n }\n unresolved = false\n for (const [id, anchor] of anchors) {\n const next = resolveOne(editor, anchor)\n if (next !== anchor) {\n anchors.set(id, next)\n if (next.kind !== 'orphan') deletedAt.delete(id)\n markDirty(id)\n }\n }\n }\n\n function carry(transactions: readonly Transaction[]): void {\n for (const transaction of transactions) {\n if (!transaction.docChanged) continue\n for (const [id, position] of deletedAt) deletedAt.set(id, transaction.mapping.map(position, 1))\n for (const [id, anchor] of anchors) {\n const next = mapAnchor(anchor, transaction)\n if (next !== anchor) {\n anchors.set(id, next)\n if (next.kind === 'orphan' && anchor.kind !== 'orphan') {\n deletedAt.set(id, transaction.mapping.map(anchor.kind === 'range' ? anchor.from : anchor.position, 1))\n }\n markDirty(id)\n }\n }\n }\n }\n\n // -- Snapshot -----------------------------------------------------------------------------------------------------------\n\n function rangesOf(editor: Editor | undefined): ReadonlyMap<string, DocRange> {\n if (!editor || unresolved) return NO_RANGES\n const size = editor.state.doc.content.size\n const ranges = new Map<string, DocRange>()\n for (const thread of threads) {\n const range = rangeOf(anchors.get(thread.annotationId))\n if (range && range.from <= size) ranges.set(thread.id, { from: range.from, to: Math.min(range.to, size) })\n }\n return ranges\n }\n\n /**\n * The snapshot's `orphanAt`, keyed by thread id: where each open thread without a text range was, read from `deletedAt`\n * (keyed by annotation id). Empty when there is no tracked deletion point; threads loaded already orphaned never have one\n * (the server stores none) and are left out, so they sit after the placed ones in the margin.\n */\n function orphanPositions(editor: Editor | undefined, ranges: ReadonlyMap<string, DocRange>): ReadonlyMap<string, number> {\n if (!editor || unresolved || deletedAt.size === 0) return NO_POSITIONS\n const size = editor.state.doc.content.size\n let found: Map<string, number> | undefined\n for (const thread of threads) {\n if (thread.status === 'resolved' || ranges.has(thread.id)) continue\n const position = deletedAt.get(thread.annotationId)\n if (position !== undefined && position <= size) (found ??= new Map()).set(thread.id, position)\n }\n return found ?? NO_POSITIONS\n }\n\n function recompute(): void {\n const editor = current()\n const previous = store.get()\n const user = userNow()\n const available = user !== null\n const canComment = available && ready && canCommentNow()\n const views = threads.map(thread => viewOf(thread, anchors.get(thread.annotationId)))\n const nextRanges = rangesOf(editor)\n const ranges = sameRanges(nextRanges, previous.ranges) ? previous.ranges : nextRanges\n const nextOrphanAt = orphanPositions(editor, ranges)\n const orphanAt = sameOrphanAt(nextOrphanAt, previous.orphanAt) ? previous.orphanAt : nextOrphanAt\n const plugin = editor && commentsKey.getState(editor.state)\n const active = plugin?.active ?? null\n const anchor = plugin?.draft\n const draft = editor && anchor ? resolveRange(editor.state, anchor) : null\n const draftQuote = editor && draft ? editor.state.doc.textBetween(draft.from, draft.to, ' ').slice(0, COMMENT_LIMITS.quote) : ''\n const sameViews = (views.length === previous.threads.length && views.every((view, index) => sameJson(view, previous.threads[index])))\n const threadsOut = sameViews ? previous.threads : views\n\n if (\n available === previous.available && canComment === previous.canComment && sameUser(user, previous.user) && threadsOut === previous.threads\n && ranges === previous.ranges && orphanAt === previous.orphanAt && active === previous.active && sameRange(draft, previous.draft) && draftQuote === previous.draftQuote\n ) return\n\n const kept = threadsOut === previous.threads && ranges === previous.ranges\n store.set({\n available,\n canComment,\n user,\n threads: threadsOut,\n ranges,\n orphanAt,\n active,\n draft: sameRange(draft, previous.draft) ? previous.draft : draft,\n draftQuote,\n open: kept\n ? previous.open\n : threadsOut\n .filter(thread => !thread.resolved)\n .sort((a, b) => (ranges.get(a.id)?.from ?? Infinity) - (ranges.get(b.id)?.from ?? Infinity) || a.createdAt.localeCompare(b.createdAt)),\n resolved: threadsOut === previous.threads ? previous.resolved : threadsOut.filter(thread => thread.resolved).sort((a, b) => b.createdAt.localeCompare(a.createdAt)),\n })\n }\n\n // -- Editor binding -----------------------------------------------------------------------------------------------------\n\n let bound: Editor | undefined\n\n function onTransaction({ transaction, appendedTransactions }: { transaction: Transaction, appendedTransactions?: readonly Transaction[] }): void {\n const editor = bound\n if (editor && anchors.size) {\n const all = [transaction, ...(appendedTransactions ?? [])]\n if (all.some(tr => tr.docChanged)) {\n if (isBlank(editor.state.doc)) unresolved = true\n else if (unresolved) resolveAll(editor)\n else carry(all)\n }\n }\n recompute()\n }\n\n function onDestroy(): void {\n if (bound) gone.add(bound)\n unbind()\n recompute()\n }\n\n function unbind(): void {\n bound?.off('transaction', onTransaction)\n bound?.off('update', recompute)\n bound?.off('destroy', onDestroy)\n bound = undefined\n }\n\n function refresh(): void {\n const editor = current()\n if (editor !== bound) {\n unbind()\n bound = editor\n editor?.on('transaction', onTransaction)\n // `setEditable` emits `update` only, and `canComment` may follow it.\n editor?.on('update', recompute)\n editor?.on('destroy', onDestroy)\n if (editor && loaded) resolveAll(editor)\n }\n if (!loaded) {\n loaded = true\n enqueue(load, false)\n }\n recompute()\n }\n\n function dispose(): void {\n flush()\n }\n\n async function load(): Promise<void> {\n const discussion = await request()\n if (!isDiscussion(discussion)) throw new Error(`@ecsplico/editor: comments request GET ${endpoint} did not answer a discussion`)\n threads = discussion.threads\n anchors = new Map(discussion.annotations.map((annotation: Annotation) => [annotation.id, annotation.anchor]))\n persisted.clear()\n for (const [id, anchor] of anchors) persisted.set(id, JSON.stringify(anchor))\n dirty.clear()\n deletedAt.clear()\n ready = true\n const editor = current()\n unresolved = anchors.size > 0\n if (editor) resolveAll(editor)\n recompute()\n }\n\n function reload(): Promise<void> {\n flush()\n loaded = true\n enqueue(load, false)\n return idle()\n }\n\n async function idle(): Promise<void> {\n flush()\n const seen = chain\n await seen\n // A request that failed queued a reload, a finished one may have moved anchors.\n if (chain !== seen || timer !== undefined || dirty.size > 0) await idle()\n }\n\n // -- Mutations ----------------------------------------------------------------------------------------------------------\n\n /** Trimmed and cut to the limit; '' when nothing is left. */\n const clean = (text: string) => text.trim().slice(0, COMMENT_LIMITS.text)\n\n function writer(): AuthorIdentity | null {\n const user = userNow()\n return user && ready && canCommentNow() ? user : null\n }\n\n const commentOf = (user: AuthorIdentity, body: string): Comment => ({ id: newId('cm'), body, authorId: user.id, authorName: user.name, authorColor: user.color, createdAt: new Date().toISOString() })\n\n function setThreads(next: readonly CommentThread[]): void {\n threads = next\n recompute()\n }\n\n const threadById = (id: string) => threads.find(thread => thread.id === id)\n\n function replaceThread(id: string, change: (thread: CommentThread) => CommentThread): void {\n setThreads(threads.map(thread => (thread.id === id ? change(thread) : thread)))\n }\n\n function add(text: string): string | null {\n const editor = current()\n const user = writer()\n const body = clean(text)\n const draft = editor && commentsKey.getState(editor.state)?.draft\n const range = editor && draft ? resolveRange(editor.state, draft) : null\n if (!editor || !user || !draft || !range || range.from >= range.to || !body) return null\n const threadId = newId('ct')\n const annotation: Annotation = { id: newId('ca'), threadId, anchor: captureAnchor(editor, range) }\n const comment = commentOf(user, body)\n editor.view.dispatch(editor.state.tr.setMeta(commentsKey, { draft: null, active: threadId }).setMeta('addToHistory', false))\n releaseRanges(editor, [draft])\n anchors.set(annotation.id, annotation.anchor)\n persisted.set(annotation.id, JSON.stringify(annotation.anchor))\n threads = [...threads, { id: threadId, annotationId: annotation.id, status: 'open', comments: [comment] }]\n recompute()\n send({ action: 'create', annotation, thread: { id: threadId, annotationId: annotation.id, initialComment: comment } })\n return threadId\n }\n\n function reply(threadId: string, text: string): void {\n const user = writer()\n const body = clean(text)\n if (!user || !body || !threadById(threadId)) return\n const comment = commentOf(user, body)\n replaceThread(threadId, thread => ({ ...thread, comments: [...thread.comments, comment] }))\n send({ action: 'reply', threadId, comment })\n }\n\n function edit(threadId: string, replyId: string | null, text: string): void {\n const user = writer()\n const body = clean(text)\n const thread = threadById(threadId)\n const target = thread && (replyId === null ? thread.comments[0] : thread.comments.find(comment => comment.id === replyId))\n if (!user || !body || !thread || !target || target.authorId !== user.id || target.body === body) return\n const editedAt = new Date().toISOString()\n replaceThread(threadId, item => ({ ...item, comments: item.comments.map(comment => (comment.id === target.id ? { ...comment, body, editedAt } : comment)) }))\n send({ action: 'edit', threadId, commentId: target.id, body, editedAt })\n }\n\n const activeThread = () => {\n const editor = current()\n return editor ? commentsKey.getState(editor.state)?.active ?? null : null\n }\n\n function setResolved(threadId: string, resolved: boolean): void {\n const thread = threadById(threadId)\n if (!writer() || !thread || (thread.status === 'resolved') === resolved) return\n const status = resolved ? 'resolved' : 'open'\n replaceThread(threadId, item => ({ ...item, status }))\n if (resolved && activeThread() === threadId) activate(null)\n send({ action: 'status', threadId, status })\n }\n\n function remove(threadId: string): void {\n const user = writer()\n const thread = threadById(threadId)\n if (!user || !thread || thread.comments[0]?.authorId !== user.id) return\n if (activeThread() === threadId) activate(null)\n anchors.delete(thread.annotationId)\n persisted.delete(thread.annotationId)\n dirty.delete(thread.annotationId)\n deletedAt.delete(thread.annotationId)\n setThreads(threads.filter(item => item.id !== threadId))\n send({ action: 'remove', threadId })\n }\n\n function removeReply(threadId: string, replyId: string): void {\n const user = writer()\n const thread = threadById(threadId)\n const target = thread?.comments.slice(1).find(comment => comment.id === replyId)\n if (!user || !thread || !target || target.authorId !== user.id) return\n replaceThread(threadId, item => ({ ...item, comments: item.comments.filter(comment => comment.id !== replyId) }))\n send({ action: 'remove-comment', threadId, commentId: replyId })\n }\n\n function activate(id: string | null, activateOptions: { reveal?: boolean } = {}): void {\n const editor = current()\n if (editor) setActiveComment(editor, id, activateOptions)\n }\n\n function startDraft(): void {\n const editor = current()\n if (editor && writer()) startCommentDraft(editor)\n }\n\n function cancelDraft(): void {\n const editor = current()\n if (editor) cancelCommentDraft(editor)\n }\n\n return { state: store, refresh, dispose, add, reply, edit, setResolved, remove, removeReply, activate, startDraft, cancelDraft, reload, idle }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Annotation, Comment, CommentAction, CommentStore, CommentThread, CreateThreadInput, Discussion, NewThread, ThreadStatus } from "./types.js";
|
|
2
2
|
import { CommentStoreError } from "./errors.js";
|
|
3
|
+
import { addComment, createThread, editComment, emptyDiscussion, removeComment, removeThread, setThreadStatus, updateAnchor } from "./record.js";
|
|
3
4
|
//#region src/adapters/comments/server.d.ts
|
|
4
5
|
export interface CommentsRequest {
|
|
5
6
|
method: string;
|
|
@@ -19,5 +20,5 @@ export interface CommentsResponse {
|
|
|
19
20
|
*/
|
|
20
21
|
export declare function handleCommentsRequest(store: CommentStore, request: CommentsRequest): Promise<CommentsResponse>;
|
|
21
22
|
//#endregion
|
|
22
|
-
export { type Annotation, type Comment, type CommentAction, type CommentStore, CommentStoreError, type CommentThread, type CreateThreadInput, type Discussion, type NewThread, type ThreadStatus };
|
|
23
|
+
export { type Annotation, type Comment, type CommentAction, type CommentStore, CommentStoreError, type CommentThread, type CreateThreadInput, type Discussion, type NewThread, type ThreadStatus, addComment, createThread, editComment, emptyDiscussion, removeComment, removeThread, setThreadStatus, updateAnchor };
|
|
23
24
|
//# sourceMappingURL=server.d.ts.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isPortableAnchor } from "../anchors.js";
|
|
2
2
|
import { CommentStoreError, invalid } from "./errors.js";
|
|
3
|
+
import { addComment, createThread, editComment, emptyDiscussion, removeComment, removeThread, setThreadStatus, updateAnchor } from "./record.js";
|
|
3
4
|
//#region src/adapters/comments/server.ts
|
|
4
5
|
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5
6
|
const isText = (value) => typeof value === "string";
|
|
@@ -97,6 +98,6 @@ async function handleCommentsRequest(store, request) {
|
|
|
97
98
|
}
|
|
98
99
|
}
|
|
99
100
|
//#endregion
|
|
100
|
-
export { CommentStoreError, handleCommentsRequest };
|
|
101
|
+
export { CommentStoreError, addComment, createThread, editComment, emptyDiscussion, handleCommentsRequest, removeComment, removeThread, setThreadStatus, updateAnchor };
|
|
101
102
|
|
|
102
103
|
//# sourceMappingURL=server.js.map
|