@push.rocks/smartfeed

A library for creating and parsing various feed formats.

readme.md for @push.rocks/smartfeed

The modern TypeScript library for creating and parsing RSS, Atom, and Podcast feeds 🚀

@push.rocks/smartfeed is a powerful, type-safe feed management library that makes creating and parsing RSS 2.0, Atom 1.0, JSON Feed, and Podcast feeds ridiculously easy. Built with TypeScript from the ground up, it offers comprehensive validation, security features, and supports modern podcast standards including iTunes tags and the Podcast namespace.

Features ✨

Installation

pnpm install @push.rocks/smartfeed

Quick Start

Creating a Basic Feed

import { Smartfeed } from '@push.rocks/smartfeed';

const smartfeed = new Smartfeed();

// Create a feed
const feed = smartfeed.createFeed({
  domain: 'example.com',
  title: 'Tech Insights',
  description: 'Latest insights in technology and innovation',
  category: 'Technology',
  company: 'Example Inc',
  companyEmail: 'hello@example.com',
  companyDomain: 'https://example.com'
});

// Add an item
feed.addItem({
  title: 'TypeScript 5.0 Released',
  timestamp: Date.now(),
  url: 'https://example.com/posts/typescript-5',
  authorName: 'Jane Developer',
  imageUrl: 'https://example.com/images/typescript.jpg',
  content: 'TypeScript 5.0 brings exciting new features...'
});

// Export as RSS, Atom, or JSON
const rss = feed.exportRssFeedString();
const atom = feed.exportAtomFeed();
const json = feed.exportJsonFeed();

Custom Feed URL

You can specify a custom URL for your feed's self-reference instead of the default https://${domain}/feed.xml:

const feed = smartfeed.createFeed({
  domain: 'example.com',
  title: 'My Blog',
  description: 'Latest posts',
  category: 'Technology',
  company: 'Example Inc',
  companyEmail: 'hello@example.com',
  companyDomain: 'https://example.com',
  feedUrl: 'https://cdn.example.com/feeds/main.xml' // Custom feed URL
});

// The feedUrl will be used in:
// - RSS: <atom:link href="..." rel="self">
// - Atom: <link href="..." rel="self">
// - JSON Feed: "feed_url" field

This is particularly useful when your feed is hosted on a CDN or different domain than your main site.

Creating a Podcast Feed

import { Smartfeed } from '@push.rocks/smartfeed';

const smartfeed = new Smartfeed();

const podcast = smartfeed.createPodcastFeed({
  domain: 'podcast.example.com',
  title: 'The Tech Show',
  description: 'Weekly discussions about technology',
  category: 'Technology',
  company: 'Tech Media Inc',
  companyEmail: 'podcast@example.com',
  companyDomain: 'https://example.com',
  // iTunes tags
  itunesCategory: 'Technology',
  itunesAuthor: 'John Host',
  itunesOwner: {
    name: 'John Host',
    email: 'john@example.com'
  },
  itunesImage: 'https://example.com/artwork.jpg',
  itunesExplicit: false,
  itunesType: 'episodic',
  // Podcast 2.0 tags
  podcastGuid: '92f49cf0-db3e-5c17-8f11-9c5bd9e1f7ec', // Permanent GUID
  podcastMedium: 'podcast', // or 'music', 'video', 'film', 'audiobook', 'newsletter', 'blog'
  podcastLocked: true, // Prevent unauthorized imports
  podcastLockOwner: 'john@example.com'
});

// Add an episode
podcast.addEpisode({
  title: 'Episode 42: The Future of AI',
  authorName: 'John Host',
  imageUrl: 'https://example.com/episode42.jpg',
  timestamp: Date.now(),
  url: 'https://example.com/episodes/42',
  content: 'In this episode, we explore the future of artificial intelligence...',
  audioUrl: 'https://example.com/audio/episode42.mp3',
  audioType: 'audio/mpeg',
  audioLength: 45678900, // bytes
  itunesDuration: 3600, // seconds
  itunesEpisode: 42,
  itunesSeason: 2,
  itunesEpisodeType: 'full',
  itunesExplicit: false,
  // Modern podcast features
  persons: [
    { name: 'John Host', role: 'host' },
    { name: 'Jane Guest', role: 'guest', href: 'https://example.com/jane' }
  ],
  transcripts: [
    { url: 'https://example.com/transcripts/ep42.txt', type: 'text/plain' }
  ],
  funding: [
    { url: 'https://example.com/support', message: 'Support the show!' }
  ]
});

// Export podcast RSS with iTunes and Podcast namespace
const podcastRss = podcast.exportPodcastRss();

Parsing Existing Feeds

import { Smartfeed } from '@push.rocks/smartfeed';

const smartfeed = new Smartfeed();

// Parse from URL
const feed = await smartfeed.parseFeedFromUrl('https://example.com/feed.xml');
console.log(feed.title);
console.log(feed.items.map(item => item.title));

// Parse from string
const xmlString = '<rss>...</rss>';
const parsedFeed = await smartfeed.parseFeedFromString(xmlString);

Creating Feeds from Article Arrays

import { Smartfeed } from '@push.rocks/smartfeed';
import type { IArticle } from '@tsclass/tsclass';

const smartfeed = new Smartfeed();

const articles: IArticle[] = [
  // Your article objects conforming to @tsclass/tsclass IArticle interface
];

const feedOptions = {
  domain: 'blog.example.com',
  title: 'My Blog',
  description: 'Thoughts on code and design',
  category: 'Programming',
  company: 'Example Inc',
  companyEmail: 'blog@example.com',
  companyDomain: 'https://example.com'
};

// Creates an Atom feed from articles
const atomFeed = await smartfeed.createFeedFromArticleArray(feedOptions, articles);

API Reference

Smartfeed Class

The main class for creating and parsing feeds.

createFeed(options: IFeedOptions): Feed

Creates a standard feed (RSS/Atom/JSON).

Options:

createPodcastFeed(options: IPodcastFeedOptions): PodcastFeed

Creates a podcast feed with iTunes and Podcast namespace support.

iTunes Options:

Podcast 2.0 Options:

parseFeedFromUrl(url: string): Promise<ParsedFeed>

Parses an RSS or Atom feed from a URL.

parseFeedFromString(xmlString: string): Promise<ParsedFeed>

Parses an RSS or Atom feed from an XML string.

createFeedFromArticleArray(options: IFeedOptions, articles: IArticle[]): Promise<string>

Creates an Atom feed from an array of @tsclass/tsclass article objects.

Feed Class

Represents a feed that can be exported in multiple formats.

addItem(item: IFeedItem): void

Adds an item to the feed.

Item Properties:

exportRssFeedString(): string

Exports the feed as RSS 2.0 XML.

exportAtomFeed(): string

Exports the feed as Atom 1.0 XML.

exportJsonFeed(): string

Exports the feed as JSON Feed 1.0.

PodcastFeed Class

Extends Feed with podcast-specific functionality.

addEpisode(episode: IPodcastItem): void

Adds a podcast episode to the feed.

Episode Properties (in addition to IFeedItem):

exportPodcastRss(): string

Exports the podcast feed as RSS 2.0 with iTunes and Podcast namespace extensions.

Validation & Security

@push.rocks/smartfeed includes comprehensive validation to ensure feed integrity and security:

Best Practices

Feed Item IDs

Feed item IDs should be permanent and never change once published. This allows feed readers to properly track which items have been read:

feed.addItem({
  id: 'post-2024-01-15-typescript-tips', // Permanent ID
  title: 'TypeScript Tips',
  url: 'https://example.com/posts/typescript-tips',
  // ... other fields
});

If you don't provide an id, the url will be used. Make sure URLs don't change for published items.

HTTPS URLs

Always use HTTPS URLs for security and privacy. The library will warn you if HTTP URLs are used:

// ✅ Good
imageUrl: 'https://example.com/image.jpg'

// ⚠️ Will trigger a warning
imageUrl: 'http://example.com/image.jpg'

Podcast Artwork

For podcast feeds, artwork should be:

Podcast 2.0 Compatibility

The library fully supports the Podcast 2.0 namespace, making your feeds compatible with modern podcast platforms like:

Key Podcast 2.0 Features:

These features are included in the RSS export when you use exportPodcastRss().

TypeScript Support

Full TypeScript definitions are included. Import types as needed:

import type {
  IFeedOptions,
  IFeedItem,
  IPodcastFeedOptions,
  IPodcastItem,
  IPodcastOwner,
  IPodcastPerson,
  IPodcastChapter,
  IPodcastTranscript,
  IPodcastFunding
} from '@push.rocks/smartfeed';

Why @push.rocks/smartfeed?

This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the license file within this repository.

Please note: The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.

Trademarks

This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.

Company Information

Task Venture Capital GmbH Registered at District court Bremen HRB 35230 HB, Germany

By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.

changelog.md for @push.rocks/smartfeed

2025-11-01 - 1.4.0 - feat(feed)

Support custom feedUrl for feeds and use it as the self-link in RSS/Atom/JSON; update docs

2025-10-31 - 1.3.0 - feat(parsing)

Replace rss-parser with fast-xml-parser and add native feed parser; update Smartfeed to use parseFeedXML and adjust plugins/tests

2025-10-31 - 1.2.0 - feat(podcast)

Add Podcast 2.0 support and remove external 'feed' dependency; implement internal RSS/Atom/JSON generators and update tests/README

2025-10-31 - 1.1.1 - fix(podcast)

Improve podcast episode validation, make Feed.itemIds protected, expand README and add tests

2025-10-31 - 1.1.0 - feat(smartfeed)

Implement Smartfeed core: add feed validation, parsing, exporting and comprehensive tests

2025-10-31 - 1.0.11 - smartfeed / feed

Add feed and validation utilities for the smartfeed plugin and perform related dependency, refactor, test, and CI updates.

2020-10-25 to 2024-05-29 - 1.0.1..1.0.11 - housekeeping

Collection of minor releases, metadata updates and routine fixes made across multiple intermediate versions.