{ "kind": "open-flow-workflow", "version": 1, "name": "Back Up n8n Workflows to Google Drive", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_512dc98acc0bb809": { "name": "Run backup manually", "kind": "start", "inputDefs": [] }, "n_aba04c26ec089a43": { "name": "Run every 4 hours UTC", "kind": "cron", "cronTimes": [ { "type": "cron", "expression": "0 */4 * * *", "timezone": "UTC" } ] }, "n_8d42d00ca914195e": { "inputs": { "root": { "kind": "value", "value": "YOUR_DEDICATED_PARENT_FOLDER_ID" } }, "name": "Prepare backup folder", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "root" } ], "outputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "root" }, { "jsonSchema": { "type": "string", "minLength": 1, "description": "The name of the file." }, "nullable": false, "handle": "name" }, { "jsonSchema": { "type": "string", "minLength": 1, "description": "The MIME type of the file." }, "nullable": false, "handle": "mimeType" }, { "jsonSchema": { "type": "array", "items": { "type": "string", "minLength": 1, "description": "Schema for nonEmptyString." }, "minItems": 1, "description": "A list of parent folder IDs to place the file in." }, "nullable": false, "handle": "parents" } ], "name": "Prepare backup folder", "moduleId": "n_c00a5a1d3a1e6976", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_06707f358eec533e": { "inputs": { "name": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8d42d00ca914195e", "output": "name" } ] }, "mimeType": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8d42d00ca914195e", "output": "mimeType" } ] }, "parents": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8d42d00ca914195e", "output": "parents" } ] } }, "name": "Create backup folder", "kind": "task", "task": { "inputs": [ { "description": "The name of the file.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The name of the file." }, "nullable": true, "handle": "name", "value": null }, { "description": "The MIME type of the file.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The MIME type of the file." }, "nullable": true, "handle": "mimeType", "value": null }, { "description": "A short description of the file.", "jsonSchema": { "type": "string", "minLength": 1, "description": "A short description of the file." }, "nullable": true, "handle": "description", "value": null }, { "description": "A list of parent folder IDs to place the file in.", "jsonSchema": { "type": "array", "items": { "type": "string", "minLength": 1, "description": "Schema for nonEmptyString." }, "minItems": 1, "description": "A list of parent folder IDs to place the file in." }, "nullable": true, "handle": "parents", "value": null }, { "description": "Whether the user has starred the file.", "jsonSchema": { "type": "boolean", "description": "Whether the user has starred the file." }, "nullable": true, "handle": "starred", "value": null }, { "description": "A collection of arbitrary key-value pairs which are private to the requesting app.", "jsonSchema": { "type": "object", "additionalProperties": { "type": "string", "description": "A record value." }, "description": "A collection of arbitrary key-value pairs which are private to the requesting app." }, "nullable": true, "handle": "appProperties", "value": null }, { "description": "A collection of arbitrary key-value pairs which are visible to all apps.", "jsonSchema": { "type": "object", "additionalProperties": { "type": "string", "description": "A record value." }, "description": "A collection of arbitrary key-value pairs which are visible to all apps." }, "nullable": true, "handle": "properties", "value": null }, { "description": "Connector media upload content encoded as a Base64 string.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Connector media upload content encoded as a Base64 string." }, "nullable": true, "handle": "contentBase64", "value": null }, { "description": "Connector text media upload content.", "jsonSchema": { "type": "string", "description": "Connector text media upload content." }, "nullable": true, "handle": "text", "value": null } ], "outputs": [ { "description": "The unique identifier of the file.", "jsonSchema": { "type": "string", "description": "The unique identifier of the file." }, "nullable": false, "handle": "id" }, { "description": "The name of the file.", "jsonSchema": { "type": "string", "description": "The name of the file." }, "nullable": false, "handle": "name" }, { "description": "The MIME type of the file.", "jsonSchema": { "type": "string", "description": "The MIME type of the file." }, "nullable": false, "handle": "mimeType" }, { "description": "A link for opening the file in a relevant Google editor or viewer in a browser.", "jsonSchema": { "type": [ "string", "null" ], "description": "A link for opening the file in a relevant Google editor or viewer in a browser." }, "nullable": true, "handle": "webViewLink" }, { "description": "The time at which the file was created (RFC 3339 date-time).", "jsonSchema": { "type": [ "string", "null" ], "description": "The time at which the file was created (RFC 3339 date-time)." }, "nullable": true, "handle": "createdTime" }, { "description": "The last time the file was modified by anyone (RFC 3339 date-time).", "jsonSchema": { "type": [ "string", "null" ], "description": "The last time the file was modified by anyone (RFC 3339 date-time)." }, "nullable": true, "handle": "modifiedTime" }, { "description": "The size of the file's content in bytes.", "jsonSchema": { "type": [ "integer", "null" ], "description": "The size of the file's content in bytes." }, "nullable": true, "handle": "sizeBytes" }, { "description": "The ID of the shared drive the file belongs to.", "jsonSchema": { "type": [ "string", "null" ], "description": "The ID of the shared drive the file belongs to." }, "nullable": true, "handle": "driveId" }, { "description": "The IDs of the parent folders containing the file.", "jsonSchema": { "type": "array", "items": { "type": "string", "description": "An array item." }, "description": "The IDs of the parent folders containing the file." }, "nullable": true, "handle": "parents" }, { "description": "The owners of the file.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "displayName": { "type": [ "string", "null" ], "description": "The display name of the owner." }, "emailAddress": { "type": [ "string", "null" ], "description": "The email address of the owner." }, "permissionId": { "type": [ "string", "null" ], "description": "The permission ID of the owner." }, "photoLink": { "type": [ "string", "null" ], "description": "A link to the owner's profile photo." } }, "required": [ "displayName", "emailAddress", "permissionId", "photoLink" ], "additionalProperties": false, "description": "Schema for driveOwnerSchema." }, "description": "The owners of the file." }, "nullable": true, "handle": "owners" }, { "description": "Whether the file has been shared.", "jsonSchema": { "type": "boolean", "description": "Whether the file has been shared." }, "nullable": true, "handle": "shared" }, { "description": "Whether the user has starred the file.", "jsonSchema": { "type": "boolean", "description": "Whether the user has starred the file." }, "nullable": true, "handle": "starred" }, { "description": "Whether the file has been trashed.", "jsonSchema": { "type": "boolean", "description": "Whether the file has been trashed." }, "nullable": true, "handle": "trashed" }, { "description": "Whether the authenticated user owns the file.", "jsonSchema": { "type": "boolean", "description": "Whether the authenticated user owns the file." }, "nullable": true, "handle": "ownedByMe" }, { "description": "The projected Drive capabilities for the authenticated user.", "jsonSchema": { "type": "object", "properties": { "canShare": { "type": "boolean", "description": "Whether the authenticated user may modify sharing settings." } }, "required": [ "canShare" ], "additionalProperties": false, "description": "The projected Drive capabilities for the authenticated user." }, "nullable": true, "handle": "capabilities" } ], "name": "Create backup folder", "executor": { "kind": "connector", "action": "googledrive.files.create" } } }, "n_0e74eb4b3e276554": { "inputs": { "previous": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_0e74eb4b3e276554", "output": "state" } ] } }, "name": "Read all n8n workflows", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": true, "handle": "previous" } ], "outputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "state" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "more" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "hasWorkflow" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "workflow" }, { "jsonSchema": { "type": "integer", "minimum": 0 }, "nullable": false, "handle": "count" } ], "name": "Read all n8n workflows", "moduleId": "n_6fe839055d323834", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [ { "action": "n8n.list_workflows" } ] } ] } }, "n_718e2f39c6de2daf": { "inputs": {}, "name": "Workflow in page?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "yes", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_0e74eb4b3e276554", "output": "hasWorkflow" } }, "operator": "isTrue" } ] } ] } ] }, "n_ab2c8ba02823ef2d": { "inputs": { "workflow": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_0e74eb4b3e276554", "output": "workflow" } ] }, "folderId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_06707f358eec533e", "output": "id" } ] } }, "name": "Prepare workflow JSON", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "workflow" }, { "jsonSchema": { "type": "string", "description": "The unique identifier of the file." }, "nullable": false, "handle": "folderId" } ], "outputs": [ { "jsonSchema": { "type": "string", "minLength": 1, "description": "The name of the file." }, "nullable": false, "handle": "name" }, { "jsonSchema": { "type": "array", "items": { "type": "string", "minLength": 1, "description": "Schema for nonEmptyString." }, "minItems": 1, "description": "A list of parent folder IDs to place the file in." }, "nullable": false, "handle": "parents" }, { "jsonSchema": { "type": "string", "minLength": 1, "description": "Connector media upload content encoded as a Base64 string." }, "nullable": false, "handle": "contentBase64" } ], "name": "Prepare workflow JSON", "moduleId": "n_8e73bdd0d3e4af92", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_96d0e8e8caeb9216": { "inputs": {}, "name": "More workflow pages?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "yes", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_0e74eb4b3e276554", "output": "more" } }, "operator": "isTrue" } ] } ] } ] }, "n_fe8955e2745211ec": { "inputs": { "name": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_ab2c8ba02823ef2d", "output": "name" } ] }, "mimeType": { "kind": "value", "value": "application/json" }, "parents": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_ab2c8ba02823ef2d", "output": "parents" } ] }, "contentBase64": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_ab2c8ba02823ef2d", "output": "contentBase64" } ] } }, "name": "Save workflow JSON", "kind": "task", "task": { "inputs": [ { "description": "The name of the file.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The name of the file." }, "nullable": true, "handle": "name", "value": null }, { "description": "The MIME type of the file.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The MIME type of the file." }, "nullable": true, "handle": "mimeType", "value": null }, { "description": "A short description of the file.", "jsonSchema": { "type": "string", "minLength": 1, "description": "A short description of the file." }, "nullable": true, "handle": "description", "value": null }, { "description": "A list of parent folder IDs to place the file in.", "jsonSchema": { "type": "array", "items": { "type": "string", "minLength": 1, "description": "Schema for nonEmptyString." }, "minItems": 1, "description": "A list of parent folder IDs to place the file in." }, "nullable": true, "handle": "parents", "value": null }, { "description": "Whether the user has starred the file.", "jsonSchema": { "type": "boolean", "description": "Whether the user has starred the file." }, "nullable": true, "handle": "starred", "value": null }, { "description": "A collection of arbitrary key-value pairs which are private to the requesting app.", "jsonSchema": { "type": "object", "additionalProperties": { "type": "string", "description": "A record value." }, "description": "A collection of arbitrary key-value pairs which are private to the requesting app." }, "nullable": true, "handle": "appProperties", "value": null }, { "description": "A collection of arbitrary key-value pairs which are visible to all apps.", "jsonSchema": { "type": "object", "additionalProperties": { "type": "string", "description": "A record value." }, "description": "A collection of arbitrary key-value pairs which are visible to all apps." }, "nullable": true, "handle": "properties", "value": null }, { "description": "Connector media upload content encoded as a Base64 string.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Connector media upload content encoded as a Base64 string." }, "nullable": true, "handle": "contentBase64", "value": null }, { "description": "Connector text media upload content.", "jsonSchema": { "type": "string", "description": "Connector text media upload content." }, "nullable": true, "handle": "text", "value": null } ], "outputs": [ { "description": "The unique identifier of the file.", "jsonSchema": { "type": "string", "description": "The unique identifier of the file." }, "nullable": false, "handle": "id" }, { "description": "The name of the file.", "jsonSchema": { "type": "string", "description": "The name of the file." }, "nullable": false, "handle": "name" }, { "description": "The MIME type of the file.", "jsonSchema": { "type": "string", "description": "The MIME type of the file." }, "nullable": false, "handle": "mimeType" }, { "description": "A link for opening the file in a relevant Google editor or viewer in a browser.", "jsonSchema": { "type": [ "string", "null" ], "description": "A link for opening the file in a relevant Google editor or viewer in a browser." }, "nullable": true, "handle": "webViewLink" }, { "description": "The time at which the file was created (RFC 3339 date-time).", "jsonSchema": { "type": [ "string", "null" ], "description": "The time at which the file was created (RFC 3339 date-time)." }, "nullable": true, "handle": "createdTime" }, { "description": "The last time the file was modified by anyone (RFC 3339 date-time).", "jsonSchema": { "type": [ "string", "null" ], "description": "The last time the file was modified by anyone (RFC 3339 date-time)." }, "nullable": true, "handle": "modifiedTime" }, { "description": "The size of the file's content in bytes.", "jsonSchema": { "type": [ "integer", "null" ], "description": "The size of the file's content in bytes." }, "nullable": true, "handle": "sizeBytes" }, { "description": "The ID of the shared drive the file belongs to.", "jsonSchema": { "type": [ "string", "null" ], "description": "The ID of the shared drive the file belongs to." }, "nullable": true, "handle": "driveId" }, { "description": "The IDs of the parent folders containing the file.", "jsonSchema": { "type": "array", "items": { "type": "string", "description": "An array item." }, "description": "The IDs of the parent folders containing the file." }, "nullable": true, "handle": "parents" }, { "description": "The owners of the file.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "displayName": { "type": [ "string", "null" ], "description": "The display name of the owner." }, "emailAddress": { "type": [ "string", "null" ], "description": "The email address of the owner." }, "permissionId": { "type": [ "string", "null" ], "description": "The permission ID of the owner." }, "photoLink": { "type": [ "string", "null" ], "description": "A link to the owner's profile photo." } }, "required": [ "displayName", "emailAddress", "permissionId", "photoLink" ], "additionalProperties": false, "description": "Schema for driveOwnerSchema." }, "description": "The owners of the file." }, "nullable": true, "handle": "owners" }, { "description": "Whether the file has been shared.", "jsonSchema": { "type": "boolean", "description": "Whether the file has been shared." }, "nullable": true, "handle": "shared" }, { "description": "Whether the user has starred the file.", "jsonSchema": { "type": "boolean", "description": "Whether the user has starred the file." }, "nullable": true, "handle": "starred" }, { "description": "Whether the file has been trashed.", "jsonSchema": { "type": "boolean", "description": "Whether the file has been trashed." }, "nullable": true, "handle": "trashed" }, { "description": "Whether the authenticated user owns the file.", "jsonSchema": { "type": "boolean", "description": "Whether the authenticated user owns the file." }, "nullable": true, "handle": "ownedByMe" }, { "description": "The projected Drive capabilities for the authenticated user.", "jsonSchema": { "type": "object", "properties": { "canShare": { "type": "boolean", "description": "Whether the authenticated user may modify sharing settings." } }, "required": [ "canShare" ], "additionalProperties": false, "description": "The projected Drive capabilities for the authenticated user." }, "nullable": true, "handle": "capabilities" } ], "name": "Save workflow JSON", "executor": { "kind": "connector", "action": "googledrive.files.create" } } }, "n_0614cab26aa05517": { "inputs": { "id": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_fe8955e2745211ec", "output": "id" } ] } }, "name": "Confirm backup file", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string", "description": "The unique identifier of the file." }, "nullable": false, "handle": "id" } ], "outputs": [ { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "ok" } ], "name": "Confirm backup file", "moduleId": "n_57d478b13e8f802a", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_364f7352d4c0b414": { "inputs": { "root": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_8d42d00ca914195e", "output": "root" } ] }, "newFolderId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_06707f358eec533e", "output": "id" } ] }, "count": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_0e74eb4b3e276554", "output": "count" } ] } }, "name": "Find old items to remove", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "root" }, { "jsonSchema": { "type": "string", "description": "The unique identifier of the file." }, "nullable": false, "handle": "newFolderId" }, { "jsonSchema": { "type": "integer", "minimum": 0 }, "nullable": false, "handle": "count" } ], "outputs": [ { "jsonSchema": { "type": "array", "items": { "type": "string" } }, "nullable": false, "handle": "ids" } ], "name": "Find old items to remove", "moduleId": "n_c940bc1cab82f13c", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [ { "action": "googledrive.files.list" } ] } ] } }, "n_c415136c4c186a92": { "inputs": { "ids": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_364f7352d4c0b414", "output": "ids" } ] }, "previous": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_c415136c4c186a92", "output": "state" } ] } }, "name": "Choose next old item", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "array", "items": { "type": "string" } }, "nullable": false, "handle": "ids" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": true, "handle": "previous" } ], "outputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "state" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "more" }, { "jsonSchema": { "type": "string", "minLength": 1, "description": "The ID of the file." }, "nullable": false, "handle": "id" } ], "name": "Choose next old item", "moduleId": "n_08ea239b6ce0ad13", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_0315503f8a9687b8": { "inputs": {}, "name": "More old items?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "yes", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_c415136c4c186a92", "output": "more" } }, "operator": "isTrue" } ] } ] } ] }, "n_86c7a7576d134b61": { "inputs": { "fileId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_c415136c4c186a92", "output": "id" } ] } }, "name": "Permanently delete old item", "kind": "task", "task": { "inputs": [ { "description": "The ID of the file.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The ID of the file." }, "nullable": true, "handle": "fileId", "value": null }, { "description": "When true, includes files from shared drives.", "jsonSchema": { "type": "boolean", "description": "When true, includes files from shared drives." }, "nullable": true, "handle": "includeSharedDrives", "value": null } ], "outputs": [ { "description": "The unique identifier of the deleted file.", "jsonSchema": { "type": "string", "description": "The unique identifier of the deleted file." }, "nullable": false, "handle": "fileId" }, { "description": "Indicates that the file was successfully deleted.", "jsonSchema": { "const": true, "description": "Indicates that the file was successfully deleted." }, "nullable": false, "handle": "deleted" } ], "name": "Permanently delete old item", "executor": { "kind": "connector", "action": "googledrive.files.delete" } } } }, "edges": [ { "source": "n_512dc98acc0bb809", "target": "n_8d42d00ca914195e" }, { "source": "n_aba04c26ec089a43", "target": "n_8d42d00ca914195e" }, { "source": "n_8d42d00ca914195e", "target": "n_06707f358eec533e" }, { "source": "n_06707f358eec533e", "target": "n_0e74eb4b3e276554" }, { "source": "n_0e74eb4b3e276554", "target": "n_718e2f39c6de2daf" }, { "source": "n_718e2f39c6de2daf", "target": "n_ab2c8ba02823ef2d", "sourceHandle": "yes" }, { "source": "n_718e2f39c6de2daf", "target": "n_96d0e8e8caeb9216", "sourceHandle": "otherwise" }, { "source": "n_ab2c8ba02823ef2d", "target": "n_fe8955e2745211ec" }, { "source": "n_fe8955e2745211ec", "target": "n_0614cab26aa05517" }, { "source": "n_0614cab26aa05517", "target": "n_96d0e8e8caeb9216" }, { "source": "n_96d0e8e8caeb9216", "target": "n_0e74eb4b3e276554", "sourceHandle": "yes" }, { "source": "n_96d0e8e8caeb9216", "target": "n_364f7352d4c0b414", "sourceHandle": "otherwise" }, { "source": "n_364f7352d4c0b414", "target": "n_c415136c4c186a92" }, { "source": "n_c415136c4c186a92", "target": "n_0315503f8a9687b8" }, { "source": "n_0315503f8a9687b8", "target": "n_86c7a7576d134b61", "sourceHandle": "yes" }, { "source": "n_86c7a7576d134b61", "target": "n_c415136c4c186a92" } ] } }, "modules": { "n_c00a5a1d3a1e6976": { "name": "Prepare backup folder", "imports": [], "source": "export default function folder({root}){if(typeof root!=='string'||!root.trim()||root.startsWith('YOUR_'))throw Error('Configure a dedicated backup folder ID');return{root,name:'Workflow Backups '+new Date().toISOString(),mimeType:'application/vnd.google-apps.folder',parents:[root]}}\n" }, "n_6fe839055d323834": { "name": "Read all n8n workflows", "imports": [], "source": "export default async function collect({previous},context){const s=previous??{cursor:null,count:0};if(!Number.isInteger(s.count)||s.count<0)throw Error('Invalid backup progress');const r=await context.actions.call('n8n.list_workflows',{limit:1,...(s.cursor?{cursor:s.cursor}:{})});if(!Array.isArray(r?.data)||r.data.length>1||(r.nextCursor!==null&&(typeof r.nextCursor!=='string'||!r.nextCursor)))throw Error('Invalid n8n workflow page');if(r.nextCursor&&r.nextCursor===s.cursor)throw Error('Repeated workflow cursor');const w=r.data[0];if(w&&(typeof w.id!=='string'||!w.id||typeof w.name!=='string'||!w.name||!Array.isArray(w.nodes)||!w.connections||!w.settings))throw Error('Incomplete workflow in backup');const count=s.count+(w?1:0);return{state:{cursor:r.nextCursor,count},more:r.nextCursor!==null,hasWorkflow:!!w,workflow:w??{},count}}\n" }, "n_8e73bdd0d3e4af92": { "name": "Prepare workflow JSON", "imports": [], "source": "import{Buffer}from'node:buffer';export default function next({workflow,folderId}){if(!folderId||typeof workflow?.name!=='string'||!workflow.name)throw Error('Missing backup folder or workflow');return{name:workflow.name+'.json',parents:[folderId],contentBase64:Buffer.from(JSON.stringify(workflow,null,2),'utf8').toString('base64')}}\n" }, "n_57d478b13e8f802a": { "name": "Confirm backup file", "imports": [], "source": "export default function attachmentReceipt({id}){if(typeof id!=='string'||!id)throw Error('Drive did not confirm file creation; inspect Drive before retrying');return {ok:true};}\n" }, "n_c940bc1cab82f13c": { "name": "Find old items to remove", "imports": [], "source": "export default async function cleanup({root,newFolderId,count},context){if(!count)return{ids:[]};if(typeof root!=='string'||!root||!newFolderId)throw Error('Missing backup folder');const escaped=root.replace(/\\\\/g,'\\\\\\\\').replace(/'/g,\"\\\\'\");const r=await context.actions.call('googledrive.files.list',{q:`'${escaped}' in parents and trashed = false and mimeType = 'application/vnd.google-apps.folder' and name contains 'Workflow Backups '`,pageSize:50});if(!Array.isArray(r?.files))throw Error('Invalid Drive listing');const ids=[];for(const f of r.files){if(typeof f?.id!=='string'||!f.id||typeof f.name!=='string'||typeof f.mimeType!=='string')throw Error('Invalid Drive item');if(f.mimeType==='application/vnd.google-apps.folder'&&f.name.startsWith('Workflow Backups ')&&f.id.toLowerCase()!==newFolderId.toLowerCase())ids.push(f.id)}return{ids}}\n" }, "n_08ea239b6ce0ad13": { "name": "Choose next old item", "imports": [], "source": "export default function next({ids,previous}){if(!Array.isArray(ids))throw Error('Invalid cleanup list');const index=previous==null?0:previous.index+1;if(!Number.isInteger(index)||index<0||index>ids.length)throw Error('Invalid cleanup progress');return{state:{index},more:index