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.
This commit is contained in:
2026-08-15 22:32:42 +07:00
parent e8e1cf383d
commit 43e9370638
36 changed files with 766 additions and 337 deletions
+12 -9
View File
@@ -1,10 +1,11 @@
import rssParser from "rss-parser";
import jsonata from "jsonata";
function ensureDataObject(ctx) {
if (ctx.data == null || typeof ctx.data !== "object" || Array.isArray(ctx.data)) {
ctx.data = {};
function passContext(ctx) {
if (ctx?.context != null && typeof ctx.context === "object" && !Array.isArray(ctx.context)) {
return { ...ctx.context };
}
return {};
}
function previewValue(value) {
@@ -28,8 +29,6 @@ async function fetchRssFeed(ctx) {
throw new Error("fetch-rss-feed: ctx.config.outputVar is required when jsonata is set");
}
ensureDataObject(ctx);
log.info({ url }, "fetch-rss-feed: fetching feed");
const parser = new rssParser({
customFields: {
@@ -46,7 +45,8 @@ async function fetchRssFeed(ctx) {
"fetch-rss-feed: fetch complete",
);
ctx.data.rssFeed = feed;
/** @type {Record<string, unknown>} */
const output = { rssFeed: feed };
log.info(
{ title: feed.title, itemCount },
"fetch-rss-feed: saved rssFeed",
@@ -56,14 +56,14 @@ async function fetchRssFeed(ctx) {
log.info({ outputVar, jsonata: jsonataExpr }, "fetch-rss-feed: evaluating jsonata");
const expression = jsonata(jsonataExpr);
const result = await expression.evaluate(feed);
ctx.data[outputVar] = result;
output[outputVar] = result;
log.info(
{ outputVar, result: previewValue(result) },
"fetch-rss-feed: saved jsonata result",
);
}
return ctx;
return { output, context: { ...passContext(ctx), ...output } };
}
fetchRssFeed.meta = {
@@ -75,7 +75,7 @@ fetchRssFeed.meta = {
outputVar: {
type: "string",
required: false,
description: "Required when jsonata is set; destination on ctx.data",
description: "Required when jsonata is set; key on output and context",
},
jsonata: {
type: "string",
@@ -89,6 +89,9 @@ fetchRssFeed.meta = {
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: {