Docs
/
syndication feed FORMAT toolkit

feeds

Syndication feed FORMAT toolkit: parse, detect, convert, and merge web feeds — RSS 2.0, Atom 1.0, and JSON Feed 1.1. Pure hand-rolled lightweight XML/JSON parsing (zero dependencies, Node built-ins...

feeds — syndication feed FORMAT toolkit

Parse, detect, convert, and merge web feeds across the three syndication formats: RSS 2.0, Atom 1.0, and JSON Feed 1.1.

Pure JavaScript — zero npm dependencies, Node built-ins only. The XML reader is a small, forgiving, hand-rolled tag-scanner (no xml2js / fast-xml-parser / cheerio). It handles CDATA, XML/HTML entities (named + numeric), namespaced tags (atom:, dc:, content:encoded, media:), and both RFC-822 (RSS) and ISO-8601 (Atom/JSON) dates.

Design

Everything routes through one canonical item model, so any format converts to any other by passing through the middle:

parseRss  ─┐                        ┌─ toRss
parseAtom ─┼──-> normalized items ──┼─ toAtom
parseJson ─┘   (title, link, id,    └─ toJsonFeed
                summary, content,
                author, published,
                updated, categories,
                enclosures)

Normalized item shape:

{
  id, title, link,
  summary, content,
  author,
  published,      // ISO-8601 string | null
  updated,        // ISO-8601 string | null
  publishedMs,    // epoch ms | null  (sort key)
  categories,     // string[]
  enclosures,     // [{ url, type, length }]
  source,         // string | null
}

Tools (14)

ToolInputReturns
parse{ feed, options? }auto-detects format, then { format, meta, items }
parseRss{ feed, options? }parse an RSS 2.0 / RDF string → { format, meta, items }
parseAtom{ feed, options? }parse an Atom 1.0 string → { format, meta, items }
parseJsonFeed{ feed, options? }parse a JSON Feed 1.x string/object → { format, meta, items }
detect{ feed }`{ format: 'rss'\'atom'\'json'\'unknown' }`
toRss{ items, meta? }{ format:'rss', xml } — valid RSS 2.0
toAtom{ items, meta? }{ format:'atom', xml } — valid Atom 1.0
toJsonFeed{ items, meta? }{ format:'json', feed } — JSON Feed 1.1 object
merge{ feeds, options? }combine parsed feeds/strings into one date-sorted, de-duped list
normalizeItems{ items }coerce loose objects into the canonical item shape
sortItems{ items, options? }sort by date (order: 'desc' default, or 'asc')
latest`{ items \feed, count? }`the count most-recent items (default 10)
extractLinks{ feed }unique set of all URLs (home + item links + enclosures)
extractCategories{ feed }unique sorted set of all tags/categories

options: { limit } (parsers, cap item count) · { order: 'desc'\|'asc' } (sort/merge) · { dedupe: boolean } (merge, on by default — keys on id then link then title).

Every tool takes ONE args object (so an HTTP POST body maps 1:1). Invalid input throws a TypeError/Error; an undetectable feed format throws an error tagged status: 422.

Usage

import feeds from './index.js';
const A = feeds.adapters;

// 1. Parse whatever format you were handed
const parsed = A.parse({ feed: someXmlOrJsonString });   // { format, meta, items }

// 2. Convert RSS → JSON Feed
const rss = A.parseRss({ feed: rssXml });
const { feed } = A.toJsonFeed({ items: rss.items, meta: rss.meta });

// 3. Aggregate several sources into one river, newest-first
const river = A.merge({ feeds: [rssXml, atomXml, jsonFeedString] });
const top5 = A.latest({ items: river.items, count: 5 });

// 4. Re-emit an aggregated Atom feed
const { xml } = A.toAtom({ items: top5.items, meta: { title: 'My River' } });

DRY boundary

This pack owns feed SYNDICATION FORMATS — reading and writing the RSS / Atom / JSON Feed grammar and converting between them. It does not fetch over the network and it does not scrape arbitrary HTML: raw HTML extraction, link discovery, sitemap.xml, and robots.txt belong to the scraping pack. If you need to turn a webpage into a feed, scrape with scraping, shape the results, then hand them to feeds (normalizeItemstoRss/toAtom/toJsonFeed). Numeric/date math stays in numbers; this pack only parses/emits the dates a feed standard requires.

Source shared/engines/adapters/domain/feeds/README.md (no-git)markdownjson
Generated from the Leumas repository. Every page cites the file it came from.leumas.techllms.txt