Files
jerapah-flow/packages/server/scripts/fetch-rss-feed.js
T
nsrb 43e9370638 feat(scripts): enhance script return structure and context handling
- Introduced a new contract for script returns, requiring an object with `output`, `context`, and `skipRemaining` fields.
- Refactored existing scripts to align with the new return structure, ensuring compatibility with the updated context management.
- Added utility functions for normalizing context and step results, improving the handling of script execution context.
- Updated various scripts (e.g., fetch-binary, fetch-html, fetch-http) to return structured output and context, enhancing data flow and usability.
- Improved error handling for script returns, ensuring clearer feedback when invalid structures are returned.

This update significantly enhances the flexibility and clarity of script interactions within workflows.
2026-08-15 22:32:42 +07:00

106 lines
2.9 KiB
JavaScript

import rssParser from "rss-parser";
import jsonata from "jsonata";
function passContext(ctx) {
if (ctx?.context != null && typeof ctx.context === "object" && !Array.isArray(ctx.context)) {
return { ...ctx.context };
}
return {};
}
function previewValue(value) {
const json = JSON.stringify(value);
if (json.length <= 500) {
return value;
}
return { preview: `${json.slice(0, 500)}...`, truncated: true };
}
async function fetchRssFeed(ctx) {
const url = ctx.config?.url ?? ctx.data?.url;
if (typeof url !== "string" || url.length === 0) {
throw new Error("fetch-rss-feed: url is required (ctx.config.url or ctx.data.url)");
}
const outputVar = ctx.config?.outputVar;
const jsonataExpr = ctx.config?.jsonata;
if (jsonataExpr && (typeof outputVar !== "string" || outputVar.length === 0)) {
throw new Error("fetch-rss-feed: ctx.config.outputVar is required when jsonata is set");
}
log.info({ url }, "fetch-rss-feed: fetching feed");
const parser = new rssParser({
customFields: {
item: [
["media:content", "mediaContent"],
["content:encoded", "contentEncoded"],
],
},
});
const feed = await parser.parseURL(url);
const itemCount = Array.isArray(feed.items) ? feed.items.length : 0;
log.info(
{ title: feed.title, itemCount },
"fetch-rss-feed: fetch complete",
);
/** @type {Record<string, unknown>} */
const output = { rssFeed: feed };
log.info(
{ title: feed.title, itemCount },
"fetch-rss-feed: saved rssFeed",
);
if (jsonataExpr) {
log.info({ outputVar, jsonata: jsonataExpr }, "fetch-rss-feed: evaluating jsonata");
const expression = jsonata(jsonataExpr);
const result = await expression.evaluate(feed);
output[outputVar] = result;
log.info(
{ outputVar, result: previewValue(result) },
"fetch-rss-feed: saved jsonata result",
);
}
return { output, context: { ...passContext(ctx), ...output } };
}
fetchRssFeed.meta = {
description: "Fetch an RSS/Atom feed and optionally transform it with JSONata",
previewConfigKey: "url",
tags: ["RSS"],
config: {
url: { type: "string", required: false, description: "Feed URL (or pass data.url)" },
outputVar: {
type: "string",
required: false,
description: "Required when jsonata is set; key on output and context",
},
jsonata: {
type: "string",
required: false,
description: "JSONata applied to the parsed feed object",
},
},
input: {
url: { type: "string", required: false, description: "Feed URL when config.url is omitted" },
},
output: {
rssFeed: { type: "object", description: "Parsed RSS/Atom feed from rss-parser" },
},
context: {
rssFeed: { type: "object", description: "Same as output.rssFeed (plus outputVar when set)" },
},
example: {
data: {},
config: {
url: "https://selfh.st/rss/",
outputVar: "item",
jsonata: "items[0]",
},
},
};
export default fetchRssFeed;