diff --git a/actions/hello.js b/actions/hello.js index 2c029d4..1f16800 100644 --- a/actions/hello.js +++ b/actions/hello.js @@ -3,28 +3,38 @@ * Hello Action - Node.js Example Pack * * A minimal Node.js action that returns "Hello, Node.js". - * Demonstrates the basic structure of a Node.js action in Attune. + * Demonstrates the basic structure of a self-contained action in Attune. * - * When invoked via the Node.js wrapper, the `run` export is called - * with the action parameters as its argument. + * Actions receive parameters as JSON on stdin and write results to stdout. */ "use strict"; -/** - * Return a simple greeting message. - * @param {object} params - Action parameters (unused). - * @returns {{ message: string }} - */ -function run(params) { - return { message: "Hello, Node.js" }; +function main() { + let data = ""; + process.stdin.setEncoding("utf8"); + process.stdin.on("readable", () => { + let chunk; + while ((chunk = process.stdin.read()) !== null) { + data += chunk; + } + }); + process.stdin.on("end", () => { + // Parse the first line as JSON parameters + const firstLine = data.split("\n")[0].trim(); + let params = {}; + if (firstLine) { + try { + params = JSON.parse(firstLine); + } catch { + // ignore parse errors, use empty params + } + } + + const name = params.name || "Node.js"; + const result = { message: `Hello, ${name}` }; + process.stdout.write(JSON.stringify(result) + "\n"); + }); } -// Direct execution support (without the wrapper) -if (require.main === module) { - const result = run({}); - process.stdout.write(JSON.stringify({ result, status: "success" }) + "\n"); - process.exit(0); -} - -module.exports = { run }; +main(); diff --git a/actions/http_example.js b/actions/http_example.js index 7cd7518..d15a9d8 100644 --- a/actions/http_example.js +++ b/actions/http_example.js @@ -2,25 +2,79 @@ /** * HTTP Example Action - Node.js Example Pack * - * Demonstrates using the `node-fetch` library to make an HTTP call to example.com. - * Receives parameters via the Node.js wrapper (stdin JSON with code_path). + * Demonstrates using the built-in https/http modules to make an HTTP call. + * Receives parameters via stdin as JSON. */ -const fetch = require("node-fetch"); +"use strict"; -async function run(params) { - const url = params.url || "https://example.com"; +const https = require("https"); +const http = require("http"); +const { URL } = require("url"); - const response = await fetch(url, { timeout: 10000 }); - const text = await response.text(); +function fetchUrl(url, timeout) { + return new Promise((resolve, reject) => { + const parsed = new URL(url); + const mod = parsed.protocol === "https:" ? https : http; - return { - status_code: response.status, - url: response.url, - content_length: text.length, - snippet: text.slice(0, 500), - success: response.ok, - }; + const req = mod.get(url, { timeout }, (res) => { + let body = ""; + res.on("data", (chunk) => { + body += chunk; + }); + res.on("end", () => { + resolve({ + status_code: res.statusCode, + url: url, + content_length: body.length, + snippet: body.slice(0, 500), + success: res.statusCode >= 200 && res.statusCode < 400, + }); + }); + }); + + req.on("error", (err) => reject(err)); + req.on("timeout", () => { + req.destroy(); + reject(new Error("Request timed out")); + }); + }); } -module.exports = { run }; +function main() { + let data = ""; + process.stdin.setEncoding("utf8"); + process.stdin.on("readable", () => { + let chunk; + while ((chunk = process.stdin.read()) !== null) { + data += chunk; + } + }); + process.stdin.on("end", async () => { + // Parse the first line as JSON parameters + const firstLine = data.split("\n")[0].trim(); + let params = {}; + if (firstLine) { + try { + params = JSON.parse(firstLine); + } catch { + // ignore parse errors, use empty params + } + } + + const url = params.url || "https://example.com"; + const timeout = (params.timeout || 10) * 1000; + + try { + const result = await fetchUrl(url, timeout); + process.stdout.write(JSON.stringify(result) + "\n"); + } catch (err) { + process.stderr.write( + JSON.stringify({ error: err.message || String(err) }) + "\n", + ); + process.exit(1); + } + }); +} + +main(); diff --git a/actions/read_counter.js b/actions/read_counter.js index 677dbf9..26fc510 100644 --- a/actions/read_counter.js +++ b/actions/read_counter.js @@ -5,26 +5,42 @@ * Consumes a counter value (typically from the counter sensor trigger payload) * and returns a formatted message containing the counter value. * - * Parameters are delivered via stdin as JSON from the Node.js wrapper. + * Parameters are delivered via stdin as JSON. */ "use strict"; -/** - * @param {object} params - * @param {number} params.counter - The counter value from the trigger payload. - * @param {string} params.rule_ref - The rule reference the counter is scoped to. - * @returns {object} Formatted message and raw counter value. - */ -function run(params) { - const counter = params.counter !== undefined ? params.counter : 0; - const ruleRef = params.rule_ref || "unknown"; +function main() { + let data = ""; + process.stdin.setEncoding("utf8"); + process.stdin.on("readable", () => { + let chunk; + while ((chunk = process.stdin.read()) !== null) { + data += chunk; + } + }); + process.stdin.on("end", () => { + // Parse the first line as JSON parameters + const firstLine = data.split("\n")[0].trim(); + let params = {}; + if (firstLine) { + try { + params = JSON.parse(firstLine); + } catch { + // ignore parse errors, use empty params + } + } - return { - message: `Counter value is ${counter} (from rule: ${ruleRef})`, - counter: counter, - rule_ref: ruleRef, - }; + const counter = params.counter !== undefined ? params.counter : 0; + const ruleRef = params.rule_ref || "unknown"; + + const result = { + message: `Counter value is ${counter} (from rule: ${ruleRef})`, + counter: counter, + rule_ref: ruleRef, + }; + process.stdout.write(JSON.stringify(result) + "\n"); + }); } -module.exports = { run }; +main();