{ "kind": "open-flow-workflow", "version": 1, "name": "Send Scheduled Customer Emails from Sheets", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_d8a26ae1d9d6be7e": { "name": "Every minute", "kind": "cron", "cronTimes": [ { "type": "cron", "expression": "* * * * *", "timezone": "UTC" } ] }, "n_693d08f38fee7460": { "inputs": {}, "name": "Choose the customer messages sheet", "kind": "task", "task": { "inputs": [], "outputs": [ { "jsonSchema": { "type": "string", "minLength": 1, "description": "The spreadsheet ID." }, "nullable": true, "handle": "spreadsheetId" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "sheetName" }, { "jsonSchema": { "type": "string", "minLength": 1, "description": "The A1 notation of the range to retrieve." }, "nullable": false, "handle": "range" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "today" } ], "name": "Choose the customer messages sheet", "moduleId": "n_bdeb9ac5ead5a9c1", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_ca63b0f572647520": { "inputs": { "spreadsheetId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_693d08f38fee7460", "output": "spreadsheetId" } ] }, "range": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_693d08f38fee7460", "output": "range" } ] }, "majorDimension": { "kind": "value", "value": "ROWS" }, "valueRenderOption": { "kind": "value", "value": "FORMATTED_VALUE" } }, "name": "Read customer messages", "kind": "task", "task": { "inputs": [ { "description": "The spreadsheet ID.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The spreadsheet ID." }, "nullable": true, "handle": "spreadsheetId", "value": null }, { "description": "The A1 notation of the range to retrieve.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The A1 notation of the range to retrieve." }, "nullable": false, "handle": "range" }, { "description": "The major dimension for the returned values.", "jsonSchema": { "type": "string", "enum": [ "DIMENSION_UNSPECIFIED", "ROWS", "COLUMNS" ], "description": "The major dimension for the returned values." }, "nullable": true, "handle": "majorDimension", "value": null }, { "description": "How values should be rendered in the output.", "jsonSchema": { "type": "string", "enum": [ "FORMATTED_VALUE", "UNFORMATTED_VALUE", "FORMULA" ], "description": "How values should be rendered in the output." }, "nullable": true, "handle": "valueRenderOption", "value": null }, { "description": "How dates and times should be rendered in the output.", "jsonSchema": { "type": "string", "enum": [ "SERIAL_NUMBER", "FORMATTED_STRING" ], "description": "How dates and times should be rendered in the output." }, "nullable": true, "handle": "dateTimeRenderOption", "value": null } ], "outputs": [ { "description": "The A1 notation of the range.", "jsonSchema": { "type": "string", "description": "The A1 notation of the range." }, "nullable": false, "handle": "range" }, { "description": "The major dimension of the values (ROWS or COLUMNS).", "jsonSchema": { "type": "string", "description": "The major dimension of the values (ROWS or COLUMNS)." }, "nullable": false, "handle": "majorDimension" }, { "description": "The data values in the range.", "jsonSchema": { "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": "The cell value schema." }, "description": "An array item." }, "description": "The data values in the range." }, "nullable": false, "handle": "values" } ], "name": "Read customer messages", "executor": { "kind": "connector", "action": "googlesheets.values_get" } } }, "n_dd4c970483a573e4": { "inputs": { "values": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_ca63b0f572647520", "output": "values" } ] }, "today": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_693d08f38fee7460", "output": "today" } ] } }, "name": "Find messages due today", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "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": "The cell value schema." }, "description": "An array item." }, "description": "The data values in the range." }, "nullable": false, "handle": "values" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "today" } ], "outputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "nullable": false, "handle": "messages" } ], "name": "Find messages due today", "moduleId": "n_f469bc861895b09d", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_df81b6b0fc754e39": { "inputs": { "messages": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_dd4c970483a573e4", "output": "messages" } ] }, "previousState": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_df81b6b0fc754e39", "output": "state" } ] } }, "name": "Prepare the next email", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "nullable": false, "handle": "messages" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": true, "handle": "previousState" } ], "outputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "state" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "more" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "current" }, { "jsonSchema": { "type": "string", "description": "Primary recipient email address." }, "nullable": true, "handle": "to" }, { "jsonSchema": { "type": "string", "description": "Email subject line." }, "nullable": true, "handle": "subject" }, { "jsonSchema": { "type": "string", "description": "Email body content." }, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "count" } ], "name": "Prepare the next email", "moduleId": "n_cdfa3cabed84e3bd", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_03d4ce2ab74f9d44": { "inputs": {}, "name": "More messages?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "send", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_df81b6b0fc754e39", "output": "more" } }, "operator": "isTrue" } ] } ] } ] }, "n_2d8fd15647862851": { "inputs": { "to": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_df81b6b0fc754e39", "output": "to" } ] }, "subject": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_df81b6b0fc754e39", "output": "subject" } ] }, "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_df81b6b0fc754e39", "output": "body" } ] }, "isHtml": { "kind": "value", "value": false } }, "name": "Send the email", "kind": "task", "task": { "inputs": [ { "description": "Primary recipient email address.", "jsonSchema": { "type": "string", "description": "Primary recipient email address." }, "nullable": true, "handle": "to", "value": null }, { "description": "Additional To recipients.", "jsonSchema": { "type": "array", "items": { "type": "string", "description": "An array item." }, "description": "Additional To recipients." }, "nullable": true, "handle": "extraRecipients", "value": null }, { "description": "Cc recipients.", "jsonSchema": { "anyOf": [ { "type": "string", "description": "A union variant." }, { "type": "array", "items": { "type": "string", "description": "An array item." }, "description": "A union variant." } ], "description": "Cc recipients." }, "nullable": true, "handle": "cc", "value": null }, { "description": "Bcc recipients.", "jsonSchema": { "anyOf": [ { "type": "string", "description": "A union variant." }, { "type": "array", "items": { "type": "string", "description": "An array item." }, "description": "A union variant." } ], "description": "Bcc recipients." }, "nullable": true, "handle": "bcc", "value": null }, { "description": "Email subject line.", "jsonSchema": { "type": "string", "description": "Email subject line." }, "nullable": true, "handle": "subject", "value": null }, { "description": "Email body content.", "jsonSchema": { "type": "string", "description": "Email body content." }, "nullable": true, "handle": "body", "value": null }, { "description": "Set to true when the body content is already HTML.", "jsonSchema": { "type": "boolean", "description": "Set to true when the body content is already HTML." }, "nullable": true, "handle": "isHtml", "value": null }, { "description": "Attachments and CID inline images. Up to 25,000,000 decoded bytes in total and 35,000,000 MIME bytes.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "filename": { "type": "string", "description": "Attachment filename; omit for an unnamed attachment." }, "mimeType": { "type": "string", "description": "MIME type without parameters; defaults to application/octet-stream." }, "contentBase64": { "type": "string", "description": "Standard padded Base64 content. Empty string represents a zero-byte file. Supply this or fileUrl." }, "fileUrl": { "type": "string", "format": "uri", "description": "Public URL to download the attachment. Supply this or contentBase64." }, "contentId": { "type": "string", "minLength": 1, "description": "Bare Content-ID without cid: or angle brackets; reference it as cid: in HTML." }, "disposition": { "type": "string", "enum": [ "inline", "attachment" ], "description": "Defaults to inline when contentId is set, otherwise attachment. Inline requires contentId." } }, "additionalProperties": false, "description": "An attachment or CID inline resource.", "oneOf": [ { "required": [ "contentBase64" ] }, { "required": [ "fileUrl" ] } ] }, "maxItems": 100, "description": "Attachments and CID inline images. Up to 25,000,000 decoded bytes in total and 35,000,000 MIME bytes." }, "nullable": true, "handle": "attachments", "value": null }, { "description": "Verified Gmail send-as alias to use in the From header.", "jsonSchema": { "type": "string", "description": "Verified Gmail send-as alias to use in the From header." }, "nullable": true, "handle": "fromEmail", "value": null } ], "outputs": [ { "description": "Gmail message ID.", "jsonSchema": { "type": "string", "description": "Gmail message ID." }, "nullable": false, "handle": "messageId" }, { "description": "Gmail thread ID.", "jsonSchema": { "type": "string", "description": "Gmail thread ID." }, "nullable": true, "handle": "threadId" } ], "name": "Send the email", "executor": { "kind": "connector", "action": "gmail.send_email" } } }, "n_3b2cba9bf005df51": { "inputs": { "spreadsheetId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_693d08f38fee7460", "output": "spreadsheetId" } ] }, "range": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_693d08f38fee7460", "output": "range" } ] }, "majorDimension": { "kind": "value", "value": "ROWS" }, "valueRenderOption": { "kind": "value", "value": "FORMATTED_VALUE" } }, "name": "Find the current message row", "kind": "task", "task": { "inputs": [ { "description": "The spreadsheet ID.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The spreadsheet ID." }, "nullable": true, "handle": "spreadsheetId", "value": null }, { "description": "The A1 notation of the range to retrieve.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The A1 notation of the range to retrieve." }, "nullable": false, "handle": "range" }, { "description": "The major dimension for the returned values.", "jsonSchema": { "type": "string", "enum": [ "DIMENSION_UNSPECIFIED", "ROWS", "COLUMNS" ], "description": "The major dimension for the returned values." }, "nullable": true, "handle": "majorDimension", "value": null }, { "description": "How values should be rendered in the output.", "jsonSchema": { "type": "string", "enum": [ "FORMATTED_VALUE", "UNFORMATTED_VALUE", "FORMULA" ], "description": "How values should be rendered in the output." }, "nullable": true, "handle": "valueRenderOption", "value": null }, { "description": "How dates and times should be rendered in the output.", "jsonSchema": { "type": "string", "enum": [ "SERIAL_NUMBER", "FORMATTED_STRING" ], "description": "How dates and times should be rendered in the output." }, "nullable": true, "handle": "dateTimeRenderOption", "value": null } ], "outputs": [ { "description": "The A1 notation of the range.", "jsonSchema": { "type": "string", "description": "The A1 notation of the range." }, "nullable": false, "handle": "range" }, { "description": "The major dimension of the values (ROWS or COLUMNS).", "jsonSchema": { "type": "string", "description": "The major dimension of the values (ROWS or COLUMNS)." }, "nullable": false, "handle": "majorDimension" }, { "description": "The data values in the range.", "jsonSchema": { "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": "The cell value schema." }, "description": "An array item." }, "description": "The data values in the range." }, "nullable": false, "handle": "values" } ], "name": "Find the current message row", "executor": { "kind": "connector", "action": "googlesheets.values_get" } } }, "n_95ea4bdcf41c5852": { "inputs": { "values": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_3b2cba9bf005df51", "output": "values" } ] }, "current": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_df81b6b0fc754e39", "output": "current" } ] }, "sheetName": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_693d08f38fee7460", "output": "sheetName" } ] } }, "name": "Prepare the status cell", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "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": "The cell value schema." }, "description": "An array item." }, "description": "The data values in the range." }, "nullable": false, "handle": "values" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "current" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "sheetName" } ], "outputs": [ { "jsonSchema": { "type": "string", "minLength": 1, "description": "The A1 notation of the range to write to." }, "nullable": false, "handle": "range" }, { "jsonSchema": { "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": "The cell value schema." }, "description": "An array item." }, "description": "The data to write into the range." }, "nullable": false, "handle": "values" } ], "name": "Prepare the status cell", "moduleId": "n_1eb99613f57657cf", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_234c4bb2faf9319b": { "inputs": { "spreadsheetId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_693d08f38fee7460", "output": "spreadsheetId" } ] }, "range": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_95ea4bdcf41c5852", "output": "range" } ] }, "values": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_95ea4bdcf41c5852", "output": "values" } ] }, "valueInputOption": { "kind": "value", "value": "RAW" } }, "name": "Mark the email sent", "kind": "task", "task": { "inputs": [ { "description": "The spreadsheet ID.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The spreadsheet ID." }, "nullable": true, "handle": "spreadsheetId", "value": null }, { "description": "The A1 notation of the range to write to.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The A1 notation of the range to write to." }, "nullable": false, "handle": "range" }, { "description": "The data to write into the range.", "jsonSchema": { "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": "The cell value schema." }, "description": "An array item." }, "description": "The data to write into the range." }, "nullable": false, "handle": "values" }, { "description": "The major dimension of the values array.", "jsonSchema": { "type": "string", "enum": [ "ROWS", "COLUMNS" ], "description": "The major dimension of the values array." }, "nullable": true, "handle": "majorDimension", "value": null }, { "description": "How the input data should be interpreted.", "jsonSchema": { "type": "string", "enum": [ "RAW", "USER_ENTERED" ], "description": "How the input data should be interpreted." }, "nullable": true, "handle": "valueInputOption", "value": null }, { "description": "Whether to include the written values in the response.", "jsonSchema": { "type": "boolean", "description": "Whether to include the written values in the response." }, "nullable": true, "handle": "includeValuesInResponse", "value": null }, { "description": "How values in the response should be rendered.", "jsonSchema": { "type": "string", "enum": [ "FORMATTED_VALUE", "UNFORMATTED_VALUE", "FORMULA" ], "description": "How values in the response should be rendered." }, "nullable": true, "handle": "responseValueRenderOption", "value": null }, { "description": "How dates in the response should be rendered.", "jsonSchema": { "type": "string", "enum": [ "SERIAL_NUMBER", "FORMATTED_STRING" ], "description": "How dates in the response should be rendered." }, "nullable": true, "handle": "responseDateTimeRenderOption", "value": null }, { "description": "Whether to auto-expand the sheet to fit the written data.", "jsonSchema": { "type": "boolean", "description": "Whether to auto-expand the sheet to fit the written data." }, "nullable": true, "handle": "autoExpandSheet", "value": null } ], "outputs": [ { "description": "The unique ID of the spreadsheet.", "jsonSchema": { "type": "string", "description": "The unique ID of the spreadsheet." }, "nullable": false, "handle": "spreadsheetId" }, { "description": "The A1 notation of the range that was updated.", "jsonSchema": { "type": "string", "description": "The A1 notation of the range that was updated." }, "nullable": false, "handle": "updatedRange" }, { "description": "The number of rows that were updated.", "jsonSchema": { "type": "integer", "description": "The number of rows that were updated." }, "nullable": false, "handle": "updatedRows" }, { "description": "The number of columns that were updated.", "jsonSchema": { "type": "integer", "description": "The number of columns that were updated." }, "nullable": false, "handle": "updatedColumns" }, { "description": "The number of cells that were updated.", "jsonSchema": { "type": "integer", "description": "The number of cells that were updated." }, "nullable": false, "handle": "updatedCells" }, { "description": "The values of the cells after the update.", "jsonSchema": { "type": "object", "properties": { "range": { "type": "string", "description": "The A1 notation of the range." }, "majorDimension": { "type": "string", "description": "The major dimension of the values (ROWS or COLUMNS)." }, "values": { "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": "The cell value schema." }, "description": "An array item." }, "description": "The data values in the range." } }, "required": [ "range", "majorDimension", "values" ], "additionalProperties": false, "description": "The values of the cells after the update." }, "nullable": true, "handle": "updatedData" } ], "name": "Mark the email sent", "executor": { "kind": "connector", "action": "googlesheets.values_update" } } }, "n_1df9ec833df57fba": { "inputs": { "updatedCells": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_234c4bb2faf9319b", "output": "updatedCells" } ] } }, "name": "Confirm the status update", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "integer", "description": "The number of cells that were updated." }, "nullable": false, "handle": "updatedCells" } ], "outputs": [ { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "ok" } ], "name": "Confirm the status update", "moduleId": "n_e29da4131c1e627a", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_653168388d103ed0": { "name": "Complete", "kind": "outputs", "outputDefs": [ { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "count" } ], "outputMappings": { "count": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_df81b6b0fc754e39", "output": "count" } ] } } } }, "edges": [ { "source": "n_d8a26ae1d9d6be7e", "target": "n_693d08f38fee7460" }, { "source": "n_693d08f38fee7460", "target": "n_ca63b0f572647520" }, { "source": "n_ca63b0f572647520", "target": "n_dd4c970483a573e4" }, { "source": "n_dd4c970483a573e4", "target": "n_df81b6b0fc754e39" }, { "source": "n_df81b6b0fc754e39", "target": "n_03d4ce2ab74f9d44" }, { "source": "n_03d4ce2ab74f9d44", "target": "n_2d8fd15647862851", "sourceHandle": "send" }, { "source": "n_2d8fd15647862851", "target": "n_3b2cba9bf005df51" }, { "source": "n_3b2cba9bf005df51", "target": "n_95ea4bdcf41c5852" }, { "source": "n_95ea4bdcf41c5852", "target": "n_234c4bb2faf9319b" }, { "source": "n_234c4bb2faf9319b", "target": "n_1df9ec833df57fba" }, { "source": "n_1df9ec833df57fba", "target": "n_df81b6b0fc754e39" }, { "source": "n_03d4ce2ab74f9d44", "target": "n_653168388d103ed0", "sourceHandle": "otherwise" } ] } }, "modules": { "n_bdeb9ac5ead5a9c1": { "name": "Choose the customer messages sheet", "imports": [], "source": "export default function config(){const spreadsheetId='YOUR_SPREADSHEET_ID',sheetName='Sheet1',now=new Date();if(!sheetName.trim())throw Error('Set a worksheet name');return{spreadsheetId,sheetName,range:\"'\"+sheetName.replace(/'/g,\"''\")+\"'\",today:now.toISOString().slice(0,10).replace(/-/g,'/')};}\n" }, "n_f469bc861895b09d": { "name": "Find messages due today", "imports": [], "source": "export default function plan({values,today}){if(!Array.isArray(values))throw Error('Invalid sheet');if(values.length===0)return{messages:[]};const headers=values[0];if(!Array.isArray(headers))throw Error('Missing sheet headers');const names=['ID','Name','Email','Date','Status','Title','Subject'],columns={};for(const name of names){const matches=headers.flatMap((x,i)=>x===name?[i]:[]);if(matches.length!==1)throw Error('Each required header must occur exactly once');columns[name]=matches[0]}if(typeof today!=='string'||!/^\\d{4}\\/\\d\\d\\/\\d\\d$/.test(today))throw Error('Invalid current date');const ids=new Map();for(const row of values.slice(1)){if(!Array.isArray(row))throw Error('Invalid sheet row');const id=row[columns.ID];if(id!=null&&String(id)!=='')ids.set(String(id),(ids.get(String(id))??0)+1)}const messages=[];for(const row of values.slice(1)){if(row[columns.Status]!=='Waiting for sending'||row[columns.Date]!==today||!['Name','Email','Date','Title','Subject'].every(k=>row[columns[k]]!=null&&String(row[columns[k]])!==''))continue;const id=row[columns.ID];if(id==null||String(id)===''||ids.get(String(id))!==1)throw Error('Missing or duplicate message ID');messages.push(Object.fromEntries(names.map(k=>[k,String(row[columns[k]]??'')])))}return{messages};}\n" }, "n_cdfa3cabed84e3bd": { "name": "Prepare the next email", "imports": [], "source": "export default function next({messages,previousState}){if(!Array.isArray(messages))throw Error('Invalid messages');const index=previousState?.index??0;if(!Number.isInteger(index)||index<0||index>messages.length)throw Error('Invalid message position');const m=messages[index];return{state:{index:index+1},more:indexx===k?[i]:[]);if(p.length!==1)throw Error('Missing or duplicate required header');c[k]=p[0]}const found=values.slice(1).flatMap((row,i)=>Array.isArray(row)&&String(row[c.ID]??'')===current.ID?[{row,i}]:[]);if(found.length!==1)throw Error('Message ID no longer uniquely identifies a row');const {row,i}=found[0];for(const k of fields)if(String(row[c[k]]??'')!==current[k])throw Error('Message row changed after sending');let col=c.Status+1,letters='';while(col){col--;letters=String.fromCharCode(65+col%26)+letters;col=Math.floor(col/26)}if(typeof sheetName!=='string'||!sheetName.trim())throw Error('Missing worksheet name');return{range:\"'\"+sheetName.replace(/'/g,\"''\")+\"'!\"+letters+(i+2),values:[['Sent successfully']]};}\n" }, "n_e29da4131c1e627a": { "name": "Confirm the status update", "imports": [], "source": "export default function confirm({updatedCells}){if(updatedCells!==1)throw Error('Status update was not confirmed');return{ok:true};}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }