convert()
import { convert, convertToMessages, createConverter } from "slackmark";
function convert(markdown: string, options?: ConvertOptions): Promise<ConversionResult>;
function convertToMessages(
markdown: string,
options?: ConvertOptions,
): Promise<ConversionMessagesResult>;
function createConverter(options?: CreateConverterOptions): SlackMarkConverter;convert: markdown in, one message out (blocks,text,degradations,receipts). With the built-in pipeline and valid options, unsupported content falls back. Invalid options, a configured renderer returning bytes when no uploader or later successful renderer is available, cancellation, and timeouts reject.convertToMessages: same input, but withoverflow: "split"long content becomes multiple messages, split between blocks. Without that option it returns a single degraded message. See Long content and splitting.createConverter: builds a reusable, stateless converter with default options; callconverter.convert(markdown, perCallOptions?)orconverter.convertToMessages(...). Per-call options override the defaults. Prefer this when converting many messages.
Result shapes are documented in ConversionResult.
ConvertOptions
Every option is optional. Content options can be set as createConverter defaults or per
call. signal and timeoutMs are per-call only.
| Option | Type | Default | Effect |
|---|---|---|---|
capabilities | preset name | flags | partial flags | "latest" | Which Slack block types the destination supports (presets) |
capabilityOverrides | partial flags | — | Flag-level overrides applied on top of capabilities |
overflow | "degrade" | "split" | "degrade" | Truncate to one message, or split into several (convertToMessages only) |
strategy | "rich-text-first" | "markdown-block" | "rich-text-first" | Full block mapping, or raw markdown in markdown blocks |
renderers | ImageRenderer[] | [] | Ordered image renderers for any fenced language (guide) |
uploader | SlackUploader | — | Uploads bytes-producing renderer output to Slack's files API |
signal | AbortSignal | — | Optional caller cancellation |
timeoutMs | number | — | Relative operation timeout measured from the start of the call |
enableMath | boolean | false | Parse $$…$$ display math and offer it to renderers |
enableInlineMath | boolean | false | Also read $x$ inside a paragraph as math; off so prose keeps its dollar amounts |
enableFrontmatter | boolean | false | Parse and skip leading YAML/TOML frontmatter (with a degradation) |
mentionResolvers | { resolveUser?, resolveChannel? } | — | Resolve bare @handle / #channel to Slack IDs (details) |
Bad options fail loudly. createConverter checks its defaults synchronously and throws
ConfigurationError; convert and convertToMessages reject with the same error. Only
undefined counts as omitted, so convert(md, { overflow: null }) rejects rather than
quietly falling back to "degrade".
A collaborator, here and elsewhere in these docs, is a parser, node adapter, plain-text
renderer, image renderer, or uploader supplied by your application. Invalid construction
shapes fail with ConfigurationError. Runtime behavior depends on the seam: parser and
plain-text failures reject as configuration errors, ordinary adapter failures use the
document fallback, and ordinary renderer/upload failures follow the renderer fallback
chain. Typed configuration and operation errors reject.
Renderers and uploaders behave differently on purpose, because they reach outside the process. A renderer that throws, or returns something the converter cannot use, does not reject the conversion: the failure is recorded as a degradation and the content falls back to text.
CreateConverterOptions
createConverter accepts everything above plus injection seams. These exist
only at construction and cannot be passed per call:
| Option | Type | Effect |
|---|---|---|
adapters | NodeAdapter[] | Custom node adapters, consulted before the built-ins |
parser | MarkdownParser | Replace the default remark-based markdown parser |
plainText | PlainTextRenderer | Replace the notification-text renderer |
These are extension and testing seams; typical use never needs them.
Subpath exports
slackmark exports the conversion API. Its slackmark/renderers and
slackmark/slack subpaths expose optional integrations; slackmark-node is a
separate package with its own subpaths.
| Import path | Exports |
|---|---|
slackmark | convert, convertToMessages, createConverter, validateBlocks, CAPABILITY_PRESETS, resolveCapabilities, all public types |
slackmark/renderers | Hosted URL renderers: Mermaid Ink, Kroki (Mermaid and other diagrams), CodeCogs (math), and QuickChart (Chart.js) |
slackmark/slack | FetchSlackUploader, the Slack external-upload flow for bytes-producing renderers |
slackmark-node | High-level Node converter, operation types, and public errors (guide) |
slackmark-node/renderers | Built-in Mermaid and KaTeX byte renderers |
slackmark-node/puppeteer | Advanced Puppeteer runtime, launcher, and local asset loaders |
Deep imports (slackmark/dist/...) are unsupported.
Runtime support
slackmark uses web-standard APIs and performs no I/O by default. It runs on
Cloudflare Workers, Bun, Deno, and Node ^20.19.0 || >=22.12.0. Default
conversion is deterministic: identical input and options produce byte-identical
output. With injected collaborators (custom parsers, adapters, renderers,
uploaders, mention resolvers), the output is only as deterministic as they are.
slackmark-node is a separate Node.js 22.12+ package because Chromium,
filesystem access, and browser-process lifecycle do not belong in universal
core.