- 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.
106 lines
2.9 KiB
JavaScript
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;
|