@shoutkol/n8n-nodes-pumble 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/README.md +72 -0
- package/dist/credentials/PumbleApi.credentials.d.ts +9 -0
- package/dist/credentials/PumbleApi.credentials.js +36 -0
- package/dist/nodes/Pumble/Pumble.node.d.ts +5 -0
- package/dist/nodes/Pumble/Pumble.node.js +337 -0
- package/dist/nodes/Pumble/descriptions.d.ts +655 -0
- package/dist/nodes/Pumble/descriptions.js +618 -0
- package/dist/nodes/Pumble/pumble.svg +4 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# n8n-nodes-pumble
|
|
2
|
+
|
|
3
|
+
A community node for [n8n](https://n8n.io/) that integrates with the [Pumble API](https://pumble-api-keys.addons.marketplace.cake.com/api-docs/).
|
|
4
|
+
|
|
5
|
+
## Resources & Operations
|
|
6
|
+
|
|
7
|
+
| Resource | Operations |
|
|
8
|
+
|---|---|
|
|
9
|
+
| **Channel** | List, Get, Create, Add Users, Remove User |
|
|
10
|
+
| **Message** | Send, Reply, Fetch, List, Edit, Delete, Search, DM User, DM Group, Fetch Thread Replies |
|
|
11
|
+
| **Reaction** | Add, Remove |
|
|
12
|
+
| **Scheduled Message** | Create, List, Fetch, Edit, Delete |
|
|
13
|
+
| **User** | Get My Info, List Users, List User Groups, Update Custom Status |
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
### In n8n
|
|
18
|
+
|
|
19
|
+
1. Go to **Settings > Community Nodes**
|
|
20
|
+
2. Click **Install**
|
|
21
|
+
3. Enter `n8n-nodes-pumble`
|
|
22
|
+
|
|
23
|
+
### Manual
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
cd ~/.n8n/custom
|
|
27
|
+
npm install n8n-nodes-pumble
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Authentication
|
|
31
|
+
|
|
32
|
+
This node uses **API Key** authentication.
|
|
33
|
+
|
|
34
|
+
1. Install the **API addon** in your Pumble workspace (+ Add Apps → API)
|
|
35
|
+
2. Generate a key: type `/api-keys generate` in any Pumble channel
|
|
36
|
+
3. Copy the ephemeral key that appears
|
|
37
|
+
4. In n8n, create a new **Pumble API** credential and paste your key
|
|
38
|
+
|
|
39
|
+
## Project Structure
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
n8n-nodes-pumble/
|
|
43
|
+
├── credentials/
|
|
44
|
+
│ └── PumbleApi.credentials.ts # API key credential definition
|
|
45
|
+
├── nodes/
|
|
46
|
+
│ └── Pumble/
|
|
47
|
+
│ ├── Pumble.node.ts # Main node execute logic
|
|
48
|
+
│ ├── descriptions.ts # All resource/operation/field definitions
|
|
49
|
+
│ └── pumble.svg # Node icon
|
|
50
|
+
├── package.json
|
|
51
|
+
└── tsconfig.json
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Development
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Install dependencies
|
|
58
|
+
npm install
|
|
59
|
+
|
|
60
|
+
# Build (TypeScript → dist/)
|
|
61
|
+
npm run build
|
|
62
|
+
|
|
63
|
+
# Watch mode
|
|
64
|
+
npm run dev
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Notes
|
|
68
|
+
|
|
69
|
+
- The Pumble API base URL is `https://pumble-api-keys.addons.marketplace.cake.com`
|
|
70
|
+
- Authentication uses the `ApiKey` request header
|
|
71
|
+
- For channel operations on private channels, the Addon Bot must be a member
|
|
72
|
+
- Bots cannot post to private channels via `sendMessage` unless they are a member
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare class PumbleApi implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
documentationUrl: string;
|
|
6
|
+
properties: INodeProperties[];
|
|
7
|
+
authenticate: IAuthenticateGeneric;
|
|
8
|
+
test: ICredentialTestRequest;
|
|
9
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PumbleApi = void 0;
|
|
4
|
+
class PumbleApi {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = 'pumbleApi';
|
|
7
|
+
this.displayName = 'Pumble API';
|
|
8
|
+
this.documentationUrl = 'https://pumble-api-keys.addons.marketplace.cake.com/api-docs/';
|
|
9
|
+
this.properties = [
|
|
10
|
+
{
|
|
11
|
+
displayName: 'API Key',
|
|
12
|
+
name: 'apiKey',
|
|
13
|
+
type: 'string',
|
|
14
|
+
typeOptions: { password: true },
|
|
15
|
+
default: '',
|
|
16
|
+
required: true,
|
|
17
|
+
description: 'Your Pumble API key. Generate one via the /api-keys generate command in Pumble.',
|
|
18
|
+
},
|
|
19
|
+
];
|
|
20
|
+
this.authenticate = {
|
|
21
|
+
type: 'generic',
|
|
22
|
+
properties: {
|
|
23
|
+
headers: {
|
|
24
|
+
ApiKey: '={{$credentials.apiKey}}',
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
this.test = {
|
|
29
|
+
request: {
|
|
30
|
+
baseURL: 'https://pumble-api-keys.addons.marketplace.cake.com',
|
|
31
|
+
url: '/myInfo',
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.PumbleApi = PumbleApi;
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Pumble = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const descriptions_1 = require("./descriptions");
|
|
6
|
+
const BASE_URL = 'https://pumble-api-keys.addons.marketplace.cake.com';
|
|
7
|
+
class Pumble {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.description = {
|
|
10
|
+
displayName: 'Pumble',
|
|
11
|
+
name: 'pumble',
|
|
12
|
+
icon: 'file:pumble.svg',
|
|
13
|
+
group: ['transform'],
|
|
14
|
+
version: 1,
|
|
15
|
+
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
|
16
|
+
description: 'Interact with the Pumble API',
|
|
17
|
+
defaults: {
|
|
18
|
+
name: 'Pumble',
|
|
19
|
+
},
|
|
20
|
+
inputs: ['main'],
|
|
21
|
+
outputs: ['main'],
|
|
22
|
+
credentials: [
|
|
23
|
+
{
|
|
24
|
+
name: 'pumbleApi',
|
|
25
|
+
required: true,
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
properties: [
|
|
29
|
+
// ── Resource selector ──
|
|
30
|
+
{
|
|
31
|
+
displayName: 'Resource',
|
|
32
|
+
name: 'resource',
|
|
33
|
+
type: 'options',
|
|
34
|
+
noDataExpression: true,
|
|
35
|
+
options: descriptions_1.resourceOptions,
|
|
36
|
+
default: 'message',
|
|
37
|
+
},
|
|
38
|
+
// ── Operations & fields per resource ──
|
|
39
|
+
...descriptions_1.channelOperations,
|
|
40
|
+
...descriptions_1.channelFields,
|
|
41
|
+
...descriptions_1.messageOperations,
|
|
42
|
+
...descriptions_1.messageFields,
|
|
43
|
+
...descriptions_1.reactionOperations,
|
|
44
|
+
...descriptions_1.reactionFields,
|
|
45
|
+
...descriptions_1.scheduledMessageOperations,
|
|
46
|
+
...descriptions_1.scheduledMessageFields,
|
|
47
|
+
...descriptions_1.userOperations,
|
|
48
|
+
...descriptions_1.userFields,
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
// ─── Execute ───────────────────────────────────────────────────────────────
|
|
53
|
+
async execute() {
|
|
54
|
+
var _a;
|
|
55
|
+
const items = this.getInputData();
|
|
56
|
+
const returnData = [];
|
|
57
|
+
for (let i = 0; i < items.length; i++) {
|
|
58
|
+
const resource = this.getNodeParameter('resource', i);
|
|
59
|
+
const operation = this.getNodeParameter('operation', i);
|
|
60
|
+
let responseData;
|
|
61
|
+
try {
|
|
62
|
+
// ═══════════════════════════════════════════════════════════════
|
|
63
|
+
// CHANNEL
|
|
64
|
+
// ═══════════════════════════════════════════════════════════════
|
|
65
|
+
if (resource === 'channel') {
|
|
66
|
+
if (operation === 'list') {
|
|
67
|
+
responseData = await pumbleRequest.call(this, 'GET', '/listChannels');
|
|
68
|
+
}
|
|
69
|
+
else if (operation === 'get') {
|
|
70
|
+
const getBy = this.getNodeParameter('getBy', i);
|
|
71
|
+
const qs = {};
|
|
72
|
+
if (getBy === 'channelId') {
|
|
73
|
+
qs.channelId = this.getNodeParameter('channelId', i);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
qs.channel = this.getNodeParameter('channelName', i);
|
|
77
|
+
}
|
|
78
|
+
responseData = await pumbleRequest.call(this, 'GET', '/getChannel', undefined, qs);
|
|
79
|
+
}
|
|
80
|
+
else if (operation === 'create') {
|
|
81
|
+
const body = {
|
|
82
|
+
name: this.getNodeParameter('name', i),
|
|
83
|
+
type: this.getNodeParameter('type', i),
|
|
84
|
+
};
|
|
85
|
+
const description = this.getNodeParameter('description', i);
|
|
86
|
+
if (description)
|
|
87
|
+
body.description = description;
|
|
88
|
+
responseData = await pumbleRequest.call(this, 'POST', '/createChannel', body);
|
|
89
|
+
}
|
|
90
|
+
else if (operation === 'addUsers') {
|
|
91
|
+
const channelId = this.getNodeParameter('channelId', i);
|
|
92
|
+
const userIdsRaw = this.getNodeParameter('userIds', i);
|
|
93
|
+
const userIds = userIdsRaw.split(',').map((s) => s.trim()).filter(Boolean);
|
|
94
|
+
responseData = await pumbleRequest.call(this, 'POST', '/addUsersToChannel', { channelId, userIds });
|
|
95
|
+
}
|
|
96
|
+
else if (operation === 'removeUser') {
|
|
97
|
+
const channelId = this.getNodeParameter('channelId', i);
|
|
98
|
+
const userId = this.getNodeParameter('userId', i);
|
|
99
|
+
responseData = await pumbleRequest.call(this, 'POST', '/removeUserFromChannel', { channelId, userId });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// ═══════════════════════════════════════════════════════════════
|
|
103
|
+
// MESSAGE
|
|
104
|
+
// ═══════════════════════════════════════════════════════════════
|
|
105
|
+
else if (resource === 'message') {
|
|
106
|
+
const resolveChannelIdent = (op) => {
|
|
107
|
+
const identType = this.getNodeParameter('channelIdentType', i);
|
|
108
|
+
const result = {};
|
|
109
|
+
if (identType === 'channelId') {
|
|
110
|
+
result.channelId = this.getNodeParameter('channelId', i);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
result.channel = this.getNodeParameter('channelName', i);
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
116
|
+
};
|
|
117
|
+
if (operation === 'send') {
|
|
118
|
+
const channelIdent = resolveChannelIdent('send');
|
|
119
|
+
const body = {
|
|
120
|
+
...channelIdent,
|
|
121
|
+
text: this.getNodeParameter('text', i),
|
|
122
|
+
asBot: this.getNodeParameter('asBot', i),
|
|
123
|
+
};
|
|
124
|
+
responseData = await pumbleRequest.call(this, 'POST', '/sendMessage', body);
|
|
125
|
+
}
|
|
126
|
+
else if (operation === 'reply') {
|
|
127
|
+
const channelIdent = resolveChannelIdent('reply');
|
|
128
|
+
const body = {
|
|
129
|
+
...channelIdent,
|
|
130
|
+
messageId: this.getNodeParameter('messageId', i),
|
|
131
|
+
text: this.getNodeParameter('text', i),
|
|
132
|
+
asBot: this.getNodeParameter('asBot', i),
|
|
133
|
+
};
|
|
134
|
+
responseData = await pumbleRequest.call(this, 'POST', '/sendReply', body);
|
|
135
|
+
}
|
|
136
|
+
else if (operation === 'fetch') {
|
|
137
|
+
const channelIdent = resolveChannelIdent('fetch');
|
|
138
|
+
const qs = {
|
|
139
|
+
messageId: this.getNodeParameter('messageId', i),
|
|
140
|
+
...channelIdent,
|
|
141
|
+
};
|
|
142
|
+
responseData = await pumbleRequest.call(this, 'GET', '/fetchMessage', undefined, qs);
|
|
143
|
+
}
|
|
144
|
+
else if (operation === 'delete') {
|
|
145
|
+
const channelIdent = resolveChannelIdent('delete');
|
|
146
|
+
const qs = {
|
|
147
|
+
messageId: this.getNodeParameter('messageId', i),
|
|
148
|
+
...channelIdent,
|
|
149
|
+
};
|
|
150
|
+
responseData = await pumbleRequest.call(this, 'DELETE', '/deleteMessage', undefined, qs);
|
|
151
|
+
}
|
|
152
|
+
else if (operation === 'edit') {
|
|
153
|
+
const channelIdent = resolveChannelIdent('edit');
|
|
154
|
+
const body = {
|
|
155
|
+
messageId: this.getNodeParameter('messageId', i),
|
|
156
|
+
...channelIdent,
|
|
157
|
+
text: this.getNodeParameter('text', i),
|
|
158
|
+
};
|
|
159
|
+
responseData = await pumbleRequest.call(this, 'POST', '/editMessage', body);
|
|
160
|
+
}
|
|
161
|
+
else if (operation === 'list') {
|
|
162
|
+
const channelIdent = resolveChannelIdent('list');
|
|
163
|
+
const opts = this.getNodeParameter('listOptions', i, {});
|
|
164
|
+
const qs = { ...channelIdent, ...opts };
|
|
165
|
+
responseData = await pumbleRequest.call(this, 'GET', '/listMessages', undefined, qs);
|
|
166
|
+
}
|
|
167
|
+
else if (operation === 'fetchThreadReplies') {
|
|
168
|
+
const channelIdent = resolveChannelIdent('fetchThreadReplies');
|
|
169
|
+
const rootMessageId = this.getNodeParameter('rootMessageId', i);
|
|
170
|
+
const opts = this.getNodeParameter('threadOptions', i, {});
|
|
171
|
+
const qs = { rootMessageId, ...channelIdent, ...opts };
|
|
172
|
+
responseData = await pumbleRequest.call(this, 'GET', '/fetchThreadReplies', undefined, qs);
|
|
173
|
+
}
|
|
174
|
+
else if (operation === 'search') {
|
|
175
|
+
const body = {};
|
|
176
|
+
const searchText = this.getNodeParameter('searchText', i);
|
|
177
|
+
const searchFrom = this.getNodeParameter('searchFrom', i);
|
|
178
|
+
const searchIn = this.getNodeParameter('searchIn', i);
|
|
179
|
+
if (searchText)
|
|
180
|
+
body.text = searchText;
|
|
181
|
+
if (searchFrom)
|
|
182
|
+
body.from = searchFrom.split(',').map((s) => s.trim()).filter(Boolean);
|
|
183
|
+
if (searchIn)
|
|
184
|
+
body.in = searchIn.split(',').map((s) => s.trim()).filter(Boolean);
|
|
185
|
+
responseData = await pumbleRequest.call(this, 'POST', '/searchMessages', body);
|
|
186
|
+
}
|
|
187
|
+
else if (operation === 'dmUser') {
|
|
188
|
+
const dmBy = this.getNodeParameter('dmUserBy', i);
|
|
189
|
+
const body = {
|
|
190
|
+
text: this.getNodeParameter('text', i),
|
|
191
|
+
};
|
|
192
|
+
if (dmBy === 'userId') {
|
|
193
|
+
body.userId = this.getNodeParameter('userId', i);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
body.email = this.getNodeParameter('email', i);
|
|
197
|
+
}
|
|
198
|
+
responseData = await pumbleRequest.call(this, 'POST', '/dmUser', body);
|
|
199
|
+
}
|
|
200
|
+
else if (operation === 'dmGroup') {
|
|
201
|
+
const dmBy = this.getNodeParameter('dmGroupBy', i);
|
|
202
|
+
const body = {
|
|
203
|
+
text: this.getNodeParameter('text', i),
|
|
204
|
+
};
|
|
205
|
+
if (dmBy === 'userIds') {
|
|
206
|
+
const raw = this.getNodeParameter('userIds', i);
|
|
207
|
+
body.userIds = raw.split(',').map((s) => s.trim()).filter(Boolean);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
const raw = this.getNodeParameter('emails', i);
|
|
211
|
+
body.emails = raw.split(',').map((s) => s.trim()).filter(Boolean);
|
|
212
|
+
}
|
|
213
|
+
responseData = await pumbleRequest.call(this, 'POST', '/dmGroup', body);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
// ═══════════════════════════════════════════════════════════════
|
|
217
|
+
// REACTION
|
|
218
|
+
// ═══════════════════════════════════════════════════════════════
|
|
219
|
+
else if (resource === 'reaction') {
|
|
220
|
+
const messageId = this.getNodeParameter('messageId', i);
|
|
221
|
+
const reaction = this.getNodeParameter('reaction', i);
|
|
222
|
+
if (operation === 'add') {
|
|
223
|
+
responseData = await pumbleRequest.call(this, 'POST', '/addReaction', { messageId, reaction });
|
|
224
|
+
}
|
|
225
|
+
else if (operation === 'remove') {
|
|
226
|
+
responseData = await pumbleRequest.call(this, 'DELETE', '/removeReaction', undefined, { messageId, reaction });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// ═══════════════════════════════════════════════════════════════
|
|
230
|
+
// SCHEDULED MESSAGE
|
|
231
|
+
// ═══════════════════════════════════════════════════════════════
|
|
232
|
+
else if (resource === 'scheduledMessage') {
|
|
233
|
+
if (operation === 'list') {
|
|
234
|
+
const opts = this.getNodeParameter('listOptions', i, {});
|
|
235
|
+
responseData = await pumbleRequest.call(this, 'GET', '/fetchScheduledMessages', undefined, opts);
|
|
236
|
+
}
|
|
237
|
+
else if (operation === 'fetch') {
|
|
238
|
+
const scheduledMessageId = this.getNodeParameter('scheduledMessageId', i);
|
|
239
|
+
responseData = await pumbleRequest.call(this, 'GET', '/fetchScheduledMessage', undefined, { scheduledMessageId });
|
|
240
|
+
}
|
|
241
|
+
else if (operation === 'create') {
|
|
242
|
+
const body = {
|
|
243
|
+
channelId: this.getNodeParameter('channelId', i),
|
|
244
|
+
text: this.getNodeParameter('text', i),
|
|
245
|
+
sendAt: this.getNodeParameter('sendAt', i),
|
|
246
|
+
};
|
|
247
|
+
responseData = await pumbleRequest.call(this, 'POST', '/createScheduledMessage', body);
|
|
248
|
+
}
|
|
249
|
+
else if (operation === 'edit') {
|
|
250
|
+
const body = {
|
|
251
|
+
scheduledMessageId: this.getNodeParameter('scheduledMessageId', i),
|
|
252
|
+
};
|
|
253
|
+
const text = this.getNodeParameter('text', i);
|
|
254
|
+
const sendAt = this.getNodeParameter('sendAt', i);
|
|
255
|
+
const channelId = this.getNodeParameter('channelId', i);
|
|
256
|
+
if (text)
|
|
257
|
+
body.text = text;
|
|
258
|
+
if (sendAt)
|
|
259
|
+
body.sendAt = sendAt;
|
|
260
|
+
if (channelId)
|
|
261
|
+
body.channelId = channelId;
|
|
262
|
+
responseData = await pumbleRequest.call(this, 'POST', '/editScheduledMessage', body);
|
|
263
|
+
}
|
|
264
|
+
else if (operation === 'delete') {
|
|
265
|
+
const scheduledMessageId = this.getNodeParameter('scheduledMessageId', i);
|
|
266
|
+
responseData = await pumbleRequest.call(this, 'DELETE', '/deleteScheduledMessage', undefined, { scheduledMessageId });
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
// ═══════════════════════════════════════════════════════════════
|
|
270
|
+
// USER
|
|
271
|
+
// ═══════════════════════════════════════════════════════════════
|
|
272
|
+
else if (resource === 'user') {
|
|
273
|
+
if (operation === 'myInfo') {
|
|
274
|
+
responseData = await pumbleRequest.call(this, 'GET', '/myInfo');
|
|
275
|
+
}
|
|
276
|
+
else if (operation === 'list') {
|
|
277
|
+
responseData = await pumbleRequest.call(this, 'GET', '/listUsers');
|
|
278
|
+
}
|
|
279
|
+
else if (operation === 'listGroups') {
|
|
280
|
+
responseData = await pumbleRequest.call(this, 'GET', '/listUserGroups');
|
|
281
|
+
}
|
|
282
|
+
else if (operation === 'customStatus') {
|
|
283
|
+
const body = {
|
|
284
|
+
code: this.getNodeParameter('code', i),
|
|
285
|
+
status: this.getNodeParameter('status', i),
|
|
286
|
+
expiration: this.getNodeParameter('expiration', i),
|
|
287
|
+
};
|
|
288
|
+
const expiresAt = this.getNodeParameter('expiresAt', i, 0);
|
|
289
|
+
if (expiresAt)
|
|
290
|
+
body.expiresAt = expiresAt;
|
|
291
|
+
responseData = await pumbleRequest.call(this, 'POST', '/customStatus', body);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
// Normalise response into INodeExecutionData
|
|
295
|
+
if (Array.isArray(responseData)) {
|
|
296
|
+
const execData = this.helpers.returnJsonArray(responseData);
|
|
297
|
+
returnData.push(...execData);
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
returnData.push({ json: (_a = responseData) !== null && _a !== void 0 ? _a : {} });
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
if (this.continueOnFail()) {
|
|
305
|
+
returnData.push({ json: { error: error.message }, pairedItem: { item: i } });
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, { itemIndex: i });
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return [returnData];
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
exports.Pumble = Pumble;
|
|
315
|
+
// ─── Private helper (bound via .call) ────────────────────────────────────────
|
|
316
|
+
async function pumbleRequest(method, endpoint, body, qs) {
|
|
317
|
+
const credentials = await this.getCredentials('pumbleApi');
|
|
318
|
+
const cleanQs = {};
|
|
319
|
+
if (qs) {
|
|
320
|
+
for (const [k, v] of Object.entries(qs)) {
|
|
321
|
+
if (v !== undefined && v !== '' && v !== 0) {
|
|
322
|
+
cleanQs[k] = v;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return this.helpers.request({
|
|
327
|
+
method,
|
|
328
|
+
url: `${BASE_URL}${endpoint}`,
|
|
329
|
+
headers: {
|
|
330
|
+
ApiKey: credentials.apiKey,
|
|
331
|
+
'Content-Type': 'application/json',
|
|
332
|
+
},
|
|
333
|
+
qs: cleanQs,
|
|
334
|
+
body,
|
|
335
|
+
json: true,
|
|
336
|
+
});
|
|
337
|
+
}
|