{ "kind": "open-flow-workflow", "version": 1, "name": "Email Hacker News Headlines as a Spreadsheet", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_6fa33fbec7df1a35": { "name": "Enter the email addresses", "kind": "start", "inputDefs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "from" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "to" } ] }, "n_602ccf8df7f5d2a6": { "inputs": { "from": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_6fa33fbec7df1a35", "output": "from" } ] }, "to": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_6fa33fbec7df1a35", "output": "to" } ] } }, "name": "Prepare email addresses", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "from" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "to" } ], "outputs": [ { "jsonSchema": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "The sender email address." }, "name": { "type": "string", "minLength": 1, "description": "The optional sender display name." } }, "required": [ "email" ], "additionalProperties": false, "description": "The verified sender used for this email." }, "nullable": false, "handle": "from" }, { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "The recipient email address." }, "name": { "type": "string", "minLength": 1, "description": "The optional recipient display name." } }, "required": [ "email" ], "additionalProperties": false, "description": "One SendGrid email recipient." }, "minItems": 1, "description": "The primary recipients for this email." }, "nullable": false, "handle": "to" } ], "name": "Prepare email addresses", "moduleId": "n_a1e6a7215fbfa67e", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_ec9cdce7ac986c83": { "inputs": { "url": { "kind": "value", "value": "https://news.ycombinator.com/" } }, "name": "Get the Hacker News front page", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" } ], "outputs": [ { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" } ], "name": "Get the Hacker News front page", "executor": { "method": "GET", "query": { "mode": "fields", "names": [] }, "headers": { "mode": "fields", "names": [] }, "bodyFormat": "none", "authentication": { "type": "none" }, "responseFormat": "text", "statusPolicy": "success", "kind": "http-request" } } }, "n_4e12f750948ec26c": { "inputs": { "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_ec9cdce7ac986c83", "output": "body" } ] } }, "name": "Extract titles and links", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": true, "handle": "body" } ], "outputs": [ { "jsonSchema": { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "array", "items": { "anyOf": [ { "type": "string", "description": "A union variant." }, { "type": "number", "description": "A union variant." }, { "type": "boolean", "description": "A union variant." }, { "const": null, "description": "A union variant." } ], "description": "A scalar worksheet cell value." }, "description": "An array item." }, "description": "Worksheet rows represented as arrays of cell values." }, "description": "Optional mapping of worksheet names to row data." }, "nullable": true, "handle": "worksheetData" }, { "jsonSchema": { "type": "string", "minLength": 1, "description": "Workbook path including the file name, relative to the drive root and ending with .xlsx." }, "nullable": false, "handle": "path" } ], "name": "Extract titles and links", "moduleId": "n_ba5cb35a746bcd0c", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_6d79d64ebfcff641": { "inputs": { "path": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_4e12f750948ec26c", "output": "path" } ] }, "worksheetData": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_4e12f750948ec26c", "output": "worksheetData" } ] } }, "name": "Create the workbook", "kind": "task", "task": { "inputs": [ { "description": "Workbook path including the file name, relative to the drive root and ending with .xlsx.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Workbook path including the file name, relative to the drive root and ending with .xlsx." }, "nullable": false, "handle": "path" }, { "description": "Optional drive ID. Leave empty to use the current user's default OneDrive.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Optional drive ID. Leave empty to use the current user's default OneDrive." }, "nullable": true, "handle": "driveId", "value": null }, { "description": "Optional drive ID. Leave empty to use the current user's default OneDrive.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Optional drive ID. Leave empty to use the current user's default OneDrive." }, "nullable": true, "handle": "drive_id", "value": null }, { "description": "Optional mapping of worksheet names to row data.", "jsonSchema": { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "array", "items": { "anyOf": [ { "type": "string", "description": "A union variant." }, { "type": "number", "description": "A union variant." }, { "type": "boolean", "description": "A union variant." }, { "const": null, "description": "A union variant." } ], "description": "A scalar worksheet cell value." }, "description": "An array item." }, "description": "Worksheet rows represented as arrays of cell values." }, "description": "Optional mapping of worksheet names to row data." }, "nullable": true, "handle": "worksheetData", "value": null }, { "description": "Alias of worksheetData.", "jsonSchema": { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "array", "items": { "anyOf": [ { "type": "string", "description": "A union variant." }, { "type": "number", "description": "A union variant." }, { "type": "boolean", "description": "A union variant." }, { "const": null, "description": "A union variant." } ], "description": "A scalar worksheet cell value." }, "description": "An array item." }, "description": "Worksheet rows represented as arrays of cell values." }, "description": "Alias of worksheetData." }, "nullable": true, "handle": "worksheet_data", "value": null }, { "description": "Optional worksheet names to create in order.", "jsonSchema": { "type": "array", "items": { "type": "string", "minLength": 1, "description": "Schema for nonEmptyString." }, "description": "Optional worksheet names to create in order." }, "nullable": true, "handle": "worksheetNames", "value": null }, { "description": "Alias of worksheetNames.", "jsonSchema": { "type": "array", "items": { "type": "string", "minLength": 1, "description": "Schema for nonEmptyString." }, "description": "Alias of worksheetNames." }, "nullable": true, "handle": "worksheet_names", "value": null } ], "outputs": [ { "description": "Drive item summary returned by Microsoft Graph.", "jsonSchema": { "type": "object", "properties": { "id": { "type": "string", "description": "Drive item ID." }, "name": { "type": "string", "description": "Drive item name." }, "webUrl": { "type": "string", "description": "Web URL for the drive item." }, "createdDateTime": { "type": "string", "description": "Creation timestamp for the drive item." }, "lastModifiedDateTime": { "type": "string", "description": "Last modification timestamp for the drive item." }, "size": { "type": "integer", "description": "Drive item size in bytes." }, "file": { "type": "object", "properties": {}, "additionalProperties": true, "description": "File facet returned by Microsoft Graph." }, "folder": { "type": "object", "properties": {}, "additionalProperties": true, "description": "Folder facet returned by Microsoft Graph." }, "workbook": { "type": "object", "properties": {}, "additionalProperties": true, "description": "Workbook facet returned by Microsoft Graph." }, "parentReference": { "type": "object", "properties": { "driveId": { "type": "string", "description": "Parent drive ID." }, "id": { "type": "string", "description": "Parent item ID." }, "path": { "type": "string", "description": "Parent path reference." } }, "additionalProperties": true, "description": "Parent reference for the drive item." } }, "required": [ "id", "name" ], "additionalProperties": true, "description": "Drive item summary returned by Microsoft Graph." }, "nullable": false, "handle": "output" } ], "name": "Create the workbook", "executor": { "kind": "connector", "action": "excel.create_workbook", "outputMode": "value" } } }, "n_0b196b84c8bff087": { "inputs": { "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_6d79d64ebfcff641", "output": "output" } ] } }, "name": "Read the workbook ID", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "object", "properties": { "id": { "type": "string", "description": "Drive item ID." }, "name": { "type": "string", "description": "Drive item name." }, "webUrl": { "type": "string", "description": "Web URL for the drive item." }, "createdDateTime": { "type": "string", "description": "Creation timestamp for the drive item." }, "lastModifiedDateTime": { "type": "string", "description": "Last modification timestamp for the drive item." }, "size": { "type": "integer", "description": "Drive item size in bytes." }, "file": { "type": "object", "properties": {}, "additionalProperties": true, "description": "File facet returned by Microsoft Graph." }, "folder": { "type": "object", "properties": {}, "additionalProperties": true, "description": "Folder facet returned by Microsoft Graph." }, "workbook": { "type": "object", "properties": {}, "additionalProperties": true, "description": "Workbook facet returned by Microsoft Graph." }, "parentReference": { "type": "object", "properties": { "driveId": { "type": "string", "description": "Parent drive ID." }, "id": { "type": "string", "description": "Parent item ID." }, "path": { "type": "string", "description": "Parent path reference." } }, "additionalProperties": true, "description": "Parent reference for the drive item." } }, "required": [ "id", "name" ], "additionalProperties": true, "description": "Drive item summary returned by Microsoft Graph." }, "nullable": false, "handle": "body" } ], "outputs": [ { "jsonSchema": { "type": "string", "minLength": 1, "description": "OneDrive drive item ID." }, "nullable": false, "handle": "id" } ], "name": "Read the workbook ID", "moduleId": "n_c3c53eab5e6b7472", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_2f2be65639b80453": { "inputs": { "itemId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_0b196b84c8bff087", "output": "id" } ] } }, "name": "Download the workbook", "kind": "task", "task": { "inputs": [ { "description": "Optional drive ID. Leave empty to use the authenticated user's default OneDrive.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Optional drive ID. Leave empty to use the authenticated user's default OneDrive." }, "nullable": true, "handle": "driveId", "value": null }, { "description": "OneDrive drive item ID.", "jsonSchema": { "type": "string", "minLength": 1, "description": "OneDrive drive item ID." }, "nullable": false, "handle": "itemId" }, { "description": "Optional format to convert the file into before download.", "jsonSchema": { "type": "string", "enum": [ "pdf", "html" ], "description": "Optional format to convert the file into before download." }, "nullable": true, "handle": "format", "value": null }, { "description": "Optional file name to use for the downloaded transit file.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Optional file name to use for the downloaded transit file." }, "nullable": true, "handle": "fileName", "value": null }, { "description": "Optional eTag or cTag used for conditional download requests.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Optional eTag or cTag used for conditional download requests." }, "nullable": true, "handle": "ifNoneMatch", "value": null } ], "outputs": [ { "description": "The downloaded file uploaded to transit storage, or null when not modified.", "jsonSchema": { "type": [ "object", "null" ], "properties": { "name": { "type": "string", "description": "The downloaded file name." }, "mimetype": { "type": "string", "description": "The MIME type of the downloaded file." }, "s3url": { "type": "string", "description": "The transit URL for downloading the file." } }, "required": [ "name", "mimetype", "s3url" ], "additionalProperties": false, "description": "The downloaded file uploaded to transit storage, or null when not modified." }, "nullable": true, "handle": "content" }, { "description": "Whether the OneDrive server returned HTTP 304 Not Modified.", "jsonSchema": { "type": "boolean", "description": "Whether the OneDrive server returned HTTP 304 Not Modified." }, "nullable": false, "handle": "notModified" } ], "name": "Download the workbook", "executor": { "kind": "connector", "action": "one_drive.download_file" } } }, "n_e3df43869b56dbd0": { "inputs": { "content": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_2f2be65639b80453", "output": "content" } ] } }, "name": "Prepare the attachment", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": [ "object", "null" ], "properties": { "name": { "type": "string", "description": "The downloaded file name." }, "mimetype": { "type": "string", "description": "The MIME type of the downloaded file." }, "s3url": { "type": "string", "description": "The transit URL for downloading the file." } }, "required": [ "name", "mimetype", "s3url" ], "additionalProperties": false, "description": "The downloaded file uploaded to transit storage, or null when not modified." }, "nullable": true, "handle": "content" } ], "outputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "contentBase64": { "type": "string", "minLength": 1, "description": "The Base64-encoded attachment content." }, "filename": { "type": "string", "minLength": 1, "description": "The attachment file name." }, "type": { "type": "string", "minLength": 1, "description": "The optional attachment MIME type." }, "disposition": { "type": "string", "enum": [ "attachment", "inline" ], "description": "The optional attachment disposition." }, "contentId": { "type": "string", "minLength": 1, "description": "The optional content ID used for inline attachments." } }, "required": [ "contentBase64", "filename" ], "additionalProperties": false, "description": "One attachment accepted by the SendGrid Mail Send API." }, "description": "The optional attachments included with this email." }, "nullable": true, "handle": "attachments" } ], "name": "Prepare the attachment", "moduleId": "n_de322f79d9715394", "capabilities": [ { "kind": "http", "hosts": [ "example.com" ] } ] } }, "n_3d16df6203f46a76": { "inputs": { "from": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_602ccf8df7f5d2a6", "output": "from" } ] }, "to": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_602ccf8df7f5d2a6", "output": "to" } ] }, "subject": { "kind": "value", "value": "Ycombinator news" }, "textContent": { "kind": "value", "value": "Here are the latest news attached!" }, "attachments": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_e3df43869b56dbd0", "output": "attachments" } ] } }, "name": "Send the spreadsheet", "kind": "task", "task": { "inputs": [ { "description": "The verified sender used for this email.", "jsonSchema": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "The sender email address." }, "name": { "type": "string", "minLength": 1, "description": "The optional sender display name." } }, "required": [ "email" ], "additionalProperties": false, "description": "The verified sender used for this email." }, "nullable": false, "handle": "from" }, { "description": "The primary recipients for this email.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "The recipient email address." }, "name": { "type": "string", "minLength": 1, "description": "The optional recipient display name." } }, "required": [ "email" ], "additionalProperties": false, "description": "One SendGrid email recipient." }, "minItems": 1, "description": "The primary recipients for this email." }, "nullable": false, "handle": "to" }, { "description": "The optional Cc recipients.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "The recipient email address." }, "name": { "type": "string", "minLength": 1, "description": "The optional recipient display name." } }, "required": [ "email" ], "additionalProperties": false, "description": "One SendGrid email recipient." }, "minItems": 1, "description": "The optional Cc recipients." }, "nullable": true, "handle": "cc", "value": null }, { "description": "The optional Bcc recipients.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "The recipient email address." }, "name": { "type": "string", "minLength": 1, "description": "The optional recipient display name." } }, "required": [ "email" ], "additionalProperties": false, "description": "One SendGrid email recipient." }, "minItems": 1, "description": "The optional Bcc recipients." }, "nullable": true, "handle": "bcc", "value": null }, { "description": "The optional Reply-To override.", "jsonSchema": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "The sender email address." }, "name": { "type": "string", "minLength": 1, "description": "The optional sender display name." } }, "required": [ "email" ], "additionalProperties": false, "description": "The optional Reply-To override." }, "nullable": true, "handle": "replyTo", "value": null }, { "description": "The email subject line.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The email subject line." }, "nullable": true, "handle": "subject", "value": null }, { "description": "The optional HTML body content.", "jsonSchema": { "type": "string", "description": "The optional HTML body content." }, "nullable": true, "handle": "htmlContent", "value": null }, { "description": "The optional plain-text body content.", "jsonSchema": { "type": "string", "description": "The optional plain-text body content." }, "nullable": true, "handle": "textContent", "value": null }, { "description": "The optional SendGrid template ID.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The optional SendGrid template ID." }, "nullable": true, "handle": "templateId", "value": null }, { "description": "The optional dynamic template data sent with the email.", "jsonSchema": { "type": "object", "properties": {}, "additionalProperties": true, "description": "The optional dynamic template data sent with the email." }, "nullable": true, "handle": "dynamicTemplateData", "value": null }, { "description": "The optional SendGrid categories attached to this email.", "jsonSchema": { "type": "array", "items": { "type": "string", "minLength": 1, "description": "One SendGrid category name." }, "maxItems": 10, "description": "The optional SendGrid categories attached to this email." }, "nullable": true, "handle": "categories", "value": null }, { "description": "The optional custom arguments attached to this email.", "jsonSchema": { "type": "object", "additionalProperties": { "type": "string", "description": "A record value." }, "description": "The optional custom arguments attached to this email." }, "nullable": true, "handle": "customArgs", "value": null }, { "description": "The optional Unix timestamp that schedules this email.", "jsonSchema": { "type": "integer", "exclusiveMinimum": 0, "description": "The optional Unix timestamp that schedules this email." }, "nullable": true, "handle": "sendAt", "value": null }, { "description": "The optional attachments included with this email.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "contentBase64": { "type": "string", "minLength": 1, "description": "The Base64-encoded attachment content." }, "filename": { "type": "string", "minLength": 1, "description": "The attachment file name." }, "type": { "type": "string", "minLength": 1, "description": "The optional attachment MIME type." }, "disposition": { "type": "string", "enum": [ "attachment", "inline" ], "description": "The optional attachment disposition." }, "contentId": { "type": "string", "minLength": 1, "description": "The optional content ID used for inline attachments." } }, "required": [ "contentBase64", "filename" ], "additionalProperties": false, "description": "One attachment accepted by the SendGrid Mail Send API." }, "description": "The optional attachments included with this email." }, "nullable": true, "handle": "attachments", "value": null } ], "outputs": [ { "description": "Whether SendGrid accepted the email for delivery.", "jsonSchema": { "type": "boolean", "description": "Whether SendGrid accepted the email for delivery." }, "nullable": false, "handle": "accepted" }, { "description": "The optional SendGrid message ID response header.", "jsonSchema": { "type": [ "string", "null" ], "description": "The optional SendGrid message ID response header." }, "nullable": true, "handle": "messageId" } ], "name": "Send the spreadsheet", "executor": { "kind": "connector", "action": "sendgrid.send_email" } } } }, "edges": [ { "source": "n_6fa33fbec7df1a35", "target": "n_602ccf8df7f5d2a6" }, { "source": "n_602ccf8df7f5d2a6", "target": "n_ec9cdce7ac986c83" }, { "source": "n_ec9cdce7ac986c83", "target": "n_4e12f750948ec26c" }, { "source": "n_4e12f750948ec26c", "target": "n_6d79d64ebfcff641" }, { "source": "n_6d79d64ebfcff641", "target": "n_0b196b84c8bff087" }, { "source": "n_0b196b84c8bff087", "target": "n_2f2be65639b80453" }, { "source": "n_2f2be65639b80453", "target": "n_e3df43869b56dbd0" }, { "source": "n_e3df43869b56dbd0", "target": "n_3d16df6203f46a76" } ] } }, "modules": { "n_a1e6a7215fbfa67e": { "name": "Prepare email addresses", "imports": [], "source": "export default function recipients({from,to}){if(typeof from!=='string'||typeof to!=='string'||!from.trim()||!to.trim())throw Error('Sender and recipient are required');return{from:{email:from.trim()},to:[{email:to.trim()}]}}\n" }, "n_ba5cb35a746bcd0c": { "name": "Extract titles and links", "imports": [], "source": "export default function rows({body}){if(typeof body!=='string')throw Error('Missing Hacker News HTML');const decode=s=>s.replace(/&(#x[0-9a-f]+|#\\d+|amp|lt|gt|quot|apos);/gi,(v,k)=>{if(k[0]==='#'){let n=k[1].toLowerCase()==='x'?parseInt(k.slice(2),16):parseInt(k.slice(1),10);return Number.isFinite(n)&&n>0&&n<=0x10ffff?String.fromCodePoint(n):v}return({amp:'&',lt:'<',gt:'>',quot:'\"',apos:\"'\"})[k.toLowerCase()]??v});const matches=[...body.matchAll(/]*>\\s*]*>([\\s\\S]*?)<\\/a>/gi)];if(!matches.length)throw Error('No Hacker News front-page stories found');let records=matches.map(m=>{let title=decode(m[2].replace(/<[^>]*>/g,'')),url=decode(m[1]);if(!title.trim()||!url.trim())throw Error('Invalid story');return[title,url]});return{worksheetData:{'Latest news':[['news_title','news_url'],...records]},path:'hn-news-'+Date.now()+'.xlsx'}}\n" }, "n_c3c53eab5e6b7472": { "name": "Read the workbook ID", "imports": [], "source": "export default function id({body}){if(!body||typeof body.id!=='string'||!body.id)throw Error('Workbook creation was not confirmed');return{id:body.id}}\n" }, "n_de322f79d9715394": { "name": "Prepare the attachment", "imports": [], "source": "import{Buffer}from'node:buffer';export default async function attachment({content},context){let url=content?.s3url;if(typeof url!=='string'||!url.startsWith('https://'))throw Error('Missing transit URL');let r=await context.fetch(url,{method:'GET'});if(!r.ok)throw Error('Workbook download failed');let b=Buffer.from(await r.arrayBuffer());if(b.length<4||b[0]!==0x50||b[1]!==0x4b||b[2]!==3||b[3]!==4)throw Error('Workbook is not an XLSX ZIP');return{attachments:[{contentBase64:b.toString('base64'),filename:'Ycombinator_news.xlsx',type:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',disposition:'attachment'}]}}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }