[
    {
        "id": "9853720840c16267",
        "type": "comment",
        "z": "bdf7dc31543e1548",
        "name": "This flow expects secrets to be defined in qibb's Secret Manager: \\n AWS_SNS_TOPIC_ARN  \\n AWS_SNS_API_KEY  \\n AWS_SNS_API_SECRET  \\n AWS_SNS_TOPIC_REGION",
        "info": "Expected space secrets:\nAWS_SNS_TOPIC_ARN\nAWS_SNS_API_KEY\nAWS_SNS_API_SECRET\nAWS_SNS_TOPIC_REGION",
        "x": 860,
        "y": 220,
        "wires": []
    },
    {
        "id": "98068836fb5e6af6",
        "type": "group",
        "z": "bdf7dc31543e1548",
        "name": "Publish SNS notifications",
        "style": {
            "label": true
        },
        "nodes": [
            "36f18758ec92d46c",
            "f39e763047a93624",
            "598ff95f41e0e124"
        ],
        "x": 84,
        "y": 159,
        "w": 472,
        "h": 82
    },
    {
        "id": "36f18758ec92d46c",
        "type": "function",
        "z": "bdf7dc31543e1548",
        "g": "98068836fb5e6af6",
        "name": "Publish SNS message to topic",
        "func": "// Import the PublishCommand from the AWS SDK v3 package\nconst { PublishCommand } = awsSdkClientSns;\n\n// Retrieve the client and configuration from the node context (set in \"On Setup\")\nconst client = this.client;\nconst config = this.config;\n\n\nasync function publishNotification(){\n    try {\n        \n        // Define the parameters for publishing a message\n        const params = {\n            Message: JSON.stringify(msg.payload),  // Convert your payload to a string\n            TopicArn: config.topicArn,             // Your SNS topic ARN\n            Subject: \"SNS Test Notification\"       // Optional: A subject line for endpoints (e.g., email)\n        };\n\n        // Create the PublishCommand using the 'new' keyword\n        const command = new PublishCommand(params);\n\n        // Send the command to SNS and await the response\n        const data = await client.send(command);\n        // Attach the response to msg.payload and send the message along the flow\n        msg.payload = data;\n        node.send(msg);\n    } catch (error) {\n        node.error(\"Error publishing message: \" + error);\n    }\n}\n\n// Execute the publishNotification function asynchronously\npublishNotification();\n\n// Return null since output is handled asynchronously via node.send()\nreturn null;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "// Import required classes from the AWS SDK v3 package\nconst { SNSClient } = awsSdkClientSns;\n\n// Group configuration values in an object\nthis.config = {\n    topicArn: global.get(\"SECRETS.AWS_SNS_TOPIC_ARN\"), // e.g., \"arn:aws:sns:us-west-2:811950790052:flow-sns-test\"\n    accessKey: global.get(\"SECRETS.AWS_SNS_API_KEY\"),\n    accessSecret: global.get(\"SECRETS.AWS_SNS_API_SECRET\"),\n    region: global.get(\"SECRETS.AWS_SNS_TOPIC_REGION\")\n};\n\n// Create an SNS client instance and store it as a property of the node (this.client)\nthis.client = new SNSClient({\n    region: this.config.region,\n    credentials: {\n        accessKeyId: this.config.accessKey,\n        secretAccessKey: this.config.accessSecret\n    }\n});\n\n// Define a helper function for safely stringifying the msg (avoiding circular references)\nthis.removeCircular = function () {\n    const seen = new WeakSet();\n    return (key, value) => {\n        if (typeof value === 'object' && value !== null) {\n            if (seen.has(value)) {\n                return undefined;\n            }\n            seen.add(value);\n        }\n        return value;\n    };\n};\n\n",
        "finalize": "",
        "libs": [
            {
                "var": "awsSdkClientSns",
                "module": "@aws-sdk/client-sns"
            }
        ],
        "x": 320,
        "y": 200,
        "wires": [
            [
                "598ff95f41e0e124"
            ]
        ],
        "icon": "node-red/envelope.svg"
    },
    {
        "id": "f39e763047a93624",
        "type": "inject",
        "z": "bdf7dc31543e1548",
        "g": "98068836fb5e6af6",
        "name": "",
        "props": [
            {
                "p": "payload.test",
                "v": "",
                "vt": "date"
            },
            {
                "p": "payload.hello",
                "v": "world",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 145,
        "y": 200,
        "wires": [
            [
                "36f18758ec92d46c"
            ]
        ],
        "l": false
    },
    {
        "id": "598ff95f41e0e124",
        "type": "debug",
        "z": "bdf7dc31543e1548",
        "g": "98068836fb5e6af6",
        "name": "Send message",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "counter",
        "x": 495,
        "y": 200,
        "wires": [],
        "l": false
    },
    {
        "id": "ca757d3ab04f5fb4",
        "type": "group",
        "z": "bdf7dc31543e1548",
        "name": "Process incoming SNS notifications",
        "style": {
            "label": true
        },
        "nodes": [
            "01da0e73ff020fd7",
            "434e9a6a93e1fe2a",
            "7a1c75445ef46226",
            "ac0df1231fb1a5c5",
            "3dc91633dad35eef"
        ],
        "x": 74,
        "y": 419,
        "w": 762,
        "h": 142
    },
    {
        "id": "01da0e73ff020fd7",
        "type": "http in",
        "z": "bdf7dc31543e1548",
        "g": "ca757d3ab04f5fb4",
        "name": "",
        "url": "/sns-subscription",
        "method": "post",
        "upload": false,
        "swaggerDoc": "",
        "x": 200,
        "y": 460,
        "wires": [
            [
                "434e9a6a93e1fe2a",
                "ac0df1231fb1a5c5"
            ]
        ]
    },
    {
        "id": "434e9a6a93e1fe2a",
        "type": "http response",
        "z": "bdf7dc31543e1548",
        "g": "ca757d3ab04f5fb4",
        "name": "http response",
        "statusCode": "200",
        "headers": {},
        "x": 380,
        "y": 520,
        "wires": []
    },
    {
        "id": "7a1c75445ef46226",
        "type": "function",
        "z": "bdf7dc31543e1548",
        "g": "ca757d3ab04f5fb4",
        "name": "SNS Notification",
        "func": "//Check type of incoming SNS message\nswitch (msg.payload.Type) {\n    case \"SubscriptionConfirmation\":\n        confirmSubscription();\n        break;\n    case \"Notification\":\n        // Process and parse message\n        processNotification();\n        break;\n}\n\n// Function that parses and passes the notification to output\nfunction processNotification() {\n    msg.payload.Message = safeJSONParse(msg.payload.Message);\n    node.send(msg);\n}\n\n// Function that calls the AWS SNS Subscribe URL to confirm subscription\nasync function confirmSubscription() {\n    try {\n        node.log(\"Received SubscriptionConfirmation. Confirming subscription...\");\n        const response = await fetch(msg.payload.SubscribeURL);\n        const body = await response.text();\n        node.log(\"Confirmed subscription.\")\n    } catch (error) {\n        node.error(\"Error confirming subscription: \" + error);\n    }\n}\n\n// Helper function to safely parse JSON; returns original string if parsing fails\nfunction safeJSONParse(input) {\n    try {\n        return JSON.parse(input);\n    } catch (err) {\n        return input;\n    }\n}\n\nreturn null;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [
            {
                "var": "awsSdkClientSns",
                "module": "@aws-sdk/client-sns"
            },
            {
                "var": "fetch",
                "module": "node-fetch"
            }
        ],
        "x": 580,
        "y": 460,
        "wires": [
            [
                "3dc91633dad35eef"
            ]
        ],
        "icon": "font-awesome/fa-check-square"
    },
    {
        "id": "ac0df1231fb1a5c5",
        "type": "json",
        "z": "bdf7dc31543e1548",
        "g": "ca757d3ab04f5fb4",
        "name": "",
        "property": "payload",
        "action": "",
        "pretty": false,
        "x": 410,
        "y": 460,
        "wires": [
            [
                "7a1c75445ef46226"
            ]
        ]
    },
    {
        "id": "3dc91633dad35eef",
        "type": "debug",
        "z": "bdf7dc31543e1548",
        "g": "ca757d3ab04f5fb4",
        "name": "SNS confirmation",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "counter",
        "x": 775,
        "y": 460,
        "wires": [],
        "l": false
    },
    {
        "id": "79ba64f594279419",
        "type": "group",
        "z": "bdf7dc31543e1548",
        "name": "Setup an HTTP SNS Subscription, Registering flow endpoint /sns-subscription",
        "style": {
            "label": true
        },
        "nodes": [
            "453e8392da2d89a2",
            "c59c5e0a0c3cc1f0",
            "4a6c8bef8bb14eca"
        ],
        "x": 84,
        "y": 299,
        "w": 542,
        "h": 82
    },
    {
        "id": "453e8392da2d89a2",
        "type": "function",
        "z": "bdf7dc31543e1548",
        "g": "79ba64f594279419",
        "name": "Subscribe to SNS topic",
        "func": "// Import the SubscribeCommand from the AWS SDK v3 package\nconst { SubscribeCommand } = awsSdkClientSns;\n\n// Retrieve the client and config from the node context (set in \"On Setup\")\nconst client = this.client;\nconst config = this.config;\n\n// Define the subscription parameters\nconst params = {\n    TopicArn: config.topicArn,  // Your SNS topic ARN\n    Protocol: \"https\",          // Protocol to use for the subscription\n    Endpoint: config.endpointUrl // Your Node-RED endpoint URL for receiving confirmation\n};\n\nasync function setupSubscription(){\n    try {\n        // Create the subscription command using the 'new' keyword\n        const command = new SubscribeCommand(params);\n\n        // Send the command to SNS and wait for the response\n        const data = await client.send(command);\n        node.log(\"Subscription request created successfully. Data: \" + JSON.stringify(data));\n\n        // Attach the response to msg.payload and send the message along the flow\n        msg.payload = data;\n        node.send(msg);\n    } catch (error) {\n        node.error(\"Error creating subscription: \" + error);\n    }\n}\n\n// Execute the setupSubscription function asynchronously\nsetupSubscription();\n// Return null since output is handled asynchronously via node.send()\nreturn null;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "// Import required classes from the AWS SDK v3 package\nconst { SNSClient } = awsSdkClientSns;\n\n// Group configuration values in an object\nthis.config = {\n    topicArn: global.get(\"SECRETS.AWS_SNS_TOPIC_ARN\"), // e.g., \"arn:aws:sns:us-west-2:811950790052:flow-sns-test\"\n    accessKey: global.get(\"SECRETS.AWS_SNS_API_KEY\"),\n    accessSecret: global.get(\"SECRETS.AWS_SNS_API_SECRET\"),\n    region: global.get(\"SECRETS.AWS_SNS_TOPIC_REGION\"),\n    endpointUrl: env.get(\"BASE_URL\") + \"/sns-subscription\" // An opened HTTP endpoint of this flow for subscription confirmation\n};\n\n// Create an SNS client instance and store it as a property of the node (this.client)\nthis.client = new SNSClient({\n    region: this.config.region,\n    credentials: {\n        accessKeyId: this.config.accessKey,\n        secretAccessKey: this.config.accessSecret\n    }\n});\n\n",
        "finalize": "",
        "libs": [
            {
                "var": "awsSdkClientSns",
                "module": "@aws-sdk/client-sns"
            }
        ],
        "x": 340,
        "y": 340,
        "wires": [
            [
                "4a6c8bef8bb14eca"
            ]
        ],
        "icon": "font-awesome/fa-eye"
    },
    {
        "id": "c59c5e0a0c3cc1f0",
        "type": "inject",
        "z": "bdf7dc31543e1548",
        "g": "79ba64f594279419",
        "name": "",
        "props": [],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "x": 145,
        "y": 340,
        "wires": [
            [
                "453e8392da2d89a2"
            ]
        ],
        "l": false
    },
    {
        "id": "4a6c8bef8bb14eca",
        "type": "debug",
        "z": "bdf7dc31543e1548",
        "g": "79ba64f594279419",
        "name": "Send message",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "counter",
        "x": 565,
        "y": 340,
        "wires": [],
        "l": false
    }
]