{ "kind": "open-flow-workflow", "version": 1, "name": "Log ISS Position to Firebase", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_309075d377cedd6d": { "name": "Every minute", "kind": "cron", "cronTimes": [ { "type": "cron", "expression": "* * * * *", "timezone": "UTC" } ] }, "n_ab80dcbe1762f14e": { "inputs": {}, "name": "Prepare the current timestamp", "kind": "task", "task": { "inputs": [], "outputs": [ { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "url" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "timestamp" } ], "name": "Prepare the current timestamp", "moduleId": "n_6dd285b03b165162", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_5ea361b2c5ae111b": { "inputs": { "url": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_ab80dcbe1762f14e", "output": "url" } ] } }, "name": "Read the ISS position", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" } ], "outputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" } ], "name": "Read the ISS position", "executor": { "method": "GET", "query": { "mode": "fields", "names": [] }, "headers": { "mode": "fields", "names": [] }, "bodyFormat": "none", "authentication": { "type": "none" }, "responseFormat": "json", "statusPolicy": "success", "kind": "http-request" } } }, "n_2a87d5ba244297e8": { "inputs": { "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_5ea361b2c5ae111b", "output": "body" } ] }, "timestamp": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_ab80dcbe1762f14e", "output": "timestamp" } ] }, "databaseUrl": { "kind": "value", "value": "https://YOUR-DATABASE.firebaseio.com/iss.json" } }, "name": "Prepare the Firebase record", "kind": "task", "task": { "inputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "timestamp" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "databaseUrl" } ], "outputs": [ { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "url" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "position" } ], "name": "Prepare the Firebase record", "moduleId": "n_d25d7971bd346961", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_445667d3f2db4dbc": { "inputs": { "url": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_2a87d5ba244297e8", "output": "url" } ] }, "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_2a87d5ba244297e8", "output": "position" } ] }, "auth.token": { "kind": "unset" } }, "name": "Push the position", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "auth.token" } ], "outputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" } ], "name": "Push the position", "executor": { "method": "POST", "query": { "mode": "fields", "names": [] }, "headers": { "mode": "fields", "names": [] }, "bodyFormat": "json", "authentication": { "type": "apiKey", "name": "auth", "in": "query" }, "responseFormat": "json", "statusPolicy": "success", "kind": "http-request" } } }, "n_1c1f1c9d7723e623": { "inputs": { "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_445667d3f2db4dbc", "output": "body" } ] } }, "name": "Confirm the push key", "kind": "task", "task": { "inputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" } ], "outputs": [ { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "key" } ], "name": "Confirm the push key", "moduleId": "n_b768840d671f3438", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_28a341450b77e859": { "name": "Stored position", "kind": "outputs", "outputDefs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "position" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "key" } ], "outputMappings": { "position": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_2a87d5ba244297e8", "output": "position" } ] }, "key": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_1c1f1c9d7723e623", "output": "key" } ] } } } }, "edges": [ { "source": "n_309075d377cedd6d", "target": "n_ab80dcbe1762f14e" }, { "source": "n_ab80dcbe1762f14e", "target": "n_5ea361b2c5ae111b" }, { "source": "n_5ea361b2c5ae111b", "target": "n_2a87d5ba244297e8" }, { "source": "n_2a87d5ba244297e8", "target": "n_445667d3f2db4dbc" }, { "source": "n_445667d3f2db4dbc", "target": "n_1c1f1c9d7723e623" }, { "source": "n_1c1f1c9d7723e623", "target": "n_28a341450b77e859" } ] } }, "modules": { "n_6dd285b03b165162": { "name": "Prepare the current timestamp", "imports": [], "source": "export default function query() {const timestamp=Math.floor(Date.now()/1000);return {timestamp,url:'https://api.wheretheiss.at/v1/satellites/25544/positions?timestamps='+timestamp};}\n" }, "n_d25d7971bd346961": { "name": "Prepare the Firebase record", "imports": [], "source": "function row({body,timestamp}) {\n if(!Array.isArray(body)||body.length!==1)throw Error('Expected one ISS position');const p=body[0];\n if(!p||p.id!==25544||typeof p.name!=='string'||!p.name||!Number.isFinite(p.latitude)||p.latitude < -90||p.latitude>90||!Number.isFinite(p.longitude)||p.longitude < -180||p.longitude>180||p.timestamp!==timestamp)throw Error('ISS position does not match the request');\n const position={name:p.name,latitude:p.latitude,longitude:p.longitude,timestamp:p.timestamp};return {position,rows:[{json:position}]};\n}\n\nexport default function firebaseRow({body,timestamp,databaseUrl}){if(typeof databaseUrl!=='string'||databaseUrl.includes('YOUR-DATABASE'))throw Error('Configure database URL');let u;try{u=new URL(databaseUrl)}catch{throw Error('Invalid database URL')}if(u.protocol!=='https:'||u.username||u.password||u.port||u.search||u.hash||u.pathname!=='/iss.json'||!(/^[-a-z0-9]+\\.firebaseio\\.com$/.test(u.hostname)||/^[-a-z0-9]+\\.[a-z0-9-]+\\.firebasedatabase\\.app$/.test(u.hostname)))throw Error('Use the Firebase database /iss.json URL');const p=row({body,timestamp}).position;return{url:u.href,position:{latitude:p.latitude,longitude:p.longitude,timestamp:p.timestamp}}}\n" }, "n_b768840d671f3438": { "name": "Confirm the push key", "imports": [], "source": "export default function confirm({body}){if(!body||typeof body.name!=='string'||!body.name)throw Error('Firebase did not confirm the push key');return{key:body.name}}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }