# @leafpad/blogs — LLM Reference > Package: @leafpad/blogs > Version: 0.3.1 > Purpose: TypeScript SDK for fetching and rendering LeafPad blog posts in any JavaScript application. > Source: https://leafpad.io > License: ISC ## Overview `@leafpad/blogs` lets you integrate LeafPad-managed blog content into any web project. It provides: - An API client (`BlogsService`) for fetching posts and docs from LeafPad's public REST API - HTML rendering utilities (`BlogPostFormat`) that produce ready-to-use HTML strings - Content helpers (`BlogUtils`) for read time, date formatting, text extraction, and slugification - TOC utilities (`renderTOCHTML`, `attachObserverToTOCLinks`) for table-of-contents generation and DOM observation - A pre-built stylesheet bundled at `src/styles/style.css` ## Installation ``` npm install @leafpad/blogs ``` ## Exports (index.ts) ```ts export { BlogsService } from './src/core/blogs.js' export { BLOG_CONFIG, type BlogsConfigType } from './src/core/blog_config.js' export * from './src/types/types.js' export { BlogPostFormat } from './src/utils/BlogPostFormat.js' export { default as BlogUtils } from './src/utils/BlogUtils.js' export { default as BlogApiError } from './src/core/BlogsError.js' export { attachObserverToTOCLinks, renderTOCHTML, type TOCOptions } from './src/utils/createToc.js' ``` --- ## Module: src/core/blogs.ts ### Class: BlogsService Primary API client. Handles HTTP requests with timeout, retry, and exponential backoff. ```ts new BlogsService(organizationSlug: string, config?: BlogsConfigType) ``` **Methods:** ```ts fetchPosts(options?: FetchPostsOptions): Promise ``` Fetch paginated published blog posts. Options: page, limit, includeHtml, md, tags[], search, docs. ```ts fetchBlog(slug: string, options?: FetchPostOptions): Promise ``` Fetch a single post by URL slug. Returns null if 404. Throws BlogApiError on other failures. ```ts fetchDocs(options?: FetchPostsOptions): Promise ``` Fetch documentation posts structured as a hierarchical tree (DocItem[]). Posts with parentId are nested under their parent. Sorted by `position` field at all levels. **Internals (private):** - `buildUrl(endpoint, params)` — Constructs the full API URL - `makeRequest(url, options)` — Fetch wrapper with AbortController timeout, 3 retries, exponential backoff, BlogApiError on HTTP errors - `fetchItems(options)` — Builds URLSearchParams and calls makeRequest **Error behavior:** - 4xx responses → throws immediately, no retry - 5xx responses → retries up to `config.retries` times with 2^attempt second delay - Timeout → throws BlogApiError with code 'TIMEOUT' - All retries exhausted → throws BlogApiError with code 'MAX_RETRIES_EXCEEDED' --- ## Module: src/core/blog_config.ts ```ts type BlogsConfigType = { baseUrl?: string // default: 'https://leafpad.io' apiPath?: string // default: '/api/public/v1/post' defaultLimit?: number // default: 10 maxPostsForFiltering?: number // default: 50 cacheRevalidateInterval?: number // default: 300 (seconds) staticParamsRevalidateInterval?: number // default: 3600 (seconds) wordsPerMinute?: number // default: 200 timeout?: number // default: 10000 (ms) retries?: number // default: 3 } const BLOG_CONFIG: Required // all defaults as const ``` --- ## Module: src/core/BlogsError.ts ```ts class BlogApiError extends Error { name: 'BlogApiError' status?: number // HTTP status code, e.g. 404, 500 code?: string // 'HTTP_404', 'HTTP_500', 'TIMEOUT', 'MAX_RETRIES_EXCEEDED' constructor(message: string, status?: number, code?: string) } ``` --- ## Module: src/types/types.ts ### Core Data Types ```ts interface BlogPost { id: number name: string // Post title slug: string // URL slug createdAt: string // ISO date string updatedAt: string // ISO date string published: boolean hasChildren: boolean // Has child doc posts parentId?: number // Parent post id for docs hierarchy position: string // Sort key for docs ordering content?: any // Raw BlockNote JSON content htmlContent?: string // Pre-rendered HTML (when includeHtml: true) md?: string // Raw Markdown (when md: true) textContent?: string // Plain text version tocItems: { level: number; text: string; id: string }[] // Headings for TOC seo?: BlogSEO tags: BlogTag[] organization: BlogOrganization createdByUser: { name: string; image?: string } } interface BlogTag { id: number; name: string } interface BlogSEO { title?: string description?: string image?: string keywords?: string[] } interface BlogOrganization { id: string; name: string; slug: string } interface BlogPagination { page: number limit: number totalCount: number totalPages: number hasNext: boolean hasPrev: boolean } interface BlogApiResponse { posts: BlogPost[] pagination: BlogPagination organization: BlogOrganization } type DocItem = { id: number label: string path?: string position: string children?: DocItem[] // Nested children for docs tree } interface DocsResponse { items: DocItem[] pagination: BlogPagination organization: BlogOrganization } interface FetchPostsOptions { page?: number // default: 1 limit?: number // default: config.defaultLimit (10) includeHtml?: boolean // default: true md?: boolean // default: false tags?: string[] // filter by tag names search?: string // full-text search docs?: boolean // fetch docs posts only } interface FetchPostOptions { includeHtml?: boolean // default: true md?: boolean // default: false } ``` --- ## Module: src/utils/BlogPostFormat.ts All methods are **static** and return `string` (HTML). ### Rendering Full Posts ```ts BlogPostFormat.completeBlogPost({ post: BlogPost, toc?: boolean, config?: CompleteBlogPostItemsConfig }): string ``` Renders a full blog post inside `.blogs-container`. Sections controlled by `config`. ```ts BlogPostFormat.blogPostWithToc({ post: BlogPost, config?: CompleteBlogPostItemsConfig }): string ``` Renders post + `