From 99c35fa829c19d82c968da76dcae1d67a51d05d9 Mon Sep 17 00:00:00 2001 From: Hyungi Ahn Date: Thu, 19 Mar 2026 15:17:08 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20Chat=20Confirm=EC=9D=84=20form-encoded?= =?UTF-8?q?=20payload=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Synology Chat incoming webhook은 JSON body가 아닌 form-encoded payload={"text":"..."} 형식 필요. Co-Authored-By: Claude Opus 4.6 (1M context) --- n8n/workflows/retrospect-capture-pipeline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/n8n/workflows/retrospect-capture-pipeline.json b/n8n/workflows/retrospect-capture-pipeline.json index 840f0f1..122a181 100644 --- a/n8n/workflows/retrospect-capture-pipeline.json +++ b/n8n/workflows/retrospect-capture-pipeline.json @@ -100,7 +100,7 @@ }, { "parameters": { - "jsCode": "function httpPost(url, body, { timeout = 10000, headers = {} } = {}) {\n return new Promise((resolve, reject) => {\n const data = JSON.stringify(body);\n const u = require('url').parse(url);\n const mod = require(u.protocol === 'https:' ? 'https' : 'http');\n const options = {\n hostname: u.hostname, port: u.port, path: u.path,\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data), ...headers },\n rejectUnauthorized: false\n };\n const req = mod.request(options, (res) => {\n let body = '';\n res.on('data', c => body += c);\n res.on('end', () => resolve({ statusCode: res.statusCode, body }));\n });\n req.on('error', reject);\n req.setTimeout(timeout, () => { req.destroy(); reject(new Error('timeout')); });\n req.write(data);\n req.end();\n });\n}\n\nconst item = $input.first().json;\nconst webhookUrl = $env.RETROSPECT_CHAT_WEBHOOK_URL || '';\n\nif (webhookUrl) {\n const tagsStr = (item.tags || []).map(t => '#' + t).join(' ');\n const msg = `\\u2713 [${item.domain}] ${tagsStr}`;\n try {\n await httpPost(webhookUrl, { text: msg }, { timeout: 10000 });\n } catch(e) {\n console.log('Chat ack failed: ' + e.message);\n }\n}\n\nreturn [{ json: { ...item, ack_sent: true } }];" + "jsCode": "function httpPostForm(url, formBody, { timeout = 10000 } = {}) {\n return new Promise((resolve, reject) => {\n const u = require('url').parse(url);\n const mod = require(u.protocol === 'https:' ? 'https' : 'http');\n const options = {\n hostname: u.hostname, port: u.port, path: u.path,\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(formBody) },\n rejectUnauthorized: false\n };\n const req = mod.request(options, (res) => {\n let body = '';\n res.on('data', c => body += c);\n res.on('end', () => resolve({ statusCode: res.statusCode, body }));\n });\n req.on('error', reject);\n req.setTimeout(timeout, () => { req.destroy(); reject(new Error('timeout')); });\n req.write(formBody);\n req.end();\n });\n}\n\nconst item = $input.first().json;\nconst webhookUrl = $env.RETROSPECT_CHAT_WEBHOOK_URL || '';\n\nif (webhookUrl) {\n const tagsStr = (item.tags || []).map(t => '#' + t).join(' ');\n const msg = `\\u2713 [${item.domain}] ${tagsStr}`;\n try {\n const payload = JSON.stringify({ text: msg });\n const formBody = 'payload=' + encodeURIComponent(payload);\n await httpPostForm(webhookUrl, formBody, { timeout: 10000 });\n } catch(e) {\n console.log('Chat ack failed: ' + e.message);\n }\n}\n\nreturn [{ json: { ...item, ack_sent: true } }];" }, "id": "r1000001-0000-0000-0000-000000000006", "name": "Chat Confirm",