@wesell/n8n-nodes-confirmx 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +77 -0
- package/credentials/ConfirmXApi.credentials.d.ts +18 -0
- package/credentials/ConfirmXApi.credentials.js +31 -0
- package/credentials/ConfirmXApi.credentials.js.map +1 -0
- package/credentials/ConfirmXApi.credentials.ts +40 -0
- package/index.d.ts +14 -0
- package/index.js +26 -0
- package/nodes/ConfirmX/ConfirmXAccount.node.d.ts +5 -0
- package/nodes/ConfirmX/ConfirmXAccount.node.js +81 -0
- package/nodes/ConfirmX/ConfirmXAccount.node.js.map +1 -0
- package/nodes/ConfirmX/ConfirmXAccount.node.ts +81 -0
- package/nodes/ConfirmX/ConfirmXConversation.node.d.ts +13 -0
- package/nodes/ConfirmX/ConfirmXConversation.node.js +266 -0
- package/nodes/ConfirmX/ConfirmXConversation.node.js.map +1 -0
- package/nodes/ConfirmX/ConfirmXConversation.node.ts +263 -0
- package/nodes/ConfirmX/ConfirmXMessage.node.d.ts +13 -0
- package/nodes/ConfirmX/ConfirmXMessage.node.js +364 -0
- package/nodes/ConfirmX/ConfirmXMessage.node.js.map +1 -0
- package/nodes/ConfirmX/ConfirmXMessage.node.ts +361 -0
- package/nodes/ConfirmX/ConfirmXShippingZone.node.d.ts +5 -0
- package/nodes/ConfirmX/ConfirmXShippingZone.node.js +100 -0
- package/nodes/ConfirmX/ConfirmXShippingZone.node.js.map +1 -0
- package/nodes/ConfirmX/ConfirmXShippingZone.node.ts +103 -0
- package/nodes/ConfirmX/ConfirmXTemplate.node.d.ts +13 -0
- package/nodes/ConfirmX/ConfirmXTemplate.node.js +310 -0
- package/nodes/ConfirmX/ConfirmXTemplate.node.js.map +1 -0
- package/nodes/ConfirmX/ConfirmXTemplate.node.ts +310 -0
- package/nodes/ConfirmX/ConfirmXTrigger.node.d.ts +29 -0
- package/nodes/ConfirmX/ConfirmXTrigger.node.js +190 -0
- package/nodes/ConfirmX/ConfirmXTrigger.node.js.map +1 -0
- package/nodes/ConfirmX/ConfirmXTrigger.node.ts +245 -0
- package/nodes/ConfirmX/ConfirmXWebhook.node.d.ts +5 -0
- package/nodes/ConfirmX/ConfirmXWebhook.node.js +169 -0
- package/nodes/ConfirmX/ConfirmXWebhook.node.js.map +1 -0
- package/nodes/ConfirmX/ConfirmXWebhook.node.ts +163 -0
- package/nodes/ConfirmX/confirmx.svg +4 -0
- package/package.json +69 -0
- package/transports/http.d.ts +43 -0
- package/transports/http.js +117 -0
- package/transports/http.js.map +1 -0
- package/transports/http.ts +170 -0
- package/transports/signature.d.ts +21 -0
- package/transports/signature.js +50 -0
- package/transports/signature.js.map +1 -0
- package/transports/signature.ts +55 -0
- package/types/api.d.ts +199 -0
- package/types/api.js +21 -0
- package/types/api.js.map +1 -0
- package/types/api.ts +238 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConfirmXTrigger = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const http_1 = require("../../transports/http");
|
|
6
|
+
const signature_1 = require("../../transports/signature");
|
|
7
|
+
const api_1 = require("../../types/api");
|
|
8
|
+
function sameEvents(a, b) {
|
|
9
|
+
if (!a)
|
|
10
|
+
return false;
|
|
11
|
+
if (a.length !== b.length)
|
|
12
|
+
return false;
|
|
13
|
+
return b.every((e) => a.includes(e));
|
|
14
|
+
}
|
|
15
|
+
class ConfirmXTrigger {
|
|
16
|
+
constructor() {
|
|
17
|
+
this.description = {
|
|
18
|
+
displayName: 'ConfirmX Trigger',
|
|
19
|
+
name: 'confirmXTrigger',
|
|
20
|
+
icon: 'file:confirmx.svg',
|
|
21
|
+
group: ['trigger'],
|
|
22
|
+
version: 1,
|
|
23
|
+
subtitle: '={{$parameter["events"].join(", ")}}',
|
|
24
|
+
description: 'Starts a flow when ConfirmX emits a webhook event (message received, conversation created, message sent, message status, template status). We register the subscription automatically.',
|
|
25
|
+
defaults: { name: 'ConfirmX Trigger' },
|
|
26
|
+
inputs: [],
|
|
27
|
+
outputs: ['main'],
|
|
28
|
+
credentials: [{ name: 'confirmXApi', required: true }],
|
|
29
|
+
webhooks: [
|
|
30
|
+
{
|
|
31
|
+
name: 'default',
|
|
32
|
+
httpMethod: 'POST',
|
|
33
|
+
responseMode: 'onReceived',
|
|
34
|
+
path: 'confirmx',
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
properties: [
|
|
38
|
+
{
|
|
39
|
+
displayName: 'Events',
|
|
40
|
+
name: 'events',
|
|
41
|
+
type: 'multiOptions',
|
|
42
|
+
default: ['message.received'],
|
|
43
|
+
required: true,
|
|
44
|
+
options: api_1.WEBHOOK_EVENT_TYPES.map((e) => ({ name: e, value: e })),
|
|
45
|
+
description: 'Which ConfirmX events to subscribe to',
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// ============================================
|
|
51
|
+
// trigger() — n8n calls this when the workflow is saved/activated.
|
|
52
|
+
//
|
|
53
|
+
// We DON'T have access to the per-flow webhook URL from ITriggerFunctions
|
|
54
|
+
// (only IWebhookFunctions / IHookFunctions expose getNodeWebhookUrl), so we
|
|
55
|
+
// perform the registration lazily on the first inbound webhook() call —
|
|
56
|
+
// see the webhook() method below.
|
|
57
|
+
//
|
|
58
|
+
// All we do here is ensure staticData is initialized and run cleanup hooks
|
|
59
|
+
// for any stale webhookIds left over from prior runs where the URL changed.
|
|
60
|
+
// ============================================
|
|
61
|
+
async trigger() {
|
|
62
|
+
// No-op stub — actual registration happens in webhook() so we have the URL.
|
|
63
|
+
return {
|
|
64
|
+
manualTriggerFunction: async () => undefined,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
// ============================================
|
|
68
|
+
// webhook() — n8n calls this for each incoming POST from ConfirmX.
|
|
69
|
+
//
|
|
70
|
+
// On the FIRST call, we register the subscription against ConfirmX
|
|
71
|
+
// (since trigger() doesn't have access to getNodeWebhookUrl). Subsequent
|
|
72
|
+
// calls are no-ops for registration and just verify + emit.
|
|
73
|
+
// ============================================
|
|
74
|
+
async webhook() {
|
|
75
|
+
const staticData = this.getWorkflowStaticData('node');
|
|
76
|
+
const events = this.getNodeParameter('events', []);
|
|
77
|
+
const webhookUrl = this.getNodeWebhookUrl('default');
|
|
78
|
+
if (!webhookUrl) {
|
|
79
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'ConfirmX Trigger could not resolve its webhook URL. Confirm WEBHOOK_URL is set correctly on your n8n server.');
|
|
80
|
+
}
|
|
81
|
+
// Lazy registration (idempotent on (url, events)).
|
|
82
|
+
if (!staticData.webhookId || staticData.webhookUrl !== webhookUrl || !sameEvents(staticData.events, events)) {
|
|
83
|
+
// URL or events changed → best-effort cleanup of stale subscription.
|
|
84
|
+
if (staticData.webhookId && staticData.webhookUrl !== webhookUrl) {
|
|
85
|
+
try {
|
|
86
|
+
await (0, http_1.confirmxApiRequest)(this, {
|
|
87
|
+
method: 'DELETE',
|
|
88
|
+
endpoint: `/webhooks/${staticData.webhookId}`,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// swallow
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const res = await (0, http_1.confirmxApiRequest)(this, {
|
|
96
|
+
method: 'POST',
|
|
97
|
+
endpoint: '/webhooks',
|
|
98
|
+
body: { url: webhookUrl, events, description: 'n8n integration' },
|
|
99
|
+
});
|
|
100
|
+
staticData.webhookId = res.webhook.id;
|
|
101
|
+
staticData.secret = res.secret;
|
|
102
|
+
staticData.webhookUrl = webhookUrl;
|
|
103
|
+
staticData.events = events;
|
|
104
|
+
// Warn if URL looks suspicious (proxy misconfig).
|
|
105
|
+
if (/^(https?:\/\/)?(localhost|127\.|10\.|192\.168\.|172\.(1[6-9]|2\d|3[01])\.)/i.test(webhookUrl)) {
|
|
106
|
+
this.logger.warn(`ConfirmX Trigger webhook URL ${webhookUrl} points to a private/local address. Confirm WEBHOOK_URL is set correctly on your n8n server.`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const secret = staticData.secret;
|
|
110
|
+
if (!secret) {
|
|
111
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'ConfirmX Trigger has no signing secret in workflow staticData. Send a test event to re-register.');
|
|
112
|
+
}
|
|
113
|
+
const req = this.getRequestObject();
|
|
114
|
+
const header = (name) => {
|
|
115
|
+
const v = req.headers?.[name.toLowerCase()];
|
|
116
|
+
return typeof v === 'string' ? v : Array.isArray(v) ? v[0] : undefined;
|
|
117
|
+
};
|
|
118
|
+
const signature = header('x-confirmx-signature');
|
|
119
|
+
const timestamp = header('x-confirmx-timestamp');
|
|
120
|
+
const eventType = header('x-confirmx-event');
|
|
121
|
+
const deliveryId = header('x-confirmx-delivery');
|
|
122
|
+
const eventId = header('x-confirmx-event-id');
|
|
123
|
+
if (!signature || !timestamp || !eventType) {
|
|
124
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Missing required ConfirmX signature headers (X-ConfirmX-Signature / -Timestamp / -Event).');
|
|
125
|
+
}
|
|
126
|
+
// Replay window: ConfirmX uses 300s.
|
|
127
|
+
const skew = (0, signature_1.timestampSkewSeconds)(timestamp);
|
|
128
|
+
if (!Number.isFinite(skew) || skew > signature_1.REPLAY_WINDOW_SECONDS) {
|
|
129
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `ConfirmX timestamp skew ${Math.round(skew)}s exceeds ${signature_1.REPLAY_WINDOW_SECONDS}s replay window.`);
|
|
130
|
+
}
|
|
131
|
+
const rawBody = typeof req.rawBody === 'string'
|
|
132
|
+
? req.rawBody
|
|
133
|
+
: req.rawBody instanceof Buffer
|
|
134
|
+
? req.rawBody.toString('utf8')
|
|
135
|
+
: typeof req.body === 'string'
|
|
136
|
+
? req.body
|
|
137
|
+
: JSON.stringify(req.body ?? {});
|
|
138
|
+
if (!(0, signature_1.verifyPayload)({ secret, body: rawBody, timestamp, signatureHeader: signature })) {
|
|
139
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Invalid ConfirmX webhook signature. (Confirm WEBHOOK_URL points at this n8n instance and the signing secret matches.)');
|
|
140
|
+
}
|
|
141
|
+
let envelope;
|
|
142
|
+
try {
|
|
143
|
+
envelope = JSON.parse(rawBody);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'ConfirmX webhook body is not valid JSON.');
|
|
147
|
+
}
|
|
148
|
+
// Emit the inner `data` as the n8n item, plus envelope metadata
|
|
149
|
+
// under __confirmx for downstream nodes that need it.
|
|
150
|
+
const itemJson = {
|
|
151
|
+
...(envelope.data ?? {}),
|
|
152
|
+
__confirmx: {
|
|
153
|
+
eventId: envelope.id ?? eventId ?? null,
|
|
154
|
+
type: envelope.type ?? eventType,
|
|
155
|
+
deliveryId: deliveryId ?? null,
|
|
156
|
+
organizationId: envelope.organizationId ?? null,
|
|
157
|
+
receivedAt: new Date().toISOString(),
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
return {
|
|
161
|
+
workflowData: [[{ json: itemJson }]],
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
// ============================================
|
|
165
|
+
// delete() — best-effort cleanup when the workflow is removed
|
|
166
|
+
// or the trigger node is deleted.
|
|
167
|
+
// ============================================
|
|
168
|
+
async delete() {
|
|
169
|
+
const staticData = this.getWorkflowStaticData('node');
|
|
170
|
+
if (!staticData.webhookId)
|
|
171
|
+
return;
|
|
172
|
+
try {
|
|
173
|
+
await (0, http_1.confirmxApiRequest)(this, {
|
|
174
|
+
method: 'DELETE',
|
|
175
|
+
endpoint: `/webhooks/${staticData.webhookId}`,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
catch (err) {
|
|
179
|
+
this.logger.warn(`ConfirmX Trigger cleanup failed for webhook ${staticData.webhookId}: ${err.message}`);
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
delete staticData.webhookId;
|
|
183
|
+
delete staticData.secret;
|
|
184
|
+
delete staticData.webhookUrl;
|
|
185
|
+
delete staticData.events;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
exports.ConfirmXTrigger = ConfirmXTrigger;
|
|
190
|
+
//# sourceMappingURL=ConfirmXTrigger.node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfirmXTrigger.node.js","sourceRoot":"","sources":["ConfirmXTrigger.node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfirmX Trigger — starts a flow when ConfirmX emits a webhook event.
|
|
3
|
+
*
|
|
4
|
+
* Self-registration lifecycle:
|
|
5
|
+
* 1. `trigger()` — n8n calls this when the trigger is added/edited or
|
|
6
|
+
* the workflow is saved/activated. We POST /api/v1/webhooks with
|
|
7
|
+
* the n8n-generated URL + the selected events, then persist the
|
|
8
|
+
* returned `secret` in workflow staticData.
|
|
9
|
+
* 2. `webhook()` — n8n calls this for each incoming POST from ConfirmX.
|
|
10
|
+
* We verify the HMAC signature, reject stale timestamps (300s window),
|
|
11
|
+
* and emit the envelope's `data` field as the n8n item.
|
|
12
|
+
* 3. `delete()` / `deactivate()` — best-effort DELETE /api/v1/webhooks/:id.
|
|
13
|
+
*
|
|
14
|
+
* Critical invariant: the `secret` MUST persist client-side because
|
|
15
|
+
* `GET /api/v1/webhooks/:id` does NOT return it. If staticData is wiped
|
|
16
|
+
* (e.g. n8n SQLite volume loss), the trigger throws a clear error
|
|
17
|
+
* and the user must re-add the node to re-register.
|
|
18
|
+
*/
|
|
19
|
+
import type {
|
|
20
|
+
ITriggerFunctions,
|
|
21
|
+
ITriggerResponse,
|
|
22
|
+
IWebhookFunctions,
|
|
23
|
+
INodeType,
|
|
24
|
+
INodeTypeDescription,
|
|
25
|
+
} from 'n8n-workflow'
|
|
26
|
+
import { NodeOperationError } from 'n8n-workflow'
|
|
27
|
+
import { confirmxApiRequest } from '../../transports/http'
|
|
28
|
+
import { verifyPayload, timestampSkewSeconds, REPLAY_WINDOW_SECONDS } from '../../transports/signature'
|
|
29
|
+
import { WEBHOOK_EVENT_TYPES } from '../../types/api'
|
|
30
|
+
|
|
31
|
+
interface TriggerStaticData {
|
|
32
|
+
webhookId?: string
|
|
33
|
+
secret?: string
|
|
34
|
+
webhookUrl?: string
|
|
35
|
+
events?: string[]
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function sameEvents(a: string[] | undefined, b: string[]): boolean {
|
|
39
|
+
if (!a) return false
|
|
40
|
+
if (a.length !== b.length) return false
|
|
41
|
+
return b.every((e) => a.includes(e))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class ConfirmXTrigger implements INodeType {
|
|
45
|
+
description: INodeTypeDescription = {
|
|
46
|
+
displayName: 'ConfirmX Trigger',
|
|
47
|
+
name: 'confirmXTrigger',
|
|
48
|
+
icon: 'file:confirmx.svg',
|
|
49
|
+
group: ['trigger'],
|
|
50
|
+
version: 1,
|
|
51
|
+
subtitle: '={{$parameter["events"].join(", ")}}',
|
|
52
|
+
description:
|
|
53
|
+
'Starts a flow when ConfirmX emits a webhook event (message received, conversation created, message sent, message status, template status). We register the subscription automatically.',
|
|
54
|
+
defaults: { name: 'ConfirmX Trigger' },
|
|
55
|
+
inputs: [],
|
|
56
|
+
outputs: ['main'],
|
|
57
|
+
credentials: [{ name: 'confirmXApi', required: true }],
|
|
58
|
+
webhooks: [
|
|
59
|
+
{
|
|
60
|
+
name: 'default',
|
|
61
|
+
httpMethod: 'POST',
|
|
62
|
+
responseMode: 'onReceived',
|
|
63
|
+
path: 'confirmx',
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
properties: [
|
|
67
|
+
{
|
|
68
|
+
displayName: 'Events',
|
|
69
|
+
name: 'events',
|
|
70
|
+
type: 'multiOptions',
|
|
71
|
+
default: ['message.received'],
|
|
72
|
+
required: true,
|
|
73
|
+
options: WEBHOOK_EVENT_TYPES.map((e) => ({ name: e, value: e })),
|
|
74
|
+
description: 'Which ConfirmX events to subscribe to',
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ============================================
|
|
80
|
+
// trigger() — n8n calls this when the workflow is saved/activated.
|
|
81
|
+
//
|
|
82
|
+
// We DON'T have access to the per-flow webhook URL from ITriggerFunctions
|
|
83
|
+
// (only IWebhookFunctions / IHookFunctions expose getNodeWebhookUrl), so we
|
|
84
|
+
// perform the registration lazily on the first inbound webhook() call —
|
|
85
|
+
// see the webhook() method below.
|
|
86
|
+
//
|
|
87
|
+
// All we do here is ensure staticData is initialized and run cleanup hooks
|
|
88
|
+
// for any stale webhookIds left over from prior runs where the URL changed.
|
|
89
|
+
// ============================================
|
|
90
|
+
async trigger(this: ITriggerFunctions): Promise<ITriggerResponse> {
|
|
91
|
+
// No-op stub — actual registration happens in webhook() so we have the URL.
|
|
92
|
+
return {
|
|
93
|
+
manualTriggerFunction: async () => undefined,
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ============================================
|
|
98
|
+
// webhook() — n8n calls this for each incoming POST from ConfirmX.
|
|
99
|
+
//
|
|
100
|
+
// On the FIRST call, we register the subscription against ConfirmX
|
|
101
|
+
// (since trigger() doesn't have access to getNodeWebhookUrl). Subsequent
|
|
102
|
+
// calls are no-ops for registration and just verify + emit.
|
|
103
|
+
// ============================================
|
|
104
|
+
async webhook(this: IWebhookFunctions) {
|
|
105
|
+
const staticData = this.getWorkflowStaticData('node') as unknown as TriggerStaticData
|
|
106
|
+
const events = this.getNodeParameter('events', []) as string[]
|
|
107
|
+
const webhookUrl = this.getNodeWebhookUrl('default')
|
|
108
|
+
|
|
109
|
+
if (!webhookUrl) {
|
|
110
|
+
throw new NodeOperationError(
|
|
111
|
+
this.getNode(),
|
|
112
|
+
'ConfirmX Trigger could not resolve its webhook URL. Confirm WEBHOOK_URL is set correctly on your n8n server.',
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Lazy registration (idempotent on (url, events)).
|
|
117
|
+
if (!staticData.webhookId || staticData.webhookUrl !== webhookUrl || !sameEvents(staticData.events, events)) {
|
|
118
|
+
// URL or events changed → best-effort cleanup of stale subscription.
|
|
119
|
+
if (staticData.webhookId && staticData.webhookUrl !== webhookUrl) {
|
|
120
|
+
try {
|
|
121
|
+
await confirmxApiRequest(this, {
|
|
122
|
+
method: 'DELETE',
|
|
123
|
+
endpoint: `/webhooks/${staticData.webhookId}`,
|
|
124
|
+
})
|
|
125
|
+
} catch {
|
|
126
|
+
// swallow
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const res = await confirmxApiRequest<{ webhook: { id: string }; secret: string }>(this, {
|
|
130
|
+
method: 'POST',
|
|
131
|
+
endpoint: '/webhooks',
|
|
132
|
+
body: { url: webhookUrl, events, description: 'n8n integration' },
|
|
133
|
+
})
|
|
134
|
+
staticData.webhookId = res.webhook.id
|
|
135
|
+
staticData.secret = res.secret
|
|
136
|
+
staticData.webhookUrl = webhookUrl
|
|
137
|
+
staticData.events = events
|
|
138
|
+
|
|
139
|
+
// Warn if URL looks suspicious (proxy misconfig).
|
|
140
|
+
if (/^(https?:\/\/)?(localhost|127\.|10\.|192\.168\.|172\.(1[6-9]|2\d|3[01])\.)/i.test(webhookUrl)) {
|
|
141
|
+
this.logger.warn(
|
|
142
|
+
`ConfirmX Trigger webhook URL ${webhookUrl} points to a private/local address. Confirm WEBHOOK_URL is set correctly on your n8n server.`,
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const secret = staticData.secret
|
|
148
|
+
if (!secret) {
|
|
149
|
+
throw new NodeOperationError(
|
|
150
|
+
this.getNode(),
|
|
151
|
+
'ConfirmX Trigger has no signing secret in workflow staticData. Send a test event to re-register.',
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const req = this.getRequestObject() as any
|
|
156
|
+
const header = (name: string): string | undefined => {
|
|
157
|
+
const v = req.headers?.[name.toLowerCase()]
|
|
158
|
+
return typeof v === 'string' ? v : Array.isArray(v) ? v[0] : undefined
|
|
159
|
+
}
|
|
160
|
+
const signature = header('x-confirmx-signature')
|
|
161
|
+
const timestamp = header('x-confirmx-timestamp')
|
|
162
|
+
const eventType = header('x-confirmx-event')
|
|
163
|
+
const deliveryId = header('x-confirmx-delivery')
|
|
164
|
+
const eventId = header('x-confirmx-event-id')
|
|
165
|
+
|
|
166
|
+
if (!signature || !timestamp || !eventType) {
|
|
167
|
+
throw new NodeOperationError(
|
|
168
|
+
this.getNode(),
|
|
169
|
+
'Missing required ConfirmX signature headers (X-ConfirmX-Signature / -Timestamp / -Event).',
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Replay window: ConfirmX uses 300s.
|
|
174
|
+
const skew = timestampSkewSeconds(timestamp)
|
|
175
|
+
if (!Number.isFinite(skew) || skew > REPLAY_WINDOW_SECONDS) {
|
|
176
|
+
throw new NodeOperationError(
|
|
177
|
+
this.getNode(),
|
|
178
|
+
`ConfirmX timestamp skew ${Math.round(skew)}s exceeds ${REPLAY_WINDOW_SECONDS}s replay window.`,
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const rawBody =
|
|
183
|
+
typeof req.rawBody === 'string'
|
|
184
|
+
? req.rawBody
|
|
185
|
+
: req.rawBody instanceof Buffer
|
|
186
|
+
? req.rawBody.toString('utf8')
|
|
187
|
+
: typeof req.body === 'string'
|
|
188
|
+
? req.body
|
|
189
|
+
: JSON.stringify(req.body ?? {})
|
|
190
|
+
|
|
191
|
+
if (!verifyPayload({ secret, body: rawBody, timestamp, signatureHeader: signature })) {
|
|
192
|
+
throw new NodeOperationError(
|
|
193
|
+
this.getNode(),
|
|
194
|
+
'Invalid ConfirmX webhook signature. (Confirm WEBHOOK_URL points at this n8n instance and the signing secret matches.)',
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
let envelope: { id?: string; type?: string; createdAt?: string; organizationId?: string; data?: any }
|
|
199
|
+
try {
|
|
200
|
+
envelope = JSON.parse(rawBody)
|
|
201
|
+
} catch {
|
|
202
|
+
throw new NodeOperationError(this.getNode(), 'ConfirmX webhook body is not valid JSON.')
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Emit the inner `data` as the n8n item, plus envelope metadata
|
|
206
|
+
// under __confirmx for downstream nodes that need it.
|
|
207
|
+
const itemJson = {
|
|
208
|
+
...(envelope.data ?? {}),
|
|
209
|
+
__confirmx: {
|
|
210
|
+
eventId: envelope.id ?? eventId ?? null,
|
|
211
|
+
type: envelope.type ?? eventType,
|
|
212
|
+
deliveryId: deliveryId ?? null,
|
|
213
|
+
organizationId: envelope.organizationId ?? null,
|
|
214
|
+
receivedAt: new Date().toISOString(),
|
|
215
|
+
},
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
workflowData: [[{ json: itemJson }]],
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// ============================================
|
|
223
|
+
// delete() — best-effort cleanup when the workflow is removed
|
|
224
|
+
// or the trigger node is deleted.
|
|
225
|
+
// ============================================
|
|
226
|
+
async delete(this: ITriggerFunctions): Promise<void> {
|
|
227
|
+
const staticData = this.getWorkflowStaticData('node') as unknown as TriggerStaticData
|
|
228
|
+
if (!staticData.webhookId) return
|
|
229
|
+
try {
|
|
230
|
+
await confirmxApiRequest(this, {
|
|
231
|
+
method: 'DELETE',
|
|
232
|
+
endpoint: `/webhooks/${staticData.webhookId}`,
|
|
233
|
+
})
|
|
234
|
+
} catch (err) {
|
|
235
|
+
this.logger.warn(
|
|
236
|
+
`ConfirmX Trigger cleanup failed for webhook ${staticData.webhookId}: ${(err as Error).message}`,
|
|
237
|
+
)
|
|
238
|
+
} finally {
|
|
239
|
+
delete staticData.webhookId
|
|
240
|
+
delete staticData.secret
|
|
241
|
+
delete staticData.webhookUrl
|
|
242
|
+
delete staticData.events
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConfirmXWebhook = void 0;
|
|
4
|
+
const http_1 = require("../../transports/http");
|
|
5
|
+
const api_1 = require("../../types/api");
|
|
6
|
+
class ConfirmXWebhook {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.description = {
|
|
9
|
+
displayName: 'ConfirmX Webhook',
|
|
10
|
+
name: 'confirmXWebhook',
|
|
11
|
+
icon: 'file:confirmx.svg',
|
|
12
|
+
group: ['transform'],
|
|
13
|
+
version: 1,
|
|
14
|
+
subtitle: '={{$parameter["operation"]}}',
|
|
15
|
+
description: 'Manage ConfirmX outbound webhook subscriptions (list, create, update, delete). Use the ConfirmX Trigger node to receive events automatically.',
|
|
16
|
+
defaults: { name: 'ConfirmX Webhook' },
|
|
17
|
+
inputs: ['main'],
|
|
18
|
+
outputs: ['main'],
|
|
19
|
+
credentials: [{ name: 'confirmXApi', required: true }],
|
|
20
|
+
// Admin-only — not exposed as an AI tool.
|
|
21
|
+
properties: [
|
|
22
|
+
{
|
|
23
|
+
displayName: 'Operation',
|
|
24
|
+
name: 'operation',
|
|
25
|
+
type: 'options',
|
|
26
|
+
noDataExpression: true,
|
|
27
|
+
options: [
|
|
28
|
+
{ name: 'List', value: 'list', action: 'List webhook subscriptions' },
|
|
29
|
+
{ name: 'Create', value: 'create', action: 'Create a webhook subscription' },
|
|
30
|
+
{ name: 'Update', value: 'update', action: 'Update a webhook subscription' },
|
|
31
|
+
{ name: 'Delete', value: 'delete', action: 'Delete a webhook subscription' },
|
|
32
|
+
],
|
|
33
|
+
default: 'list',
|
|
34
|
+
},
|
|
35
|
+
// --- Common ---
|
|
36
|
+
{
|
|
37
|
+
displayName: 'Webhook ID',
|
|
38
|
+
name: 'webhookId',
|
|
39
|
+
type: 'string',
|
|
40
|
+
default: '',
|
|
41
|
+
required: true,
|
|
42
|
+
displayOptions: { show: { operation: ['update', 'delete'] } },
|
|
43
|
+
description: 'The webhook subscription ID',
|
|
44
|
+
},
|
|
45
|
+
// --- Create / Update ---
|
|
46
|
+
{
|
|
47
|
+
displayName: 'URL',
|
|
48
|
+
name: 'url',
|
|
49
|
+
type: 'string',
|
|
50
|
+
default: '',
|
|
51
|
+
required: true,
|
|
52
|
+
displayOptions: { show: { operation: ['create', 'update'] } },
|
|
53
|
+
placeholder: 'https://example.com/webhook',
|
|
54
|
+
description: 'Public URL that ConfirmX will POST events to',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
displayName: 'Events',
|
|
58
|
+
name: 'events',
|
|
59
|
+
type: 'multiOptions',
|
|
60
|
+
default: ['message.received'],
|
|
61
|
+
required: true,
|
|
62
|
+
displayOptions: { show: { operation: ['create', 'update'] } },
|
|
63
|
+
options: api_1.WEBHOOK_EVENT_TYPES.map((e) => ({ name: e, value: e })),
|
|
64
|
+
description: 'Event types this subscription should receive',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
displayName: 'Description',
|
|
68
|
+
name: 'description',
|
|
69
|
+
type: 'string',
|
|
70
|
+
default: '',
|
|
71
|
+
displayOptions: { show: { operation: ['create', 'update'] } },
|
|
72
|
+
description: 'Optional human-readable description (max 256 chars)',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
displayName: 'Active',
|
|
76
|
+
name: 'isActive',
|
|
77
|
+
type: 'boolean',
|
|
78
|
+
default: true,
|
|
79
|
+
displayOptions: { show: { operation: ['update'] } },
|
|
80
|
+
description: 'Whether the subscription is active',
|
|
81
|
+
},
|
|
82
|
+
// --- List ---
|
|
83
|
+
{
|
|
84
|
+
displayName: 'Return All',
|
|
85
|
+
name: 'returnAll',
|
|
86
|
+
type: 'boolean',
|
|
87
|
+
default: false,
|
|
88
|
+
displayOptions: { show: { operation: ['list'] } },
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
displayName: 'Limit',
|
|
92
|
+
name: 'limit',
|
|
93
|
+
type: 'number',
|
|
94
|
+
default: 50,
|
|
95
|
+
typeOptions: { minValue: 1, maxValue: 200 },
|
|
96
|
+
displayOptions: { show: { operation: ['list'], returnAll: [false] } },
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
async execute() {
|
|
102
|
+
const items = this.getInputData();
|
|
103
|
+
const returnData = [];
|
|
104
|
+
for (let i = 0; i < items.length; i++) {
|
|
105
|
+
const operation = this.getNodeParameter('operation', i);
|
|
106
|
+
if (operation === 'list') {
|
|
107
|
+
const returnAll = this.getNodeParameter('returnAll', i);
|
|
108
|
+
const limit = this.getNodeParameter('limit', i) || 50;
|
|
109
|
+
const res = await (0, http_1.confirmxApiRequest)(this, {
|
|
110
|
+
method: 'GET',
|
|
111
|
+
endpoint: '/webhooks',
|
|
112
|
+
});
|
|
113
|
+
const sliced = returnAll ? res.webhooks || [] : (res.webhooks || []).slice(0, limit);
|
|
114
|
+
returnData.push(...sliced.map((w) => ({ json: w })));
|
|
115
|
+
}
|
|
116
|
+
else if (operation === 'create') {
|
|
117
|
+
const body = {
|
|
118
|
+
url: this.getNodeParameter('url', i),
|
|
119
|
+
events: this.getNodeParameter('events', i),
|
|
120
|
+
description: this.getNodeParameter('description', i) || undefined,
|
|
121
|
+
};
|
|
122
|
+
const res = await (0, http_1.confirmxApiRequest)(this, {
|
|
123
|
+
method: 'POST',
|
|
124
|
+
endpoint: '/webhooks',
|
|
125
|
+
body,
|
|
126
|
+
});
|
|
127
|
+
// Surface the secret prominently — it is returned ONLY at create time.
|
|
128
|
+
returnData.push({
|
|
129
|
+
json: {
|
|
130
|
+
...res,
|
|
131
|
+
_warning: res.secretNote || 'Save the secret now — it cannot be retrieved later.',
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
else if (operation === 'update') {
|
|
136
|
+
const webhookId = this.getNodeParameter('webhookId', i);
|
|
137
|
+
const body = {};
|
|
138
|
+
const url = this.getNodeParameter('url', i);
|
|
139
|
+
const events = this.getNodeParameter('events', i);
|
|
140
|
+
const description = this.getNodeParameter('description', i);
|
|
141
|
+
const isActive = this.getNodeParameter('isActive', i, true);
|
|
142
|
+
if (url)
|
|
143
|
+
body.url = url;
|
|
144
|
+
if (events && events.length)
|
|
145
|
+
body.events = events;
|
|
146
|
+
if (description !== undefined)
|
|
147
|
+
body.description = description;
|
|
148
|
+
body.isActive = isActive;
|
|
149
|
+
const res = await (0, http_1.confirmxApiRequest)(this, {
|
|
150
|
+
method: 'PATCH',
|
|
151
|
+
endpoint: `/webhooks/${webhookId}`,
|
|
152
|
+
body,
|
|
153
|
+
});
|
|
154
|
+
returnData.push({ json: res.webhook });
|
|
155
|
+
}
|
|
156
|
+
else if (operation === 'delete') {
|
|
157
|
+
const webhookId = this.getNodeParameter('webhookId', i);
|
|
158
|
+
const res = await (0, http_1.confirmxApiRequest)(this, {
|
|
159
|
+
method: 'DELETE',
|
|
160
|
+
endpoint: `/webhooks/${webhookId}`,
|
|
161
|
+
});
|
|
162
|
+
returnData.push({ json: { success: true, webhookId, ...res } });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return [returnData];
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
exports.ConfirmXWebhook = ConfirmXWebhook;
|
|
169
|
+
//# sourceMappingURL=ConfirmXWebhook.node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfirmXWebhook.node.js","sourceRoot":"","sources":["ConfirmXWebhook.node.ts"],"names":[],"mappings":"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"}
|