Skip to content

API Reference

github-actions[bot] edited this page Sep 11, 2026 · 5 revisions

API Reference

The public surface re-exported from src/index.ts. The two classes you will use most are RSSFeed and HTMLMapper.

← Back to Home · Related: RSS Feeds · HTML Mapping · Component Types

No-throw contract

For any string input and any params/root config, new RSSFeed(...), validate(), and build() never throw — problems are reported through errors/warnings instead:

  • Malformed XML — the constructor wraps XMLParser.parse in a try/catch; a parse failure becomes an XML_PARSE_ERROR issue on both feed.errors and feed.rss.errors, and this.data is left empty so validate()/build() still run to completion.
  • Malformed URLs reachable from feed content — the channel <link>, iframe embeds (YouTube/TikTok/Vimeo/Dailymotion/Twitter/Infogram/Apple Podcasts), anchor-based embeds, relative media:content URL resolution, and the item-<link>-based resolution of relative image/gallery/video/audio URLs inside a built item's components (resolveComponentMediaUrls) are all guarded with URL.canParse before construction; an unparseable URL becomes a warning, is left untouched, or becomes an error-annotated component instead of throwing.
  • Invalid params/root — never silently dropped. The constructor always stores what it's given; build() is the one place that validates them (RSSFeed.validateParams) and reports the result.
  • Network I/OgetRecipeFromUrl/getHtmlContent (see below) still reject on a genuine network failure or non-ok response — that's a Promise rejection, not a thrown exception from RSSFeed itself, and is the one place this library performs I/O you didn't explicitly ask for.

Verified by a seeded property-test suite (src/rss/__tests__/rss-feed.fuzz.test.ts) driving the constructor → validate()build() lifecycle over hand-picked edge cases and random XML/params input. See ADR-0007 (docs/adr/0007-throw-surface-inventory.md) for the full throw-surface inventory and how each site was fixed.

Error model: FeedIssue

errors/warnings throughout this library — RSS, Channel, Item, Enclosure, MediaGroup, MediaContent, RSSFeed.errors, RSSFeed.validateParams()'s return value, and every Component's errors/warnings — are arrays of:

interface FeedIssue {
  code: FeedIssueCode; // stable string union, exported from '@canvasflow/feed'
  severity: 'error' | 'warning';
  message: string; // human-readable, for logging/display
  path?: string; // e.g. "cf:thumbnail.url", the tag/field the issue is about
}

FeedIssueCode is a large, stable, switchable union (XML_PARSE_ERROR, MISSING_REQUIRED_TAG, INVALID_PARAMS, MISSING_IMAGE_SRC, INVALID_YOUTUBE_URL, ... — see src/feed-issue.ts for the full list). Branch on .code for programmatic handling; use .message for display. See the CHANGELOG's migration guide for the string[]FeedIssue[] transition.

validate() / build() lifecycle

  • validate() populates errors/warnings against the tag allow-lists in tag.ts. It does not mutate the parsed input (no delete), and it resets its own accumulators at the start, so calling it more than once is idempotent.
  • build() calls validate() automatically if it hasn't run yet, then constructs the typed RSS. If rss.errors is non-empty after validation, build() returns early with that RSS (no items are built).
  • Both are async even though today's implementation is fully synchronous internally — see ADR-0008 (docs/adr/0008-keep-validate-build-async.md) for why the sync conversion is deferred rather than done now.

RSSFeed

import { RSSFeed } from '@canvasflow/feed';

Instance members

Member Signature Description
constructor new RSSFeed(content: string, params?: Params) Parse the feed XML; optional Params configures HTML conversion.
content string The original XML passed in.
rss RSS The typed result, populated by validate() / build().
errors FeedIssue[] Top-level errors collected during validation.
root (setter) set root(mapping?: Mapping) Scope content extraction to a sub-element before conversion.
validate() Promise<void> Validate required tags; fill errors/warnings.
build() Promise<RSS> Build the typed RSS; attach a components array to each item.

Static members

Member Signature Description
validateParams (params?: Params, root?: Mapping) => FeedIssue[] Validate params/root against the Zod schemas; returns structured issues (code is 'INVALID_PARAMS' | 'INVALID_ROOT_MAPPING').
toJSON (rss: RSS) => unknown Serialize then re-parse an RSS (round-trips errors via toString).
toString (rss: RSS) => string JSON string of an RSS (Error values are flattened).
getRecipeFromUrl (url: string) => Promise<Recipe | null> Deprecated thin wrapper around getRecipeFromUrl from ../rss/recipe (see below).
getHtmlContent (url: string, headers?: HeadersInit) => Promise<string> Deprecated thin wrapper around getHtml from ../utils/http (see below) — kept as an identical-behaviour alias.

getRecipeFromUrl / getHtmlContent perform network I/O (fetch); everything else is pure.

Network I/O (src/utils/http.ts, src/utils/node-https-fetch.ts, src/rss/recipe.ts)

Extracted out of RSSFeed (Section 3, "Network I/O extraction") so the XML-parsing library doesn't hide unbounded fetch calls behind its public API. All are exported from @canvasflow/feed directly:

import {
  fetchUrl,
  getHtml,
  getHtmlContent,
  getJson,
  nodeHttpsFetch,
  getRecipeFromUrl,
} from '@canvasflow/feed';
Function Signature Description
fetchUrl(url, options?) (url: string, options?: FetchOptions) => Promise<string> Fetch url as text — status check + body cap only, no Content-Type opinion.
getHtml(url, options?) (url: string, options?: FetchOptions) => Promise<string> fetchUrl plus a Content-Type: text/html check; rejects a 2xx response whose body isn't actually HTML.
getHtmlContent(url, options?) same as getHtml Deprecated alias for getHtml, kept for backward compatibility.
getJson<T>(url, options?) (url: string, options?: FetchOptions) => Promise<T> fetchUrl plus a Content-Type: application/json check, then JSON.parses the body.
nodeHttpsFetch Node https-backed fetch-compatible implementation Injectable as options.fetch when the global fetch isn't suitable.
getRecipeFromUrl(url, options?) (url: string, options?: FetchOptions) => Promise<Recipe | null> Fetch url and extract the first LD+JSON Recipe (top-level or nested in @graph); malformed JSON-LD blocks are skipped.

FetchOptions: { fetch?: typeof fetch; headers?: HeadersInit; timeoutMs?: number /* default 10000 */; maxBytes?: number /* default 5MB */ }. The request is aborted via AbortSignal.timeout(timeoutMs); the response body is read through a size-capped stream. fetchUrl/getHtml/getJson share one internal request helper and only differ in what they do with the response afterward.

HTMLMapper

import { HTMLMapper } from '@canvasflow/feed';
Member Signature Description
toComponents (html: string, params?: Params) => Component[] Convert an HTML string into components.
getRootElement (html: string, mapping: Mapping) => string | null Serialize the first element matching mapping.
splitParagraphImages (html: string, tag: string) => string Split elements of the given tag that contain <img> so each image becomes its own block.

See HTML Mapping.

Exported helper functions

From the mapping module:

Function Purpose
processTextLinks(html, link?) Rewrite relative/protocol-relative/unsafe links in text HTML.
isValidMapping(value), isValidParams(value) Boolean validation against the Zod schemas.
validateParams(value) Parse-or-throw, returning a typed Params.

These four are the only mapping.ts helpers re-exported from src/index.ts. mapping.ts and its sibling modules export a good deal more at the module level for use within src/reduceComponents, fromNode, getRootElement (the node-array version; HTMLMapper.getRootElement is the public string version), reduceEmptyTextNode/filterEmptyTextNode, mapLivePost, resolveMediaUrl/resolveComponentMediaUrls, isEmpty, and the textTags/textTagsSet/mappingTagsSet constants — but none of those are part of the published @canvasflow/feed package; they are internal implementation detail. See Architecture if you're reading the source rather than consuming the package.

Type guards

The is* component guards (e.g. isImageComponent, isVideoComponent) and isValidTextRole are exported from the component module — see Component Types.

Exported types

Group Types
Feed RSS, Channel, ChannelImage, Item, MutableItem, Thumbnail, Enclosure, Source, MediaContent, MediaGroup
Errors FeedIssue, FeedIssueCode, FeedIssueSeverity — see "Error model" above
Config Params, Mapping, ComponentMapping, MatchType, Filter, TagFilter, ClassFilter, AttributeFilter, AttributeValueFilter, AttributePatternFilter
Component mappings ContainerMapping, ColumnsMapping, LiveContainerMapping, RecipeMapping, CustomMapping, TextMapping, GalleryMapping, DividerMapping, SpacerMapping
Components Component, ComponentType, TextType, ComponentLink, ImageSource, GalleryImage, and every *Component interface
Schema Recipe and related schema types (Thing, Person, Organization, NutritionInformation, …)

Exact signatures are the source of truth — see src/index.ts and the files it re-exports. Note that none of the Zod schema objects (ComponentSchema, ImageComponentSchema, MappingSchema, ParamsSchema, RecipeSchema, etc.) are re-exported — they live in component.ts/mapping.schema.ts/schema/recipe-schema.ts for internal validation only. Use isValidParams/isValidMapping/validateParams (above) or the is*Component type guards instead of importing a schema directly.

Clone this wiki locally