Isomorphic TypeScript client for the Draftmark v1 API.
Zero runtime dependencies; runs anywhere fetch is available (Node 18+, VS Code
extension host, browsers). Shared by the dm CLI and the Draftmark VS Code
extension.
npm install @draftmark-app/clientimport { DraftmarkClient } from "@draftmark-app/client";
// An account API key (acct_...) covers the full owner lifecycle for docs it
// creates: create, update, delete, comment, resolve.
const dm = new DraftmarkClient({ apiKey: process.env.DM_API_KEY });
// Create (the doc is owned by the account behind the acct_ key)
const created = await dm.createDoc({
content: "# Draft\n\nReview me.",
visibility: "public",
});
// Read
const doc = await dm.getDoc(created.slug);
const markdown = await dm.getDocRaw(created.slug);
// Comments
const comments = await dm.listComments(created.slug, { status: "open" });
await dm.createComment(created.slug, {
body: "Nit: tighten this line.",
anchor_type: "line",
anchor_ref: 3,
anchor_text: "Review me.", // populate so the comment survives edits (re-anchoring)
});
await dm.setCommentStatus(created.slug, comments[0].id, "resolved");
// Update (new version) — no per-doc magic token needed for account-owned docs
await dm.updateDoc(created.slug, { content: "# Draft\n\nReviewed.", version_note: "addressed feedback" });
// Reviews & reactions (dedup identity is derived server-side)
await dm.createReview(created.slug, { reviewer_type: "agent" });
await dm.addReaction(created.slug, "thumbs_up");Pass default auth to the constructor, or override per call:
const dm = new DraftmarkClient({ baseUrl: "https://draftmark.app/api/v1" });
await dm.getDoc("abc123", { apiKey: "key_..." }); // doc api_key
await dm.updateDoc("abc123", { title: "New" }, { magicToken: "..." }); // per-doc magic tokenapiKey→Authorization: Bearer(a docapi_keyor an accountacct_key).magicToken→X-Magic-Token(per-doc owner token; only needed for docs not owned by an account).
Typed methods throw DraftmarkApiError (.status, .code, .message,
.details). For result-style handling, use the low-level raw() /
request(), which return { ok, status, data }.
import { DraftmarkApiError } from "@draftmark-app/client";
try {
await dm.createComment(slug, { body: "hi" });
} catch (e) {
if (e instanceof DraftmarkApiError && e.status === 409) {
// review closed / deadline passed
}
}new DraftmarkClient({ fetch: myFetch }); // e.g. tests, or a runtime without global fetchnpm install
npm run build # tsc → dist/ (ESM + .d.ts)MIT © Rumbo Labs