feat(feed): Support custom feedUrl for feeds and use it as the self-link in RSS/Atom/JSON; update docs
This commit is contained in:
@@ -1,5 +1,14 @@
|
||||
# Changelog
|
||||
|
||||
## 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
|
||||
|
||||
- Add optional feedUrl option to IFeedOptions (ts/classes.feed.ts).
|
||||
- Use feedUrl as the atom:link rel="self" href in RSS and as the <link rel="self"> in Atom when provided.
|
||||
- Expose feedUrl as the JSON Feed "feed_url" value (ts/classes.feed.ts).
|
||||
- PodcastFeed now uses podcastOptions.feedUrl for its atom self-link (ts/classes.podcast.ts).
|
||||
- Update README: add a Custom Feed URL section and mention feedUrl in the API docs (readme.md).
|
||||
|
||||
## 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
|
||||
|
||||
|
||||
26
readme.md
26
readme.md
@@ -7,6 +7,7 @@
|
||||
## Features ✨
|
||||
|
||||
- 🎯 **Full TypeScript Support** - Complete type definitions for all feed formats
|
||||
- 🌐 **Cross-Platform** - Works in Node.js, Bun, Deno, and browsers
|
||||
- 📡 **Multiple Feed Formats** - RSS 2.0, Atom 1.0, JSON Feed 1.0, and Podcast RSS
|
||||
- 🎙️ **Modern Podcast Support** - iTunes tags, Podcast 2.0 namespace (guid, medium, locked, persons, transcripts, funding)
|
||||
- 🔒 **Built-in Validation** - Comprehensive validation for URLs, emails, domains, and timestamps
|
||||
@@ -57,6 +58,30 @@ 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`:
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```typescript
|
||||
@@ -183,6 +208,7 @@ Creates a standard feed (RSS/Atom/JSON).
|
||||
- `company` (string) - Company/organization name
|
||||
- `companyEmail` (string) - Contact email
|
||||
- `companyDomain` (string) - Company website URL (absolute)
|
||||
- `feedUrl` (string, optional) - Custom URL for the feed's self-reference (defaults to `https://${domain}/feed.xml`)
|
||||
|
||||
#### `createPodcastFeed(options: IPodcastFeedOptions): PodcastFeed`
|
||||
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@push.rocks/smartfeed',
|
||||
version: '1.3.0',
|
||||
version: '1.4.0',
|
||||
description: 'A library for creating and parsing various feed formats.'
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ export interface IFeedOptions {
|
||||
companyEmail: string;
|
||||
/** The company website URL (must be absolute) */
|
||||
companyDomain: string;
|
||||
/** Optional: Custom URL for the feed's atom:link rel="self" (defaults to https://${domain}/feed.xml) */
|
||||
feedUrl?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,7 +188,8 @@ export class Feed {
|
||||
rss += `<category>${this.escapeXml(this.options.category)}</category>\n`;
|
||||
|
||||
// Atom self link
|
||||
rss += `<atom:link href="https://${this.options.domain}/feed.xml" rel="self" type="application/rss+xml" />\n`;
|
||||
const selfUrl = this.options.feedUrl || `https://${this.options.domain}/feed.xml`;
|
||||
rss += `<atom:link href="${selfUrl}" rel="self" type="application/rss+xml" />\n`;
|
||||
|
||||
// Items
|
||||
for (const item of this.items) {
|
||||
@@ -221,7 +224,8 @@ export class Feed {
|
||||
atom += `<title>${this.escapeXml(this.options.title)}</title>\n`;
|
||||
atom += `<subtitle>${this.escapeXml(this.options.description)}</subtitle>\n`;
|
||||
atom += `<link href="https://${this.options.domain}" />\n`;
|
||||
atom += `<link href="https://${this.options.domain}/feed.xml" rel="self" />\n`;
|
||||
const selfUrl = this.options.feedUrl || `https://${this.options.domain}/feed.xml`;
|
||||
atom += `<link href="${selfUrl}" rel="self" />\n`;
|
||||
atom += `<updated>${this.formatIso8601Date(new Date())}</updated>\n`;
|
||||
atom += `<generator>@push.rocks/smartfeed</generator>\n`;
|
||||
atom += '<author>\n';
|
||||
@@ -265,7 +269,7 @@ export class Feed {
|
||||
version: 'https://jsonfeed.org/version/1',
|
||||
title: this.options.title,
|
||||
home_page_url: `https://${this.options.domain}`,
|
||||
feed_url: `https://${this.options.domain}/feed.json`,
|
||||
feed_url: this.options.feedUrl || `https://${this.options.domain}/feed.json`,
|
||||
description: this.options.description,
|
||||
icon: '',
|
||||
favicon: '',
|
||||
|
||||
@@ -369,7 +369,8 @@ export class PodcastFeed extends Feed {
|
||||
rss += `<lastBuildDate>${new Date().toUTCString()}</lastBuildDate>\n`;
|
||||
|
||||
// Atom self link
|
||||
rss += `<atom:link href="https://${this.podcastOptions.domain}/feed.xml" rel="self" type="application/rss+xml" />\n`;
|
||||
const selfUrl = this.podcastOptions.feedUrl || `https://${this.podcastOptions.domain}/feed.xml`;
|
||||
rss += `<atom:link href="${selfUrl}" rel="self" type="application/rss+xml" />\n`;
|
||||
|
||||
// iTunes channel tags
|
||||
rss += `<itunes:author>${this.escapeXml(this.podcastOptions.itunesAuthor)}</itunes:author>\n`;
|
||||
|
||||
Reference in New Issue
Block a user