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). Markdown never makes it throw: unsupported content falls back. Invalid options, 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; converted internally to one absolute collaborator context |
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 piece you can supply in place of
slackmark's own: the markdown parser, extra node adapters, the plain-text renderer,
renderers, and the uploader. Their shapes are checked when the converter is built, and a
parser or adapter that fails mid-conversion also rejects with ConfigurationError.
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. Puppeteer's LaunchOptions belongs to slackmark-node, which passes it through
untouched.
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
The package entry exports the conversion API; two optional subpaths carry network-facing implementations:
| 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 is universal JavaScript: no Node built-ins, no Buffer, no
process, no I/O in core. 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.