@linkorb/n8n-nodes-nebula 1.0.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 +22 -0
- package/README.md +438 -0
- package/dist/credentials/NebulaApi.credentials.d.ts +11 -0
- package/dist/credentials/NebulaApi.credentials.d.ts.map +1 -0
- package/dist/credentials/NebulaApi.credentials.js +68 -0
- package/dist/credentials/NebulaApi.credentials.js.map +1 -0
- package/dist/credentials/nebulaApi.svg +11 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/nodes/NebulaHitlRequest/NebulaHitlRequest.node.d.ts +7 -0
- package/dist/nodes/NebulaHitlRequest/NebulaHitlRequest.node.d.ts.map +1 -0
- package/dist/nodes/NebulaHitlRequest/NebulaHitlRequest.node.js +390 -0
- package/dist/nodes/NebulaHitlRequest/NebulaHitlRequest.node.js.map +1 -0
- package/dist/nodes/NebulaHitlRequest/NebulaHitlRequest.node.json +28 -0
- package/dist/nodes/NebulaHitlRequest/nebulaHitlRequest.svg +7 -0
- package/package.json +69 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Joost Faassen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
# n8n-nodes-nebula
|
|
2
|
+
|
|
3
|
+
A custom n8n node for implementing **Nebula HITL (Human-in-the-Loop)** workflows with your own configurable REST API backend.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Description
|
|
8
|
+
|
|
9
|
+
This node allows you to create human approval/input requests in your n8n workflows. Unlike other HITL solutions that are tied to specific cloud services, this node is designed to work with **your own backend**, giving you full control over how requests are created, stored, displayed, and responded to.
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
- βΈοΈ **True Wait Functionality**: Workflow execution pauses until a human responds
|
|
14
|
+
- π **Configurable Backend**: Connect to your own REST API endpoint
|
|
15
|
+
- π **Multiple Response Types**: Ok, Yes/No, Text, or Custom options
|
|
16
|
+
- π·οΈ **Rich Metadata**: Support for priority, assignee, tags, and custom data
|
|
17
|
+
- π **Webhook-based Responses**: Automatically resume workflow when human responds
|
|
18
|
+
- β° **Configurable Timeout**: Set how long to wait for a response
|
|
19
|
+
- π **Full Context**: Pass workflow and execution context to your backend
|
|
20
|
+
|
|
21
|
+
### How It Works
|
|
22
|
+
|
|
23
|
+
1. **Request Creation**: The node POSTs a request to your backend with all details including a webhook URL
|
|
24
|
+
2. **Workflow Pauses**: The n8n execution enters a "waiting" state - no resources are consumed while waiting
|
|
25
|
+
3. **Human Action**: Your backend displays the request to a human for action
|
|
26
|
+
4. **Webhook Callback**: When the human responds, your backend POSTs to the webhook URL
|
|
27
|
+
5. **Workflow Resumes**: n8n receives the webhook, resumes the workflow with the response data as output
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
### Prerequisites
|
|
32
|
+
|
|
33
|
+
- n8n version 1.0.0 or later
|
|
34
|
+
- Node.js 18.10 or later
|
|
35
|
+
- pnpm (recommended) or npm
|
|
36
|
+
|
|
37
|
+
### Install via npm (Community Nodes)
|
|
38
|
+
|
|
39
|
+
In your n8n instance, go to **Settings β Community Nodes** and install:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
n8n-nodes-nebula
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Manual Installation (Self-hosted n8n)
|
|
46
|
+
|
|
47
|
+
1. **Clone or download this repository:**
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
cd ~/.n8n/custom
|
|
51
|
+
git clone https://github.com/linkorb/n8n-nodes-nebula.git
|
|
52
|
+
cd n8n-nodes-nebula
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
2. **Install dependencies:**
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pnpm install
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
3. **Build the node:**
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pnpm build
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
4. **Restart n8n:**
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# If running n8n directly
|
|
71
|
+
n8n start
|
|
72
|
+
|
|
73
|
+
# If running via PM2
|
|
74
|
+
pm2 restart n8n
|
|
75
|
+
|
|
76
|
+
# If running via Docker
|
|
77
|
+
docker restart n8n
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Installation with Docker
|
|
81
|
+
|
|
82
|
+
If you're running n8n in Docker, you can mount the custom nodes:
|
|
83
|
+
|
|
84
|
+
```yaml
|
|
85
|
+
version: '3.8'
|
|
86
|
+
services:
|
|
87
|
+
n8n:
|
|
88
|
+
image: n8nio/n8n
|
|
89
|
+
volumes:
|
|
90
|
+
- ~/.n8n:/home/node/.n8n
|
|
91
|
+
- ./n8n-nodes-nebula:/home/node/.n8n/custom/n8n-nodes-nebula
|
|
92
|
+
environment:
|
|
93
|
+
- N8N_CUSTOM_EXTENSIONS=/home/node/.n8n/custom
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Configuration
|
|
97
|
+
|
|
98
|
+
### Setting up Credentials
|
|
99
|
+
|
|
100
|
+
1. In n8n, go to **Credentials β Add Credential**
|
|
101
|
+
2. Search for "Nebula API"
|
|
102
|
+
3. Fill in the required fields:
|
|
103
|
+
|
|
104
|
+
| Field | Description | Example |
|
|
105
|
+
|-------|-------------|---------|
|
|
106
|
+
| **Base URL** | Your Nebula API backend base URL | `https://api.mycompany.com/nebula` |
|
|
107
|
+
| **Username** | Authentication username | `n8n-service` |
|
|
108
|
+
| **Password** | Authentication password | `your-secure-password` |
|
|
109
|
+
| **Metadata** | Additional JSON data for all requests | `{"tenantId": "abc123"}` |
|
|
110
|
+
|
|
111
|
+
> **Note:** The webhook callback URL is automatically determined from your n8n instance configuration. You don't need to specify it manually.
|
|
112
|
+
|
|
113
|
+
## Usage
|
|
114
|
+
|
|
115
|
+
### Basic Workflow
|
|
116
|
+
|
|
117
|
+
1. Add the **Nebula HITL Request** node to your workflow
|
|
118
|
+
2. Connect it to your workflow flow
|
|
119
|
+
3. Configure the node:
|
|
120
|
+
- **Title**: A short description of what needs human attention
|
|
121
|
+
- **Message**: Detailed markdown-formatted message
|
|
122
|
+
- **Response Type**: Choose from Ok, Yes/No, Text, or Form
|
|
123
|
+
|
|
124
|
+
### Response Types
|
|
125
|
+
|
|
126
|
+
| Type | Description | Response Value |
|
|
127
|
+
|------|-------------|----------------|
|
|
128
|
+
| **Ok** | Simple acknowledgement | `"ok"` |
|
|
129
|
+
| **Yes/No** | Binary choice | `"yes"` or `"no"` |
|
|
130
|
+
| **Text** | Free-form text input | User's text input |
|
|
131
|
+
| **Form (survey.json)** | Custom form in survey.json format | Form submission data |
|
|
132
|
+
|
|
133
|
+
### Form JSON Example
|
|
134
|
+
|
|
135
|
+
The Form response type uses [survey.json](https://surveyjs.io/form-library/documentation/design-survey/create-a-simple-survey) format:
|
|
136
|
+
|
|
137
|
+
```json
|
|
138
|
+
{
|
|
139
|
+
"elements": [
|
|
140
|
+
{
|
|
141
|
+
"type": "radiogroup",
|
|
142
|
+
"name": "decision",
|
|
143
|
+
"title": "Please select an option",
|
|
144
|
+
"choices": ["Approve", "Reject", "Need More Info"]
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"type": "text",
|
|
148
|
+
"name": "comment",
|
|
149
|
+
"title": "Additional comments"
|
|
150
|
+
}
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Node Options
|
|
156
|
+
|
|
157
|
+
| Option | Description | Default |
|
|
158
|
+
|--------|-------------|---------|
|
|
159
|
+
| **Priority** | Request priority level | `normal` |
|
|
160
|
+
| **Timeout (Minutes)** | Auto-timeout for requests | `0` (no timeout) |
|
|
161
|
+
| **Assignee** | Email/ID to assign request to | (none) |
|
|
162
|
+
| **Tags** | Comma-separated tags | (none) |
|
|
163
|
+
|
|
164
|
+
### Additional Data
|
|
165
|
+
|
|
166
|
+
You can pass additional JSON data that will be included in the request to your backend:
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"orderId": "12345",
|
|
171
|
+
"customerName": "John Doe",
|
|
172
|
+
"amount": 150.00
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Backend API Requirements
|
|
177
|
+
|
|
178
|
+
Your backend API needs to implement the following endpoint:
|
|
179
|
+
|
|
180
|
+
### POST /requests
|
|
181
|
+
|
|
182
|
+
Creates a new HITL request.
|
|
183
|
+
|
|
184
|
+
**Request Body:**
|
|
185
|
+
|
|
186
|
+
```json
|
|
187
|
+
{
|
|
188
|
+
"requestId": "uuid-v4-string",
|
|
189
|
+
"title": "Approval Required",
|
|
190
|
+
"message": "Please review this order...",
|
|
191
|
+
"responseType": "yesno",
|
|
192
|
+
"form": null,
|
|
193
|
+
"webhookUrl": "https://your-n8n.com/webhook-waiting/xxx/nebula-hitl-response",
|
|
194
|
+
"priority": "normal",
|
|
195
|
+
"timeoutMinutes": 0,
|
|
196
|
+
"assignee": "john@example.com",
|
|
197
|
+
"tags": ["urgent", "finance"],
|
|
198
|
+
"metadata": {"tenantId": "abc123"},
|
|
199
|
+
"additionalData": {"orderId": "12345"},
|
|
200
|
+
"inputData": {},
|
|
201
|
+
"workflowId": "workflow-id",
|
|
202
|
+
"executionId": "execution-id",
|
|
203
|
+
"createdAt": "2024-01-15T10:30:00Z"
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Response:**
|
|
208
|
+
|
|
209
|
+
```json
|
|
210
|
+
{
|
|
211
|
+
"success": true,
|
|
212
|
+
"requestId": "uuid-v4-string",
|
|
213
|
+
"status": "pending"
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Webhook Callback (IMPORTANT - This Resumes the Workflow!)
|
|
218
|
+
|
|
219
|
+
When a human responds, your backend **MUST** call the `webhookUrl` provided in the request payload. This is what resumes the waiting n8n workflow execution.
|
|
220
|
+
|
|
221
|
+
**POST to webhookUrl:**
|
|
222
|
+
|
|
223
|
+
```json
|
|
224
|
+
{
|
|
225
|
+
"requestId": "uuid-v4-string",
|
|
226
|
+
"response": "approved",
|
|
227
|
+
"responseValue": "approved",
|
|
228
|
+
"respondedBy": "john@example.com",
|
|
229
|
+
"respondedAt": "2024-01-15T11:45:00Z",
|
|
230
|
+
"comment": "Looks good!",
|
|
231
|
+
"data": {
|
|
232
|
+
"anyAdditionalData": "you want to pass"
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**What happens:**
|
|
238
|
+
1. n8n receives the webhook POST
|
|
239
|
+
2. The waiting workflow execution resumes
|
|
240
|
+
3. The Nebula HITL Request node outputs the webhook payload data
|
|
241
|
+
4. Subsequent nodes in your workflow can access `$json.response`, `$json.respondedBy`, etc.
|
|
242
|
+
|
|
243
|
+
**The webhook URL format:** `https://your-n8n-instance.com/webhook-waiting/{executionId}/nebula-hitl-response`
|
|
244
|
+
|
|
245
|
+
The `webhookUrl` is automatically constructed and included in the request payload sent to your backend. Your backend simply needs to POST to this URL when a human responds.
|
|
246
|
+
|
|
247
|
+
### Health Check (Optional)
|
|
248
|
+
|
|
249
|
+
For credential testing, implement:
|
|
250
|
+
|
|
251
|
+
**GET /health**
|
|
252
|
+
|
|
253
|
+
```json
|
|
254
|
+
{
|
|
255
|
+
"status": "ok"
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Example Backend Implementation
|
|
260
|
+
|
|
261
|
+
Here's a minimal Express.js backend example:
|
|
262
|
+
|
|
263
|
+
```javascript
|
|
264
|
+
const express = require('express');
|
|
265
|
+
const app = express();
|
|
266
|
+
|
|
267
|
+
app.use(express.json());
|
|
268
|
+
|
|
269
|
+
// Store requests in memory (use a database in production)
|
|
270
|
+
const requests = new Map();
|
|
271
|
+
|
|
272
|
+
// Create request
|
|
273
|
+
app.post('/requests', (req, res) => {
|
|
274
|
+
const { requestId, webhookUrl, ...data } = req.body;
|
|
275
|
+
|
|
276
|
+
requests.set(requestId, {
|
|
277
|
+
...data,
|
|
278
|
+
requestId,
|
|
279
|
+
webhookUrl,
|
|
280
|
+
status: 'pending'
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
console.log('New Nebula HITL request:', requestId, data.title);
|
|
284
|
+
|
|
285
|
+
res.json({ success: true, requestId, status: 'pending' });
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
// Respond to request (called by your UI)
|
|
289
|
+
app.post('/requests/:requestId/respond', async (req, res) => {
|
|
290
|
+
const requestId = req.params.requestId;
|
|
291
|
+
const { response, respondedBy } = req.body;
|
|
292
|
+
|
|
293
|
+
const request = requests.get(requestId);
|
|
294
|
+
if (!request) {
|
|
295
|
+
return res.status(404).json({ error: 'Request not found' });
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Call n8n webhook to resume workflow
|
|
299
|
+
await fetch(request.webhookUrl, {
|
|
300
|
+
method: 'POST',
|
|
301
|
+
headers: { 'Content-Type': 'application/json' },
|
|
302
|
+
body: JSON.stringify({
|
|
303
|
+
requestId,
|
|
304
|
+
response,
|
|
305
|
+
responseValue: response,
|
|
306
|
+
respondedBy,
|
|
307
|
+
respondedAt: new Date().toISOString()
|
|
308
|
+
})
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
requests.delete(requestId);
|
|
312
|
+
|
|
313
|
+
res.json({ success: true });
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// Health check
|
|
317
|
+
app.get('/health', (req, res) => {
|
|
318
|
+
res.json({ status: 'ok' });
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
app.listen(3000, () => {
|
|
322
|
+
console.log('Nebula HITL Backend running on port 3000');
|
|
323
|
+
});
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
## Workflow Example
|
|
327
|
+
|
|
328
|
+
```
|
|
329
|
+
[Trigger] β [Process Data] β [Nebula HITL Request] β [If Response == "approved"] β [Continue]
|
|
330
|
+
β
|
|
331
|
+
[Handle Rejection]
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Accessing Response Data
|
|
335
|
+
|
|
336
|
+
After the Nebula HITL Request node resumes (when the webhook is called), the node outputs the webhook payload data. You can access:
|
|
337
|
+
|
|
338
|
+
```javascript
|
|
339
|
+
// In a Code node or expression
|
|
340
|
+
const requestId = $json.requestId; // The original request ID
|
|
341
|
+
const response = $json.response; // The response value (e.g., "approved", "yes", "rejected")
|
|
342
|
+
const responseValue = $json.responseValue; // Same as response (for compatibility)
|
|
343
|
+
const respondedBy = $json.respondedBy; // Who responded (email/ID)
|
|
344
|
+
const respondedAt = $json.respondedAt; // ISO timestamp when they responded
|
|
345
|
+
const comment = $json.comment; // Optional comment from responder
|
|
346
|
+
const data = $json.data; // Any additional data from your backend
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
**Example: Using in an IF node condition:**
|
|
350
|
+
```
|
|
351
|
+
{{ $json.response }} equals "approved"
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
**Example: Send notification with response:**
|
|
355
|
+
```
|
|
356
|
+
The request was {{ $json.response }} by {{ $json.respondedBy }} at {{ $json.respondedAt }}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
## Development
|
|
360
|
+
|
|
361
|
+
### Project Structure
|
|
362
|
+
|
|
363
|
+
```
|
|
364
|
+
n8n-nodes-nebula/
|
|
365
|
+
βββ credentials/
|
|
366
|
+
β βββ NebulaApi.credentials.ts
|
|
367
|
+
βββ nodes/
|
|
368
|
+
β βββ NebulaHitlRequest/
|
|
369
|
+
β βββ NebulaHitlRequest.node.ts
|
|
370
|
+
β βββ NebulaHitlRequest.node.json
|
|
371
|
+
β βββ nebulaHitlRequest.svg
|
|
372
|
+
βββ package.json
|
|
373
|
+
βββ tsconfig.json
|
|
374
|
+
βββ README.md
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Building from Source
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
# Install dependencies
|
|
381
|
+
pnpm install
|
|
382
|
+
|
|
383
|
+
# Build
|
|
384
|
+
pnpm build
|
|
385
|
+
|
|
386
|
+
# Watch mode (for development)
|
|
387
|
+
pnpm dev
|
|
388
|
+
|
|
389
|
+
# Lint
|
|
390
|
+
pnpm lint
|
|
391
|
+
|
|
392
|
+
# Format
|
|
393
|
+
pnpm format
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
## Troubleshooting
|
|
397
|
+
|
|
398
|
+
### Node not appearing in n8n
|
|
399
|
+
|
|
400
|
+
1. Ensure the build completed successfully (`pnpm build`)
|
|
401
|
+
2. Check that the `dist` folder contains compiled JS files
|
|
402
|
+
3. Verify the custom nodes path in n8n configuration
|
|
403
|
+
4. Restart n8n completely
|
|
404
|
+
|
|
405
|
+
### Webhook not being called
|
|
406
|
+
|
|
407
|
+
1. Ensure your n8n instance is publicly accessible or your backend can reach it
|
|
408
|
+
2. Check the webhookUrl in your backend logs
|
|
409
|
+
3. Verify the requestId matches in both the request and response
|
|
410
|
+
|
|
411
|
+
### Authentication errors
|
|
412
|
+
|
|
413
|
+
1. Verify credentials in n8n are correct
|
|
414
|
+
2. Check your backend's authentication logic
|
|
415
|
+
3. Look at the backend logs for more details
|
|
416
|
+
|
|
417
|
+
## Contributing
|
|
418
|
+
|
|
419
|
+
Contributions are welcome! Please:
|
|
420
|
+
|
|
421
|
+
1. Fork the repository
|
|
422
|
+
2. Create a feature branch
|
|
423
|
+
3. Make your changes
|
|
424
|
+
4. Submit a pull request
|
|
425
|
+
|
|
426
|
+
## License
|
|
427
|
+
|
|
428
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
429
|
+
|
|
430
|
+
## Related Projects
|
|
431
|
+
|
|
432
|
+
- [n8n](https://n8n.io) - Fair-code workflow automation
|
|
433
|
+
- [n8n documentation on creating nodes](https://docs.n8n.io/integrations/creating-nodes/)
|
|
434
|
+
|
|
435
|
+
## Support
|
|
436
|
+
|
|
437
|
+
- Create an issue on GitHub for bug reports
|
|
438
|
+
- Discussions for questions and feature requests
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
|
|
2
|
+
export declare class NebulaApi implements ICredentialType {
|
|
3
|
+
name: string;
|
|
4
|
+
displayName: string;
|
|
5
|
+
documentationUrl: string;
|
|
6
|
+
icon: "fa:circle-nodes";
|
|
7
|
+
properties: INodeProperties[];
|
|
8
|
+
authenticate: IAuthenticateGeneric;
|
|
9
|
+
test: ICredentialTestRequest;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=NebulaApi.credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NebulaApi.credentials.d.ts","sourceRoot":"","sources":["../../credentials/NebulaApi.credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,eAAe,EACf,eAAe,EAChB,MAAM,cAAc,CAAC;AAEtB,qBAAa,SAAU,YAAW,eAAe;IAC/C,IAAI,SAAe;IACnB,WAAW,SAAgB;IAC3B,gBAAgB,SAAiD;IAIjE,IAAI,EAAG,iBAAiB,CAAU;IAElC,UAAU,EAAE,eAAe,EAAE,CAqC3B;IAEF,YAAY,EAAE,oBAAoB,CAQhC;IAEF,IAAI,EAAE,sBAAsB,CAM1B;CACH"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NebulaApi = void 0;
|
|
4
|
+
class NebulaApi {
|
|
5
|
+
name = 'nebulaApi';
|
|
6
|
+
displayName = 'Nebula API';
|
|
7
|
+
documentationUrl = 'https://github.com/linkorb/n8n-nodes-nebula';
|
|
8
|
+
// Note: Custom SVG icons don't work with N8N_CUSTOM_EXTENSIONS due to n8n bug
|
|
9
|
+
// See: https://github.com/n8n-io/n8n/issues/21360
|
|
10
|
+
// Using Font Awesome as fallback. Install via npm for custom SVG icons.
|
|
11
|
+
icon = 'fa:circle-nodes';
|
|
12
|
+
properties = [
|
|
13
|
+
{
|
|
14
|
+
displayName: 'Base URL',
|
|
15
|
+
name: 'baseUrl',
|
|
16
|
+
type: 'string',
|
|
17
|
+
default: '',
|
|
18
|
+
placeholder: 'https://api.example.com',
|
|
19
|
+
description: 'The base URL of your Nebula API backend',
|
|
20
|
+
required: true,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
displayName: 'Username',
|
|
24
|
+
name: 'username',
|
|
25
|
+
type: 'string',
|
|
26
|
+
default: '',
|
|
27
|
+
description: 'Username for authentication with the API',
|
|
28
|
+
required: true,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
displayName: 'Password',
|
|
32
|
+
name: 'password',
|
|
33
|
+
type: 'string',
|
|
34
|
+
typeOptions: {
|
|
35
|
+
password: true,
|
|
36
|
+
},
|
|
37
|
+
default: '',
|
|
38
|
+
description: 'Password for authentication with the API',
|
|
39
|
+
required: true,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
displayName: 'Metadata',
|
|
43
|
+
name: 'metadata',
|
|
44
|
+
type: 'json',
|
|
45
|
+
default: '{}',
|
|
46
|
+
description: 'Additional JSON metadata to include with all requests (e.g., tenant ID, environment)',
|
|
47
|
+
placeholder: '{"tenantId": "abc123", "environment": "production"}',
|
|
48
|
+
},
|
|
49
|
+
];
|
|
50
|
+
authenticate = {
|
|
51
|
+
type: 'generic',
|
|
52
|
+
properties: {
|
|
53
|
+
auth: {
|
|
54
|
+
username: '={{$credentials.username}}',
|
|
55
|
+
password: '={{$credentials.password}}',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
test = {
|
|
60
|
+
request: {
|
|
61
|
+
baseURL: '={{$credentials.baseUrl}}',
|
|
62
|
+
url: '/health',
|
|
63
|
+
method: 'GET',
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
exports.NebulaApi = NebulaApi;
|
|
68
|
+
//# sourceMappingURL=NebulaApi.credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NebulaApi.credentials.js","sourceRoot":"","sources":["../../credentials/NebulaApi.credentials.ts"],"names":[],"mappings":";;;AAOA,MAAa,SAAS;IACpB,IAAI,GAAG,WAAW,CAAC;IACnB,WAAW,GAAG,YAAY,CAAC;IAC3B,gBAAgB,GAAG,6CAA6C,CAAC;IACjE,8EAA8E;IAC9E,kDAAkD;IAClD,wEAAwE;IACxE,IAAI,GAAG,iBAA0B,CAAC;IAElC,UAAU,GAAsB;QAC9B;YACE,WAAW,EAAE,UAAU;YACvB,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,EAAE;YACX,WAAW,EAAE,yBAAyB;YACtC,WAAW,EAAE,yCAAyC;YACtD,QAAQ,EAAE,IAAI;SACf;QACD;YACE,WAAW,EAAE,UAAU;YACvB,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,EAAE;YACX,WAAW,EAAE,0CAA0C;YACvD,QAAQ,EAAE,IAAI;SACf;QACD;YACE,WAAW,EAAE,UAAU;YACvB,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE;gBACX,QAAQ,EAAE,IAAI;aACf;YACD,OAAO,EAAE,EAAE;YACX,WAAW,EAAE,0CAA0C;YACvD,QAAQ,EAAE,IAAI;SACf;QACD;YACE,WAAW,EAAE,UAAU;YACvB,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,sFAAsF;YACnG,WAAW,EAAE,qDAAqD;SACnE;KACF,CAAC;IAEF,YAAY,GAAyB;QACnC,IAAI,EAAE,SAAS;QACf,UAAU,EAAE;YACV,IAAI,EAAE;gBACJ,QAAQ,EAAE,4BAA4B;gBACtC,QAAQ,EAAE,4BAA4B;aACvC;SACF;KACF,CAAC;IAEF,IAAI,GAA2B;QAC7B,OAAO,EAAE;YACP,OAAO,EAAE,2BAA2B;YACpC,GAAG,EAAE,SAAS;YACd,MAAM,EAAE,KAAK;SACd;KACF,CAAC;CACH;AAjED,8BAiEC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60">
|
|
2
|
+
<rect width="60" height="60" rx="8" fill="#1a1a2e"/>
|
|
3
|
+
<g transform="translate(10, 10)">
|
|
4
|
+
<path d="M20 2C10.059 2 2 10.059 2 20s8.059 18 18 18c4.641 0 8.886-1.76 12.082-4.646l4.95 4.95v-3.608h4.085L35.355 29.1A17.91 17.91 0 0038 20c0-9.941-8.059-18-18-18z" fill="#F58220"/>
|
|
5
|
+
<circle cx="20" cy="20" r="9" fill="#1a1a2e"/>
|
|
6
|
+
<path d="M30 28l10 10v-6h-4v-6h-6z" fill="#F58220"/>
|
|
7
|
+
</g>
|
|
8
|
+
<circle cx="10" cy="10" r="1.2" fill="#fff" opacity="0.5"/>
|
|
9
|
+
<circle cx="50" cy="8" r="0.8" fill="#fff" opacity="0.4"/>
|
|
10
|
+
<circle cx="52" cy="50" r="1" fill="#fff" opacity="0.5"/>
|
|
11
|
+
</svg>
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { IExecuteFunctions, INodeType, INodeTypeDescription, INodeExecutionData, IWebhookFunctions, IWebhookResponseData } from 'n8n-workflow';
|
|
2
|
+
export declare class NebulaHitlRequest implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
webhook(this: IWebhookFunctions): Promise<IWebhookResponseData>;
|
|
5
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=NebulaHitlRequest.node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NebulaHitlRequest.node.d.ts","sourceRoot":"","sources":["../../../nodes/NebulaHitlRequest/NebulaHitlRequest.node.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,SAAS,EACT,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EAGrB,MAAM,cAAc,CAAC;AAGtB,qBAAa,iBAAkB,YAAW,SAAS;IACjD,WAAW,EAAE,oBAAoB,CA+L/B;IAEI,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAsC/D,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;CAmLxE"}
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NebulaHitlRequest = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const uuid_1 = require("uuid");
|
|
6
|
+
class NebulaHitlRequest {
|
|
7
|
+
description = {
|
|
8
|
+
displayName: 'Nebula HITL Request',
|
|
9
|
+
name: 'nebulaHitlRequest',
|
|
10
|
+
// Note: Custom SVG icons don't work with N8N_CUSTOM_EXTENSIONS due to n8n bug
|
|
11
|
+
// See: https://github.com/n8n-io/n8n/issues/21360
|
|
12
|
+
// Using Font Awesome as fallback. Install via npm for custom SVG icons.
|
|
13
|
+
icon: 'fa:user-clock',
|
|
14
|
+
group: ['transform'],
|
|
15
|
+
version: 1,
|
|
16
|
+
subtitle: '={{$parameter["operation"]}}',
|
|
17
|
+
description: 'Send Human-in-the-Loop requests via Nebula and wait for responses',
|
|
18
|
+
defaults: {
|
|
19
|
+
name: 'Nebula HITL Request',
|
|
20
|
+
},
|
|
21
|
+
inputs: ['main'],
|
|
22
|
+
outputs: ['main'],
|
|
23
|
+
credentials: [
|
|
24
|
+
{
|
|
25
|
+
name: 'nebulaApi',
|
|
26
|
+
required: true,
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
webhooks: [
|
|
30
|
+
{
|
|
31
|
+
name: 'default',
|
|
32
|
+
httpMethod: 'POST',
|
|
33
|
+
responseMode: 'onReceived',
|
|
34
|
+
path: 'nebula-hitl-response',
|
|
35
|
+
restartWebhook: true,
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
properties: [
|
|
39
|
+
{
|
|
40
|
+
displayName: 'Operation',
|
|
41
|
+
name: 'operation',
|
|
42
|
+
type: 'options',
|
|
43
|
+
noDataExpression: true,
|
|
44
|
+
options: [
|
|
45
|
+
{
|
|
46
|
+
name: 'HITL Request',
|
|
47
|
+
value: 'hitlRequest',
|
|
48
|
+
description: 'Create a Human-in-the-Loop request and wait for response',
|
|
49
|
+
action: 'Create a HITL request and wait for response',
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
default: 'hitlRequest',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
displayName: 'Title',
|
|
56
|
+
name: 'title',
|
|
57
|
+
type: 'string',
|
|
58
|
+
default: '',
|
|
59
|
+
placeholder: 'Approval Required',
|
|
60
|
+
description: 'A short title for the HITL request',
|
|
61
|
+
required: true,
|
|
62
|
+
displayOptions: {
|
|
63
|
+
show: {
|
|
64
|
+
operation: ['hitlRequest'],
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
displayName: 'Message',
|
|
70
|
+
name: 'message',
|
|
71
|
+
type: 'string',
|
|
72
|
+
typeOptions: {
|
|
73
|
+
rows: 6,
|
|
74
|
+
},
|
|
75
|
+
default: '',
|
|
76
|
+
placeholder: 'Please review the following information and provide your approval...',
|
|
77
|
+
description: 'A detailed message in Markdown format',
|
|
78
|
+
required: true,
|
|
79
|
+
displayOptions: {
|
|
80
|
+
show: {
|
|
81
|
+
operation: ['hitlRequest'],
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
displayName: 'Response Type',
|
|
87
|
+
name: 'responseType',
|
|
88
|
+
type: 'options',
|
|
89
|
+
options: [
|
|
90
|
+
{
|
|
91
|
+
name: 'Ok',
|
|
92
|
+
value: 'ok',
|
|
93
|
+
description: 'Simple acknowledgement with an OK button',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: 'Yes/No',
|
|
97
|
+
value: 'yesno',
|
|
98
|
+
description: 'Binary choice between Yes and No',
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: 'Text',
|
|
102
|
+
value: 'text',
|
|
103
|
+
description: 'Free-form text input',
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'Form (survey.json)',
|
|
107
|
+
value: 'form',
|
|
108
|
+
description: 'Custom form defined as survey.json JSON format',
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
default: 'ok',
|
|
112
|
+
description: 'The type of response expected from the human',
|
|
113
|
+
displayOptions: {
|
|
114
|
+
show: {
|
|
115
|
+
operation: ['hitlRequest'],
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
displayName: 'Form JSON',
|
|
121
|
+
name: 'formJson',
|
|
122
|
+
type: 'json',
|
|
123
|
+
default: '{\n "elements": [\n {\n "type": "radiogroup",\n "name": "decision",\n "title": "Please select an option",\n "choices": ["Approve", "Reject", "Need More Info"]\n }\n ]\n}',
|
|
124
|
+
placeholder: '{"elements": [{"type": "text", "name": "comment", "title": "Your comment"}]}',
|
|
125
|
+
description: 'Form definition in survey.json JSON format',
|
|
126
|
+
displayOptions: {
|
|
127
|
+
show: {
|
|
128
|
+
operation: ['hitlRequest'],
|
|
129
|
+
responseType: ['form'],
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
displayName: 'Additional Data',
|
|
135
|
+
name: 'additionalData',
|
|
136
|
+
type: 'json',
|
|
137
|
+
default: '{}',
|
|
138
|
+
description: 'Additional JSON data to include with the request',
|
|
139
|
+
displayOptions: {
|
|
140
|
+
show: {
|
|
141
|
+
operation: ['hitlRequest'],
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
displayName: 'Options',
|
|
147
|
+
name: 'options',
|
|
148
|
+
type: 'collection',
|
|
149
|
+
placeholder: 'Add Option',
|
|
150
|
+
default: {},
|
|
151
|
+
displayOptions: {
|
|
152
|
+
show: {
|
|
153
|
+
operation: ['hitlRequest'],
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
options: [
|
|
157
|
+
{
|
|
158
|
+
displayName: 'Priority',
|
|
159
|
+
name: 'priority',
|
|
160
|
+
type: 'options',
|
|
161
|
+
options: [
|
|
162
|
+
{ name: 'Low', value: 'low' },
|
|
163
|
+
{ name: 'Normal', value: 'normal' },
|
|
164
|
+
{ name: 'High', value: 'high' },
|
|
165
|
+
{ name: 'Urgent', value: 'urgent' },
|
|
166
|
+
],
|
|
167
|
+
default: 'normal',
|
|
168
|
+
description: 'Priority level of the request',
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
displayName: 'Timeout (Minutes)',
|
|
172
|
+
name: 'timeoutMinutes',
|
|
173
|
+
type: 'number',
|
|
174
|
+
default: 0,
|
|
175
|
+
description: 'Timeout in minutes after which the workflow continues with a timeout response (0 = wait indefinitely)',
|
|
176
|
+
typeOptions: {
|
|
177
|
+
minValue: 0,
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
displayName: 'Assignee',
|
|
182
|
+
name: 'assignee',
|
|
183
|
+
type: 'string',
|
|
184
|
+
default: '',
|
|
185
|
+
description: 'Email or ID of the person to assign this request to',
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
displayName: 'Tags',
|
|
189
|
+
name: 'tags',
|
|
190
|
+
type: 'string',
|
|
191
|
+
default: '',
|
|
192
|
+
description: 'Comma-separated list of tags',
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
},
|
|
196
|
+
],
|
|
197
|
+
};
|
|
198
|
+
async webhook() {
|
|
199
|
+
const bodyData = this.getBodyData();
|
|
200
|
+
// Validate the incoming webhook has required data
|
|
201
|
+
if (!bodyData.requestId) {
|
|
202
|
+
return {
|
|
203
|
+
webhookResponse: {
|
|
204
|
+
status: 400,
|
|
205
|
+
body: { error: 'Missing requestId in webhook payload' },
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
// Return the response data to continue the workflow
|
|
210
|
+
// The webhook data becomes the output of the node
|
|
211
|
+
return {
|
|
212
|
+
webhookResponse: {
|
|
213
|
+
status: 200,
|
|
214
|
+
body: { success: true, message: 'Response received, workflow will continue' },
|
|
215
|
+
},
|
|
216
|
+
workflowData: [
|
|
217
|
+
[
|
|
218
|
+
{
|
|
219
|
+
json: {
|
|
220
|
+
requestId: bodyData.requestId,
|
|
221
|
+
response: bodyData.response,
|
|
222
|
+
responseValue: bodyData.responseValue,
|
|
223
|
+
respondedBy: bodyData.respondedBy,
|
|
224
|
+
respondedAt: bodyData.respondedAt || new Date().toISOString(),
|
|
225
|
+
comment: bodyData.comment,
|
|
226
|
+
data: bodyData.data || {},
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
],
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
async execute() {
|
|
234
|
+
const items = this.getInputData();
|
|
235
|
+
// Check if we're resuming from a webhook (execution was waiting)
|
|
236
|
+
const waitingWebhookData = this.getInputData();
|
|
237
|
+
// If we have webhook response data (resuming), pass it through
|
|
238
|
+
// This happens when the webhook is called and the execution resumes
|
|
239
|
+
if (waitingWebhookData.length > 0 &&
|
|
240
|
+
waitingWebhookData[0].json.requestId &&
|
|
241
|
+
waitingWebhookData[0].json.response !== undefined) {
|
|
242
|
+
// We're resuming from webhook - return the webhook data as output
|
|
243
|
+
return [waitingWebhookData];
|
|
244
|
+
}
|
|
245
|
+
const operation = this.getNodeParameter('operation', 0);
|
|
246
|
+
if (operation === 'hitlRequest') {
|
|
247
|
+
// Process only the first item for the request
|
|
248
|
+
// (HITL requests typically handle one request at a time)
|
|
249
|
+
const itemIndex = 0;
|
|
250
|
+
try {
|
|
251
|
+
const credentials = await this.getCredentials('nebulaApi');
|
|
252
|
+
const baseUrl = credentials.baseUrl.replace(/\/$/, ''); // Remove trailing slash
|
|
253
|
+
// Parse metadata from credentials
|
|
254
|
+
let metadata = {};
|
|
255
|
+
try {
|
|
256
|
+
metadata = credentials.metadata ? JSON.parse(credentials.metadata) : {};
|
|
257
|
+
}
|
|
258
|
+
catch {
|
|
259
|
+
// Use empty object if parsing fails
|
|
260
|
+
}
|
|
261
|
+
// Get parameters
|
|
262
|
+
const title = this.getNodeParameter('title', itemIndex);
|
|
263
|
+
const message = this.getNodeParameter('message', itemIndex);
|
|
264
|
+
const responseType = this.getNodeParameter('responseType', itemIndex);
|
|
265
|
+
const additionalDataStr = this.getNodeParameter('additionalData', itemIndex, '{}');
|
|
266
|
+
const options = this.getNodeParameter('options', itemIndex, {});
|
|
267
|
+
// Get form JSON if response type is form
|
|
268
|
+
let form = {};
|
|
269
|
+
if (responseType === 'form') {
|
|
270
|
+
const formJsonStr = this.getNodeParameter('formJson', itemIndex, '{}');
|
|
271
|
+
try {
|
|
272
|
+
form = JSON.parse(formJsonStr);
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
// Use empty object if parsing fails
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
// Generate unique request ID
|
|
279
|
+
const requestId = (0, uuid_1.v4)();
|
|
280
|
+
// Construct the webhook URL using n8n's built-in instance base URL
|
|
281
|
+
// The webhook path is defined in the node description as 'nebula-hitl-response'
|
|
282
|
+
const n8nBaseUrl = this.getInstanceBaseUrl().replace(/\/$/, '');
|
|
283
|
+
const executionId = this.getExecutionId();
|
|
284
|
+
// n8n webhook URL format for waiting executions: {baseUrl}/webhook-waiting/{executionId}/nebula-hitl-response
|
|
285
|
+
const webhookUrl = `${n8nBaseUrl}/webhook-waiting/${executionId}/nebula-hitl-response`;
|
|
286
|
+
// Parse additional data
|
|
287
|
+
let parsedAdditionalData = {};
|
|
288
|
+
try {
|
|
289
|
+
parsedAdditionalData = JSON.parse(additionalDataStr);
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
// If parsing fails, use empty object
|
|
293
|
+
}
|
|
294
|
+
// Store incoming item data for reference
|
|
295
|
+
const inputItemData = items[itemIndex]?.json || {};
|
|
296
|
+
// Get workflow info
|
|
297
|
+
const workflow = this.getWorkflow();
|
|
298
|
+
// Build request payload
|
|
299
|
+
const payload = {
|
|
300
|
+
requestId,
|
|
301
|
+
title,
|
|
302
|
+
message,
|
|
303
|
+
responseType,
|
|
304
|
+
form: responseType === 'form' ? form : undefined,
|
|
305
|
+
webhookUrl, // The URL the backend should POST to when responding
|
|
306
|
+
priority: options.priority || 'normal',
|
|
307
|
+
timeoutMinutes: options.timeoutMinutes || 0,
|
|
308
|
+
assignee: options.assignee || undefined,
|
|
309
|
+
tags: options.tags ? options.tags.split(',').map((t) => t.trim()) : [],
|
|
310
|
+
metadata,
|
|
311
|
+
additionalData: parsedAdditionalData,
|
|
312
|
+
inputData: inputItemData,
|
|
313
|
+
workflowId: workflow.id,
|
|
314
|
+
workflowName: workflow.name,
|
|
315
|
+
executionId,
|
|
316
|
+
createdAt: new Date().toISOString(),
|
|
317
|
+
};
|
|
318
|
+
// Make HTTP POST request to create the HITL request
|
|
319
|
+
try {
|
|
320
|
+
await this.helpers.httpRequest({
|
|
321
|
+
method: 'POST',
|
|
322
|
+
url: `${baseUrl}/requests`,
|
|
323
|
+
body: payload,
|
|
324
|
+
json: true,
|
|
325
|
+
auth: {
|
|
326
|
+
username: credentials.username,
|
|
327
|
+
password: credentials.password,
|
|
328
|
+
},
|
|
329
|
+
headers: {
|
|
330
|
+
'Content-Type': 'application/json',
|
|
331
|
+
},
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
throw new n8n_workflow_1.NodeApiError(this.getNode(), { error: error.message }, {
|
|
336
|
+
message: 'Failed to create HITL request on the Nebula server',
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
// Calculate the wait timeout
|
|
340
|
+
const timeoutMinutes = options.timeoutMinutes || 0;
|
|
341
|
+
let waitTill;
|
|
342
|
+
if (timeoutMinutes > 0) {
|
|
343
|
+
// Wait until the specified timeout
|
|
344
|
+
waitTill = new Date(Date.now() + timeoutMinutes * 60 * 1000);
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
// Wait indefinitely (max date - n8n will handle this)
|
|
348
|
+
// Set to 1 year from now as "indefinite"
|
|
349
|
+
waitTill = new Date(Date.now() + 365 * 24 * 60 * 60 * 1000);
|
|
350
|
+
}
|
|
351
|
+
// Store request info in static data for potential reference
|
|
352
|
+
const staticData = this.getWorkflowStaticData('node');
|
|
353
|
+
staticData.currentRequest = {
|
|
354
|
+
requestId,
|
|
355
|
+
title,
|
|
356
|
+
webhookUrl,
|
|
357
|
+
createdAt: payload.createdAt,
|
|
358
|
+
waitTill: waitTill.toISOString(),
|
|
359
|
+
};
|
|
360
|
+
// PUT THE EXECUTION TO WAIT!
|
|
361
|
+
// This is the key - it pauses the workflow until the webhook is called
|
|
362
|
+
// or the timeout is reached
|
|
363
|
+
await this.putExecutionToWait(waitTill);
|
|
364
|
+
// This code is reached when the execution resumes (either from webhook or timeout)
|
|
365
|
+
// However, in practice, when webhook is called, n8n handles the resume differently
|
|
366
|
+
// Return empty - the webhook handler will provide the actual output
|
|
367
|
+
return [[]];
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
if (this.continueOnFail()) {
|
|
371
|
+
return [
|
|
372
|
+
[
|
|
373
|
+
{
|
|
374
|
+
json: {
|
|
375
|
+
error: error.message,
|
|
376
|
+
},
|
|
377
|
+
pairedItem: { item: itemIndex },
|
|
378
|
+
},
|
|
379
|
+
],
|
|
380
|
+
];
|
|
381
|
+
}
|
|
382
|
+
throw error;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
// Default return for unknown operations
|
|
386
|
+
return [[]];
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
exports.NebulaHitlRequest = NebulaHitlRequest;
|
|
390
|
+
//# sourceMappingURL=NebulaHitlRequest.node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NebulaHitlRequest.node.js","sourceRoot":"","sources":["../../../nodes/NebulaHitlRequest/NebulaHitlRequest.node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"node": "n8n-nodes-nebula.nebulaHitlRequest",
|
|
3
|
+
"nodeVersion": "1.0",
|
|
4
|
+
"codexVersion": "1.0",
|
|
5
|
+
"categories": ["Utility", "Core Nodes"],
|
|
6
|
+
"resources": {
|
|
7
|
+
"primaryDocumentation": [
|
|
8
|
+
{
|
|
9
|
+
"url": "https://github.com/linkorb/n8n-nodes-nebula"
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
"alias": [
|
|
14
|
+
"nebula",
|
|
15
|
+
"hitl",
|
|
16
|
+
"human",
|
|
17
|
+
"approval",
|
|
18
|
+
"wait",
|
|
19
|
+
"human in the loop",
|
|
20
|
+
"manual",
|
|
21
|
+
"confirm",
|
|
22
|
+
"review"
|
|
23
|
+
],
|
|
24
|
+
"subcategories": {
|
|
25
|
+
"Core Nodes": ["Flow"]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 60">
|
|
2
|
+
<rect width="60" height="60" rx="8" fill="#5C6BC0"/>
|
|
3
|
+
<circle cx="30" cy="18" r="7" fill="#fff"/>
|
|
4
|
+
<path d="M18 42c0-8.284 5.373-15 12-15s12 6.716 12 15v3H18v-3z" fill="#fff"/>
|
|
5
|
+
<circle cx="44" cy="18" r="8" fill="#FF7043"/>
|
|
6
|
+
<path d="M44 12v8M44 22v2" stroke="#fff" stroke-width="2.5" stroke-linecap="round"/>
|
|
7
|
+
</svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@linkorb/n8n-nodes-nebula",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "n8n nodes for Nebula - Human-in-the-Loop (HITL) requests with configurable REST API backend",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n-community-node-package",
|
|
7
|
+
"n8n",
|
|
8
|
+
"nebula",
|
|
9
|
+
"human-in-the-loop",
|
|
10
|
+
"hitl",
|
|
11
|
+
"approval",
|
|
12
|
+
"nebula-hitl"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"homepage": "https://github.com/linkorb/n8n-nodes-nebula",
|
|
16
|
+
"author": {
|
|
17
|
+
"name": "Joost Faassen"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/linkorb/n8n-nodes-nebula.git"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=18.10",
|
|
28
|
+
"pnpm": ">=9.1"
|
|
29
|
+
},
|
|
30
|
+
"packageManager": "pnpm@9.1.4",
|
|
31
|
+
"main": "dist/index.js",
|
|
32
|
+
"types": "dist/index.d.ts",
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsc && gulp build:icons",
|
|
35
|
+
"dev": "tsc --watch",
|
|
36
|
+
"format": "prettier nodes credentials --write",
|
|
37
|
+
"lint": "eslint nodes credentials package.json",
|
|
38
|
+
"lintfix": "eslint nodes credentials package.json --fix",
|
|
39
|
+
"prepublishOnly": "npm run build"
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"dist"
|
|
43
|
+
],
|
|
44
|
+
"n8n": {
|
|
45
|
+
"n8nNodesApiVersion": 1,
|
|
46
|
+
"credentials": [
|
|
47
|
+
"dist/credentials/NebulaApi.credentials.js"
|
|
48
|
+
],
|
|
49
|
+
"nodes": [
|
|
50
|
+
"dist/nodes/NebulaHitlRequest/NebulaHitlRequest.node.js"
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@types/node": "^22.10.1",
|
|
55
|
+
"@types/uuid": "^10.0.0",
|
|
56
|
+
"@typescript-eslint/parser": "^8.18.0",
|
|
57
|
+
"eslint": "^9.16.0",
|
|
58
|
+
"gulp": "^5.0.0",
|
|
59
|
+
"n8n-workflow": "^1.70.0",
|
|
60
|
+
"prettier": "^3.4.2",
|
|
61
|
+
"typescript": "^5.7.2"
|
|
62
|
+
},
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"uuid": "^11.0.3"
|
|
65
|
+
},
|
|
66
|
+
"peerDependencies": {
|
|
67
|
+
"n8n-workflow": "*"
|
|
68
|
+
}
|
|
69
|
+
}
|