Migrating from 2.x to 3.x
This guide covers all breaking changes when upgrading from Feedsmith 2.x to 3.x. Each breaking change is detailed with specific upgrade steps and examples.
IMPORTANT
Version 3.x inverts the default behavior: feeds are now lenient by default (all fields optional), with strict mode available as an opt-in via { strict: true }.
Installation
Update your package to the latest 3.x version:
npm install feedsmith@latestBreaking Changes
Strict Mode Now Opt-In
In version 2.x, generate functions enforced spec-required fields by default and to make all fields optional, it required passing { lenient: true }. In 3.x, this is inverted: all fields are optional by default and { strict: true } enables compile-time validation of spec-required fields.
Before (2.x)
import { generateRssFeed } from 'feedsmith'
// Strict mode (default) - required fields and Date objects
const xml = generateRssFeed({
title: 'My Blog',
description: 'A blog about things',
pubDate: new Date('2024-01-01'),
})
// Lenient mode - all optional, string dates accepted
const xml = generateRssFeed({
title: 'My Blog',
pubDate: '2024-01-01T00:00:00Z',
}, { lenient: true })After (3.x)
import { generateRssFeed } from 'feedsmith'
// Lenient mode (default) - all optional, string dates accepted
const xml = generateRssFeed({
title: 'My Blog',
pubDate: '2024-01-01T00:00:00Z',
})
// Strict mode - required fields and Date objects
const xml = generateRssFeed({
title: 'My Blog',
description: 'A blog about things',
pubDate: new Date('2024-01-01'),
}, { strict: true })Migration Steps
- Remove
{ lenient: true }from all generate function calls (it's now the default) - Add
{ strict: true }if you want to preserve v2's default strict behavior
All Type Fields Now Optional by Default
Related to the above, previously required fields in type definitions are now optional by default. Pass true as the strict type parameter if you need compile-time enforcement.
Before (2.x)
import type { Atom } from 'feedsmith/types'
// TypeScript enforced required fields
const entry: Atom.Entry<Date> = {
id: 'https://example.com/post/1',
title: 'Post Title',
updated: new Date('2024-01-01'),
}After (3.x)
import type { Atom } from 'feedsmith'
// All fields optional by default
const entry: Atom.Entry<Date> = {
title: 'Post Title',
}
// Pass `true` for compile-time enforcement
const strictEntry: Atom.Entry<Date, true> = {
id: 'https://example.com/post/1',
title: 'Post Title',
updated: new Date('2024-01-01'),
}Migration Steps
- If you relied on TypeScript to enforce required fields, add
trueas the last type parameter - Alternatively, add runtime validation for required fields
DeepPartial Type Removed
The DeepPartial utility type has been removed. Since all type fields are now optional by default, this type is no longer needed.
Before (2.x)
import type { DeepPartial, Rss } from 'feedsmith/types'
const processFeed = (feed: DeepPartial<Rss.Feed<string>>) => {
console.log(feed.title)
}After (3.x)
import type { Rss } from 'feedsmith'
// All fields already optional - DeepPartial not needed
const processFeed = (feed: Rss.Feed<string>) => {
console.log(feed.title)
}Migration Steps
- Remove
DeepPartialfrom your imports - Use base types directly (
Rss.Feed,Atom.Feed, etc.)
Types Entry Point Removed
The feedsmith/types entry point has been removed. All types are now exported from the main feedsmith entry point. Additionally, deprecated type aliases (RssFeed, AtomFeed, JsonFeed, RdfFeed, Opml) have been removed.
Before (2.x)
import type { Rss } from 'feedsmith/types'
import { parseRssFeed } from 'feedsmith'After (3.x)
import { type Rss, parseRssFeed } from 'feedsmith'Migration Steps
- Change
feedsmith/typesimports tofeedsmith - Replace deprecated type aliases:
RssFeed→Rss.Feed,AtomFeed→Atom.Feed, etc.
Media Namespace: Deprecated Field Removed
The deprecated group field has been removed to align with the Media RSS specification:
group→groups(spec allows multiplemedia:groupelements)
Before (2.x)
const feed = parseRssFeed(xml)
const group = feed.media?.groupAfter (3.x)
const feed = parseRssFeed(xml)
const group = feed.media?.groups?.[0]Migration Steps
- Replace
groupwithgroups - Access the first element:
media.group→media.groups?.[0]
Podcast Namespace: Deprecated Fields Removed
Deprecated fields have been removed to align with the Podcasting 2.0 specification:
location→locations(spec allows multiplepodcast:locationelements)value→values(spec allows multiplepodcast:valueelements)chats→chat(spec allows only onepodcast:chatelement)
Before (2.x)
const feed = parseRssFeed(xml)
const location = feed.items?.[0]?.podcast?.location
const value = feed.items?.[0]?.podcast?.value
const chat = feed.items?.[0]?.podcast?.chats?.[0]After (3.x)
const feed = parseRssFeed(xml)
const location = feed.items?.[0]?.podcast?.locations?.[0]
const value = feed.items?.[0]?.podcast?.values?.[0]
const chat = feed.items?.[0]?.podcast?.chatMigration Steps
- Replace
locationwithlocations(wrap in array) - Replace
valuewithvalues(wrap in array) - Replace
chatswithchat(usechats[0]if you had multiple)
Dublin Core Namespace: Singular Fields Removed
Deprecated singular fields have been removed to align with the Dublin Core specification where all elements are repeatable:
title→titlescreator→creatorssubject→subjectsdescription→descriptionspublisher→publisherscontributor→contributorsdate→datestype→typesformat→formatsidentifier→identifierssource→sourceslanguage→languagesrelation→relationscoverage(now array)rights(now array)
Before (2.x)
const feed = parseRssFeed(xml)
const title = feed.dc?.title
const creator = feed.dc?.creator
const coverage = feed.dc?.coverageAfter (3.x)
const feed = parseRssFeed(xml)
const title = feed.dc?.titles?.[0]
const creator = feed.dc?.creators?.[0]
const coverage = feed.dc?.coverage?.[0]Migration Steps
- Replace singular fields with plural equivalents (e.g.,
dc.title→dc.titles?.[0]) - Fields that kept their name (
coverage,rights) are now arrays:dc.coverage→dc.coverage?.[0]
Dublin Core Terms Namespace: Singular Fields Removed
Deprecated singular fields have been removed to align with the Dublin Core Terms specification where all elements are repeatable:
title→titlescreator→creatorssubject→subjectsdescription→descriptionspublisher→publisherscontributor→contributorsdate→datestype→typesformat→formatsidentifier→identifierssource→sourceslanguage→languagesrelation→relationsabstract→abstractsaudience→audiencesalternative→alternativeseducationLevel→educationLevelsextent→extentshasFormat→hasFormatshasPart→hasPartshasVersion→hasVersionsinstructionalMethod→instructionalMethodslicense→licensesmediator→mediatorsmedium→mediumsprovenance→provenancesrightsHolder→rightsHoldersspatial→spatialstemporal→temporalsaccrualMethod→accrualMethodsaccrualPeriodicity→accrualPeriodicitiesaccrualPolicy→accrualPoliciesbibliographicCitation→bibliographicCitations- Plus 21 fields that kept their name but are now arrays (e.g.,
created,modified,issued,valid)
Before (2.x)
const feed = parseRssFeed(xml)
const title = feed.dcterms?.title
const creator = feed.dcterms?.creator
const created = feed.dcterms?.createdAfter (3.x)
const feed = parseRssFeed(xml)
const title = feed.dcterms?.titles?.[0]
const creator = feed.dcterms?.creators?.[0]
const created = feed.dcterms?.created?.[0]Migration Steps
- Replace singular fields with plural equivalents (e.g.,
dcterms.title→dcterms.titles?.[0]) - Fields that kept their name (e.g.,
created,modified) are now arrays:dcterms.created→dcterms.created?.[0]
New Features
Namespace Type Exports
All namespace types are now exported directly from the main package:
import type { ItunesNs, DcNs, MediaNs, PodcastNs } from 'feedsmith'
const category: ItunesNs.Category = {
text: 'Technology'
}
const transcript: PodcastNs.Transcript = {
url: 'https://example.com/transcript.srt',
type: 'application/srt'
}See Working with TypeScript for the more information and usage examples.
XML Namespace Support
Version 3.x adds support for the XML namespace (xml:* attributes) in RSS, Atom, and RDF feeds. The xml property is available on both feed and item levels, providing access to xml:lang, xml:base, xml:space, and xml:id attributes.
Migration Checklist
Use this checklist to ensure a complete migration:
- Remove
{ lenient: true }from all generate function calls - Add
{ strict: true }where you need compile-time validation of required fields - Update type parameters if using strict types directly (add
trueas last parameter) - Remove
DeepPartialfrom imports - Change
feedsmith/typesimports tofeedsmith - Replace Media namespace deprecated field (
group→groups) - Replace Podcast namespace deprecated fields (
location→locations,value→values,chats→chat) - Replace Dublin Core singular fields with plural arrays (e.g.,
title→titles) - Replace Dublin Core Terms singular fields with plural arrays (e.g.,
title→titles) - Test feed generation to ensure output is correct