Minimal, framework-agnostic SDK for building RefMD plugins.
- v0.1.x: API surface is small and focused on DOM primitives, a tiny UI kit, and host bridging helpers.
- No external deps, designed to be imported directly by plugins in the browser.
npm i @refmdio/plugin-sdk
Then in your plugin code:
import { createKit, resolveDocId } from '@refmdio/plugin-sdk'
export default async function mount(container: Element, host: any) {
const kit = createKit(host)
const state = { docId: host?.context?.docId || resolveDocId(), text: '' }
kit.store({
container,
initialState: state,
render: (s, set) => kit.card({
title: 'SDK Demo',
body: kit.fragment(
kit.input({ value: s.text, onInput: (v) => set({ text: v }) }),
kit.button({ label: 'Preview', onClick: async () => {
const out = document.createElement('div')
container.appendChild(out)
await kit.markdownPreview(s.text, out, { sanitize: true, absolute_attachments: true, doc_id: s.docId, base_origin: host.origin })
}})
)
})
})
}- Core:
h,fragment,render,store - UI:
button,card,input,textarea,tokens - Utils:
markdownPreview(host, { text, options, target }),resolveDocId,escapeHtml - Host bridges:
createHostContext,normalizeExec,createRecordStore,createMarkdownRenderer,createMarkdownEditor,createUploader - Split editor bridge (v0.1.9+):
host.ui.mountSplitEditor(container, { docId, token, preview: { delegate }, document: { onReady } }) - Record store pagination (v0.1.10+):
createRecordStore(...).list({ limit, offset })passes pagination throughhost.records.list. - Document editor actions (v0.1.11+):
ctx.actions.exec(action, payload)runs a plugin-defined backend action. Use backend action effects for plugin state changes. - Document editor pane bridge: optional
canActivateDocumentEditor(ctx)andactivateDocumentEditor(ctx)exports can attach plugin behavior to the standard RefMD document editor. Usectx.documentPanes.register(...)for Backlinks-style right pane UI andctx.editorfor selection, insertion, reveal, content, and decorations.
Document editor API notes:
ctx.editor.setDecorations(ownerId, ...)andctx.editor.setHiddenRanges(ownerId, ...)use plugin-local owner IDs. RefMD scopes those IDs by plugin internally.ctx.records.list(kind, { limit, offset })supports pagination.ctx.kv.get(key)resolves to the stored value for document editor plugins.ctx.actions.exec(action, payload)is the write path for document editor plugins. Expose plugin-specific backend actions instead of mutating generic records or KV from the frontend.ctx.documentPanes.register({ icon })accepts a host-defined icon name string. Unknown values fall back to the host default.
Document editor pane plugins export named lifecycle functions:
import type { DocumentEditorActivationContext } from '@refmdio/plugin-sdk'
export async function canActivateDocumentEditor(ctx: { document?: { type?: string | null } }) {
return ctx.document?.type === 'markdown'
}
export async function activateDocumentEditor(ctx: DocumentEditorActivationContext) {
const pane = ctx.documentPanes.register({
id: 'comments',
title: 'Comments',
icon: 'message-square',
render(container) {
container.textContent = ctx.document.getContent()
return () => {
container.textContent = ''
}
},
})
return () => pane.dispose()
}WC are not intended to be used directly by plugin authors; markdownPreview calls the host hydration routines under the hood.
npm run build
Outputs ESM + CJS + d.ts to dist/.
- Tag
v0.1.x→ GitHub Actions builds and publishes to npm.