{
"name": "Container Update",
"nodes": [
{
"parameters": {
"inputSource": "passthrough",
"schema": {
"schemaType": "fromFields",
"fields": [
{
"fieldName": "containerId",
"fieldType": "string"
},
{
"fieldName": "containerName",
"fieldType": "string"
},
{
"fieldName": "chatId",
"fieldType": "number"
},
{
"fieldName": "messageId",
"fieldType": "number"
},
{
"fieldName": "responseMode",
"fieldType": "string"
},
{
"fieldName": "correlationId",
"fieldType": "string"
}
]
}
},
"id": "sub-trigger",
"name": "When executed by another workflow",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"typeVersion": 1.1,
"position": [
240,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"typeValidation": "loose"
},
"conditions": [
{
"id": "has-container-id",
"leftValue": "={{ $json.containerId }}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "notEquals"
}
}
],
"combinator": "and"
}
},
"id": "if-has-id",
"name": "Has Container ID?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
400,
300
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $env.UNRAID_HOST }}/graphql",
"authentication": "none",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "x-api-key",
"value": "={{ $env.UNRAID_API_KEY }}"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\"query\": \"query { docker { containers { id names state image imageId } } }\"}",
"options": {
"timeout": 15000
}
},
"id": "http-query-containers",
"name": "Query All Containers",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
560,
400
],
"onError": "continueRegularOutput"
},
{
"parameters": {
"jsCode": "// GraphQL Response Normalizer - Transform Unraid GraphQL to Docker API contract\n// Input: $input.item.json = raw GraphQL response\n// Output: Array of normalized containers\n\nconst response = $input.item.json;\n\n// Validation: Check for GraphQL errors\nif (response.errors && response.errors.length > 0) {\n const messages = response.errors.map(e => e.message).join('; ');\n throw new Error(`GraphQL error: ${messages}`);\n}\n\n// Validation: Check response structure\nif (!response.data?.docker?.containers) {\n throw new Error('Invalid GraphQL response structure: missing data.docker.containers');\n}\n\n// State mapping: Unraid UPPERCASE -> Docker lowercase\nconst stateMap = {\n 'RUNNING': 'running',\n 'STOPPED': 'exited', // Docker convention: stopped = exited\n 'PAUSED': 'paused'\n};\n\nfunction normalizeState(unraidState) {\n return stateMap[unraidState] || unraidState.toLowerCase();\n}\n\n// Transform each container\nconst containers = response.data.docker.containers;\nconst normalized = containers.map(container => {\n const dockerState = normalizeState(container.state);\n \n return {\n // Core fields matching Docker API contract\n Id: container.id, // Keep full PrefixedID (registry handles translation)\n Names: container.names, // Already has '/' prefix (Phase 14 verified)\n State: dockerState, // Normalized lowercase state\n Status: dockerState, // Docker has separate Status field\n Image: '', // Not available in basic query\n \n // Debug field: preserve original Unraid ID\n _unraidId: container.id\n };\n});\n\n// Return as array of items (n8n multi-item output format)\nreturn normalized.map(container => ({ json: container }));\n"
},
"id": "code-normalize-response",
"name": "Normalize GraphQL Response",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
720,
400
]
},
{
"id": "code-update-registry",
"name": "Update Container ID Registry",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
880,
400
],
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "// Container ID Registry - Update action only\nconst registry = $getWorkflowStaticData('global');\nif (!registry._containerIdMap) {\n registry._containerIdMap = JSON.stringify({});\n}\n\nconst containers = $input.all().map(item => item.json);\nconst containerMap = JSON.parse(registry._containerIdMap);\n\n// Update map from normalized containers\nfor (const container of containers) {\n const name = (container.Names?.[0] || '').replace(/^\\//, '').toLowerCase();\n if (name && container.Id) {\n containerMap[name] = {\n name: name,\n unraidId: container.Id,\n timestamp: Date.now()\n };\n }\n}\n\nregistry._containerIdMap = JSON.stringify(containerMap);\nregistry._lastRefresh = Date.now();\n\n// Pass through all containers\nreturn containers.map(c => ({ json: c }));\n"
}
},
{
"parameters": {
"jsCode": "// Find container by name and resolve ID\nconst triggerData = $('When executed by another workflow').item.json;\nconst containerName = triggerData.containerName;\nconst containers = $input.all();\n\n// Normalize function to strip leading slash\nconst normalizeName = (name) => name.replace(/^\\//, '').toLowerCase();\nconst searchName = normalizeName(containerName);\n\n// Find matching container\nlet matched = null;\nfor (const item of containers) {\n const c = item.json;\n if (c.Names && c.Names.length > 0) {\n const cName = normalizeName(c.Names[0]);\n if (cName === searchName || cName.includes(searchName)) {\n matched = c;\n break;\n }\n }\n}\n\nif (!matched) {\n throw new Error(`Container '${containerName}' not found`);\n}\n\nreturn {\n json: {\n ...triggerData,\n containerId: matched.Id,\n unraidId: matched.Id, // Full PrefixedID for GraphQL mutation\n currentImageId: matched.imageId || '', // For later comparison\n currentImage: matched.image || ''\n }\n};\n"
},
"id": "code-resolve-id",
"name": "Resolve Container ID",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1040,
400
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $env.UNRAID_HOST }}/graphql",
"authentication": "none",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "x-api-key",
"value": "={{ $env.UNRAID_API_KEY }}"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ {\"query\": \"query { docker { containers(filter: { id: \\\"\" + $json.containerId + \"\\\" }) { id names state image imageId } } }\"} }}",
"options": {
"timeout": 15000
}
},
"id": "http-query-single",
"name": "Query Single Container",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
560,
300
],
"onError": "continueRegularOutput"
},
{
"parameters": {
"jsCode": "// GraphQL Response Normalizer - Transform Unraid GraphQL to Docker API contract\n// Input: $input.item.json = raw GraphQL response\n// Output: Array of normalized containers\n\nconst response = $input.item.json;\n\n// Validation: Check for GraphQL errors\nif (response.errors && response.errors.length > 0) {\n const messages = response.errors.map(e => e.message).join('; ');\n throw new Error(`GraphQL error: ${messages}`);\n}\n\n// Validation: Check response structure\nif (!response.data?.docker?.containers) {\n throw new Error('Invalid GraphQL response structure: missing data.docker.containers');\n}\n\n// State mapping: Unraid UPPERCASE -> Docker lowercase\nconst stateMap = {\n 'RUNNING': 'running',\n 'STOPPED': 'exited', // Docker convention: stopped = exited\n 'PAUSED': 'paused'\n};\n\nfunction normalizeState(unraidState) {\n return stateMap[unraidState] || unraidState.toLowerCase();\n}\n\n// Transform each container\nconst containers = response.data.docker.containers;\nconst normalized = containers.map(container => {\n const dockerState = normalizeState(container.state);\n \n return {\n // Core fields matching Docker API contract\n Id: container.id, // Keep full PrefixedID (registry handles translation)\n Names: container.names, // Already has '/' prefix (Phase 14 verified)\n State: dockerState, // Normalized lowercase state\n Status: dockerState, // Docker has separate Status field\n Image: '', // Not available in basic query\n \n // Debug field: preserve original Unraid ID\n _unraidId: container.id\n };\n});\n\n// Return as array of items (n8n multi-item output format)\nreturn normalized.map(container => ({ json: container }));\n"
},
"id": "code-normalize-single",
"name": "Normalize Single Container",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
720,
300
]
},
{
"parameters": {
"jsCode": "// Capture pre-update state from input\nconst data = $input.item.json;\nconst triggerData = $('When executed by another workflow').item.json;\n\n// Check if we have container data already (from Resolve path) or need to extract (from direct ID path)\nlet unraidId, containerName, currentImageId, currentImage;\n\nif (data.unraidId) {\n // From Resolve Container ID path\n unraidId = data.unraidId;\n containerName = data.containerName;\n currentImageId = data.currentImageId;\n currentImage = data.currentImage;\n} else if (data.Id) {\n // From Query Single Container path (normalized)\n unraidId = data.Id;\n containerName = (data.Names?.[0] || '').replace(/^\\//, '');\n currentImageId = data.imageId || '';\n currentImage = data.image || '';\n} else {\n throw new Error('No container data found');\n}\n\nreturn {\n json: {\n unraidId,\n containerName,\n currentImageId,\n currentImage,\n chatId: triggerData.chatId,\n messageId: triggerData.messageId,\n responseMode: triggerData.responseMode,\n correlationId: triggerData.correlationId || ''\n }\n};\n"
},
"id": "code-capture-state",
"name": "Capture Pre-Update State",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
920,
300
]
},
{
"parameters": {
"jsCode": "// Build GraphQL updateContainer mutation\nconst data = $input.item.json;\nreturn {\n json: {\n ...data,\n query: `mutation { docker { updateContainer(id: \"${data.unraidId}\") { id state image imageId } } }`\n }\n};\n"
},
"id": "code-build-mutation",
"name": "Build Update Mutation",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1120,
300
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $env.UNRAID_HOST }}/graphql",
"authentication": "none",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "x-api-key",
"value": "={{ $env.UNRAID_API_KEY }}"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ {\"query\": $json.query} }}",
"options": {
"timeout": 60000
}
},
"id": "http-update-container",
"name": "Update Container",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1320,
300
],
"onError": "continueRegularOutput"
},
{
"parameters": {
"jsCode": "// Handle updateContainer mutation response\nconst response = $input.item.json;\nconst prevData = $('Capture Pre-Update State').item.json;\n\n// Check for GraphQL errors\nif (response.errors) {\n const error = response.errors[0];\n return {\n json: {\n success: false,\n error: true,\n errorMessage: error.message || 'Update failed',\n ...prevData\n }\n };\n}\n\n// Extract updated container from response\nconst updated = response.data?.docker?.updateContainer;\nif (!updated) {\n return {\n json: {\n success: false,\n error: true,\n errorMessage: 'No response from update mutation',\n ...prevData\n }\n };\n}\n\n// Compare imageId to determine if update happened\nconst newImageId = updated.imageId || '';\nconst oldImageId = prevData.currentImageId || '';\nconst wasUpdated = (newImageId !== oldImageId);\n\nreturn {\n json: {\n success: true,\n needsUpdate: wasUpdated,\n updated: wasUpdated,\n containerName: prevData.containerName,\n currentVersion: prevData.currentImage,\n newVersion: updated.image,\n currentImageId: oldImageId,\n newImageId: newImageId,\n chatId: prevData.chatId,\n messageId: prevData.messageId,\n responseMode: prevData.responseMode,\n correlationId: prevData.correlationId\n }\n};\n"
},
"id": "code-handle-response",
"name": "Handle Update Response",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1520,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "is-success",
"leftValue": "={{ $json.error }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "notEquals"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "if-update-success",
"name": "Check Update Success",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1720,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "was-updated",
"leftValue": "={{ $json.needsUpdate }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "if-was-updated",
"name": "Check If Updated",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1920,
200
]
},
{
"parameters": {
"jsCode": "// Format update success result\nconst data = $('Handle Update Response').item.json;\nconst containerName = data.containerName;\nconst currentVersion = data.currentVersion;\nconst newVersion = data.newVersion;\n\nconst message = `${containerName} updated: ${currentVersion} \\u2192 ${newVersion}`;\n\nreturn {\n json: {\n success: true,\n updated: true,\n message,\n oldDigest: currentVersion,\n newDigest: newVersion,\n chatId: data.chatId,\n messageId: data.messageId,\n responseMode: data.responseMode,\n containerName: containerName,\n correlationId: data.correlationId || ''\n }\n};\n"
},
"id": "code-format-success",
"name": "Format Update Success",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1960,
200
]
},
{
"parameters": {
"rules": {
"values": [
{
"id": "is-inline",
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "inline-check",
"leftValue": "={{ $json.responseMode }}",
"rightValue": "inline",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"outputKey": "inline"
},
{
"id": "is-batch",
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "batch-check",
"leftValue": "={{ $json.responseMode }}",
"rightValue": "batch",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"outputKey": "batch"
}
]
},
"options": {
"fallbackOutput": "extra"
}
},
"id": "if-response-mode-success",
"name": "Check Response Mode (Success)",
"type": "n8n-nodes-base.switch",
"typeVersion": 3.2,
"position": [
2180,
200
]
},
{
"parameters": {
"method": "POST",
"url": "=https://api.telegram.org/bot{{ $env.TELEGRAM_BOT_TOKEN }}/editMessageText",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ chat_id: $json.chatId, message_id: $json.messageId, text: '\\u2705 ' + $json.message, parse_mode: 'HTML', reply_markup: { inline_keyboard: [[{ text: '\\u25C0\\uFE0F Back to Containers', callback_data: 'list:0' }]] } }) }}",
"options": {}
},
"id": "http-send-inline-success",
"name": "Send Inline Success",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2400,
100
]
},
{
"parameters": {
"resource": "message",
"operation": "sendMessage",
"chatId": "={{ $json.chatId }}",
"text": "={{ $json.message }}",
"additionalFields": {
"parse_mode": "HTML"
}
},
"id": "telegram-send-text-success",
"name": "Send Text Success",
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
2400,
300
],
"credentials": {
"telegramApi": {
"id": "I0xTTiASl7C1NZhJ",
"name": "Telegram account"
}
}
},
{
"parameters": {
"jsCode": "// Return final success result\nconst data = $('Format Update Success').item.json;\nreturn {\n json: {\n success: true,\n updated: true,\n message: data.message,\n oldDigest: data.oldDigest,\n newDigest: data.newDigest,\n correlationId: data.correlationId || ''\n }\n};"
},
"id": "code-return-success",
"name": "Return Success",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2620,
200
]
},
{
"parameters": {
"jsCode": "// Format 'already up to date' result\nconst data = $('Handle Update Response').item.json;\nconst containerName = data.containerName;\n\nconst message = `${containerName} is already up to date`;\n\nreturn {\n json: {\n success: true,\n updated: false,\n message,\n chatId: data.chatId,\n messageId: data.messageId,\n responseMode: data.responseMode,\n containerName: containerName,\n correlationId: data.correlationId || ''\n }\n};\n"
},
"id": "code-format-no-update",
"name": "Format No Update Needed",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1960,
400
]
},
{
"parameters": {
"rules": {
"values": [
{
"id": "is-inline-no-update",
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "inline-check",
"leftValue": "={{ $json.responseMode }}",
"rightValue": "inline",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"outputKey": "inline"
},
{
"id": "is-batch-no-update",
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "batch-check",
"leftValue": "={{ $json.responseMode }}",
"rightValue": "batch",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"outputKey": "batch"
}
]
},
"options": {
"fallbackOutput": "extra"
}
},
"id": "if-response-mode-no-update",
"name": "Check Response Mode (No Update)",
"type": "n8n-nodes-base.switch",
"typeVersion": 3.2,
"position": [
2180,
400
]
},
{
"parameters": {
"method": "POST",
"url": "=https://api.telegram.org/bot{{ $env.TELEGRAM_BOT_TOKEN }}/editMessageText",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ chat_id: $json.chatId, message_id: $json.messageId, text: '\\u2705 ' + $json.message, parse_mode: 'HTML', reply_markup: { inline_keyboard: [[{ text: '\\u25C0\\uFE0F Back to Containers', callback_data: 'list:0' }]] } }) }}",
"options": {}
},
"id": "http-send-inline-no-update",
"name": "Send Inline No Update",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
2400,
400
]
},
{
"parameters": {
"resource": "message",
"operation": "sendMessage",
"chatId": "={{ $json.chatId }}",
"text": "={{ $json.message }}",
"additionalFields": {
"parse_mode": "HTML"
}
},
"id": "telegram-send-text-no-update",
"name": "Send Text No Update",
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
2400,
500
],
"credentials": {
"telegramApi": {
"id": "I0xTTiASl7C1NZhJ",
"name": "Telegram account"
}
}
},
{
"parameters": {
"jsCode": "// Return no update result\nconst data = $('Format No Update Needed').item.json;\nreturn {\n json: {\n success: true,\n updated: false,\n message: data.message,\n correlationId: data.correlationId || ''\n }\n};"
},
"id": "code-return-no-update",
"name": "Return No Update",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2620,
400
]
},
{
"parameters": {
"jsCode": "// Format update error result\nconst data = $('Handle Update Response').item.json;\nconst containerName = data.containerName;\nconst errorMessage = data.errorMessage;\n\nconst message = `Failed to update ${containerName}: ${errorMessage}`;\n\nreturn {\n json: {\n success: false,\n updated: false,\n message,\n error: {\n workflow: 'n8n-update',\n node: 'Update Container',\n message: errorMessage,\n httpCode: null,\n rawResponse: errorMessage\n },\n correlationId: data.correlationId || '',\n chatId: data.chatId,\n messageId: data.messageId,\n responseMode: data.responseMode,\n containerName: containerName\n }\n};\n"
},
"id": "code-format-pull-error",
"name": "Format Update Error",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1540,
500
]
},
{
"parameters": {
"rules": {
"values": [
{
"id": "is-inline-error",
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "inline-check",
"leftValue": "={{ $json.responseMode }}",
"rightValue": "inline",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"outputKey": "inline"
},
{
"id": "is-batch-error",
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "batch-check",
"leftValue": "={{ $json.responseMode }}",
"rightValue": "batch",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"outputKey": "batch"
}
]
},
"options": {
"fallbackOutput": "extra"
}
},
"id": "if-response-mode-error",
"name": "Check Response Mode (Error)",
"type": "n8n-nodes-base.switch",
"typeVersion": 3.2,
"position": [
1760,
500
]
},
{
"parameters": {
"method": "POST",
"url": "=https://api.telegram.org/bot{{ $env.TELEGRAM_BOT_TOKEN }}/editMessageText",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ chat_id: $json.chatId, message_id: $json.messageId, text: '\\u274C ' + $json.message, parse_mode: 'HTML', reply_markup: { inline_keyboard: [[{ text: '\\u25C0\\uFE0F Back to Containers', callback_data: 'list:0' }]] } }) }}",
"options": {}
},
"id": "http-send-inline-error",
"name": "Send Inline Error",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1980,
500
]
},
{
"parameters": {
"resource": "message",
"operation": "sendMessage",
"chatId": "={{ $json.chatId }}",
"text": "={{ $json.message }}",
"additionalFields": {
"parse_mode": "HTML"
}
},
"id": "telegram-send-text-error",
"name": "Send Text Error",
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
1980,
600
],
"credentials": {
"telegramApi": {
"id": "I0xTTiASl7C1NZhJ",
"name": "Telegram account"
}
}
},
{
"parameters": {
"jsCode": "// Return error result\nconst data = $('Format Pull Error').item.json;\nreturn {\n json: {\n success: false,\n updated: false,\n message: data.message\n }\n};"
},
"id": "code-return-error",
"name": "Return Error",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
2200,
500
]
}
],
"connections": {
"When executed by another workflow": {
"main": [
[
{
"node": "Has Container ID?",
"type": "main",
"index": 0
}
]
]
},
"Has Container ID?": {
"main": [
[
{
"node": "Query Single Container",
"type": "main",
"index": 0
}
],
[
{
"node": "Query All Containers",
"type": "main",
"index": 0
}
]
]
},
"Query Single Container": {
"main": [
[
{
"node": "Normalize Single Container",
"type": "main",
"index": 0
}
]
]
},
"Normalize Single Container": {
"main": [
[
{
"node": "Capture Pre-Update State",
"type": "main",
"index": 0
}
]
]
},
"Query All Containers": {
"main": [
[
{
"node": "Normalize GraphQL Response",
"type": "main",
"index": 0
}
]
]
},
"Normalize GraphQL Response": {
"main": [
[
{
"node": "Update Container ID Registry",
"type": "main",
"index": 0
}
]
]
},
"Update Container ID Registry": {
"main": [
[
{
"node": "Resolve Container ID",
"type": "main",
"index": 0
}
]
]
},
"Resolve Container ID": {
"main": [
[
{
"node": "Capture Pre-Update State",
"type": "main",
"index": 0
}
]
]
},
"Capture Pre-Update State": {
"main": [
[
{
"node": "Build Update Mutation",
"type": "main",
"index": 0
}
]
]
},
"Build Update Mutation": {
"main": [
[
{
"node": "Update Container",
"type": "main",
"index": 0
}
]
]
},
"Update Container": {
"main": [
[
{
"node": "Handle Update Response",
"type": "main",
"index": 0
}
]
]
},
"Handle Update Response": {
"main": [
[
{
"node": "Check Update Success",
"type": "main",
"index": 0
}
]
]
},
"Check If Updated": {
"main": [
[
{
"node": "Format Update Success",
"type": "main",
"index": 0
}
],
[
{
"node": "Format No Update Needed",
"type": "main",
"index": 0
}
]
]
},
"Format Update Success": {
"main": [
[
{
"node": "Check Response Mode (Success)",
"type": "main",
"index": 0
}
]
]
},
"Check Response Mode (Success)": {
"main": [
[
{
"node": "Send Inline Success",
"type": "main",
"index": 0
}
],
[
{
"node": "Return Success",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Text Success",
"type": "main",
"index": 0
}
]
]
},
"Send Inline Success": {
"main": [
[
{
"node": "Return Success",
"type": "main",
"index": 0
}
]
]
},
"Send Text Success": {
"main": [
[
{
"node": "Return Success",
"type": "main",
"index": 0
}
]
]
},
"Format No Update Needed": {
"main": [
[
{
"node": "Check Response Mode (No Update)",
"type": "main",
"index": 0
}
]
]
},
"Check Response Mode (No Update)": {
"main": [
[
{
"node": "Send Inline No Update",
"type": "main",
"index": 0
}
],
[
{
"node": "Return No Update",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Text No Update",
"type": "main",
"index": 0
}
]
]
},
"Send Inline No Update": {
"main": [
[
{
"node": "Return No Update",
"type": "main",
"index": 0
}
]
]
},
"Send Text No Update": {
"main": [
[
{
"node": "Return No Update",
"type": "main",
"index": 0
}
]
]
},
"Format Update Error": {
"main": [
[
{
"node": "Check Response Mode (Error)",
"type": "main",
"index": 0
}
]
]
},
"Check Response Mode (Error)": {
"main": [
[
{
"node": "Send Inline Error",
"type": "main",
"index": 0
}
],
[
{
"node": "Return Error",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Text Error",
"type": "main",
"index": 0
}
]
]
},
"Send Inline Error": {
"main": [
[
{
"node": "Return Error",
"type": "main",
"index": 0
}
]
]
},
"Send Text Error": {
"main": [
[
{
"node": "Return Error",
"type": "main",
"index": 0
}
]
]
},
"Check Update Success": {
"main": [
[
{
"node": "Check If Updated",
"type": "main",
"index": 0
}
],
[
{
"node": "Format Update Error",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
}
}