RSS API
Manages RSS feed cache invalidation for the RSS Feed Worker.
Base Path: /api/rss
Authentication: Requires Bearer token.
Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
POST | /invalidate | Yes | Invalidate RSS cache for podcast |
Invalidate RSS Cache
Triggers cache invalidation for a podcast's RSS feed.
POST /api/rss/invalidateRequest Body:
{
"slug": "the-tech-show",
"podcast_id": "uuid",
"episode_id": "uuid",
"reason": "episode.published",
"immediate": true,
"delay_seconds": 0
}Only slug is required. delay_seconds (0-43200) defers the invalidation via Cloudflare Queues — used to schedule cache rebuilds at a known future moment (e.g. when an email-visibility window expires). When set, HTTP is bypassed; the queue is authoritative.
Response:
{
"success": true,
"method": "queue"
}Invalidation Methods
| Method | Description | When Used |
|---|---|---|
queue | Message sent to invalidation queue | Production (Workers available) |
http | Direct HTTP request to RSS Worker | Development/fallback |
skipped | No action taken | Queue/worker unavailable |
Automatic Invalidation
RSS cache is automatically invalidated when content that affects the feed changes. The reason field in the queue message identifies the trigger and is emitted by the helper in src/lib/utils/rss-invalidate.ts:
type InvalidationReason =
| 'podcast.info.updated'
| 'podcast.classification.updated'
| 'podcast.status.updated'
| 'podcast.image.updated'
| 'podcast.ownership.updated'
| 'podcast.advanced.updated'
| 'podcast.funding.updated'
| 'podcast.email_visibility.updated'
| 'podcast.email_visibility.expired'
| 'podcast.disclosure.updated'
| 'episode.published'
| 'episode.updated'
| 'episode.deleted'
| 'episode.credits.updated'
| 'episode.soundbites.updated'
| 'episode.disclosure.updated'
| 'manual.invalidation';The Podcast Import Executor worker additionally sends a single import.completed message from its finalisation path when a back-catalogue import closes its last item.
Queue Message Format
interface RssInvalidationMessage {
type: string; // reason string, e.g. 'episode.published' or 'import.completed'
podcast_id: string;
podcast_slug: string;
episode_id?: string;
timestamp: string;
}Cache Strategy
TypeScript Client Usage
import { createApiClient } from '$api/client';
const client = createApiClient(fetch);
// Invalidate RSS cache
const res = await client.api.rss.invalidate.$post(
{
json: {
podcast_id: 'uuid',
podcast_slug: 'the-tech-show'
}
},
{
headers: { Authorization: `Bearer ${token}` }
}
);Utility Functions
Helpers live in src/lib/utils/rss-invalidate.ts. They authenticate via the RSS_INVALIDATION_SECRET environment secret, so they can be called from +page.server.ts actions without a user token. All helpers are no-ops when hosting_type === 'external'.
// src/lib/utils/rss-invalidate.ts
export async function invalidateRssFeed(
fetch: typeof globalThis.fetch,
options: {
slug: string;
podcastId?: string;
episodeId?: string;
reason?: InvalidationReason;
immediate?: boolean; // default true
delaySeconds?: number; // max 43200 (12h)
}
): Promise<{ success: boolean; method: 'queue' | 'http' | 'skipped'; error?: string }>;
// Convenience wrappers
export async function invalidateAfterPodcastUpdate(fetch, podcast, reason): Promise<void>;
export async function invalidateAfterEpisodeUpdate(
fetch,
podcast,
episodeId,
reason
): Promise<void>;
export async function invalidateMultipleRssFeeds(fetch, slugs, reason): Promise<boolean>;Example (form action after publishing an episode):
import { invalidateAfterEpisodeUpdate } from '$lib/utils/rss-invalidate';
await invalidateAfterEpisodeUpdate(fetch, podcast, episodeId, 'episode.published');The two wrappers log failures via console.warn/console.error but never throw — RSS cache invalidation is a non-critical path and must never block the main operation.
Related
- RSS Feed Worker - Feed generation
- Cloudflare Queues - Queue infrastructure