n8n-nodes-sudomock 0.4.0 → 0.5.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 +56 -12
- package/dist/nodes/SudoMock/SudoMock.node.js +494 -70
- package/dist/nodes/SudoMock/SudoMockTrigger.node.d.ts +12 -0
- package/dist/nodes/SudoMock/SudoMockTrigger.node.js +118 -0
- package/dist/nodes/SudoMock/webhooks.d.ts +5 -0
- package/dist/nodes/SudoMock/webhooks.js +38 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -7,9 +7,11 @@ n8n community node for the SudoMock API. Integrate mockup rendering into your n8
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
9
|
### Account Operations
|
|
10
|
+
|
|
10
11
|
- **Get Account Info**: Retrieve account details, subscription plan, and usage statistics
|
|
11
12
|
|
|
12
13
|
### Mockup Management
|
|
14
|
+
|
|
13
15
|
- **Upload PSD**: Upload PSD templates from a URL
|
|
14
16
|
- **List Mockups**: List all your uploaded mockup templates with filtering and pagination
|
|
15
17
|
- **Get Mockup**: Get detailed information about a specific mockup template
|
|
@@ -17,6 +19,7 @@ n8n community node for the SudoMock API. Integrate mockup rendering into your n8
|
|
|
17
19
|
- **Delete Mockup**: Delete a specific mockup template
|
|
18
20
|
|
|
19
21
|
### 2D Mockups
|
|
22
|
+
|
|
20
23
|
- **2D: Create Mockup**: Create a reusable 2D mockup from an image
|
|
21
24
|
- **2D: Get Mockup**: Check preparation status and get ready print areas
|
|
22
25
|
- **2D: List Mockups**: List your 2D mockups
|
|
@@ -25,18 +28,27 @@ n8n community node for the SudoMock API. Integrate mockup rendering into your n8
|
|
|
25
28
|
- **2D: Delete Mockup**: Delete a 2D mockup
|
|
26
29
|
|
|
27
30
|
### Rendering
|
|
28
|
-
|
|
29
|
-
- **Render
|
|
31
|
+
|
|
32
|
+
- **Render Mockup**: Generate mockups with artwork, personalized text, or both. Text overrides support styled segments, fonts, size, color, stroke color, and overflow, shrink, or clip fitting. Optionally run asynchronously with the **Run Asynchronously** toggle, which returns a `job_id` to track with **Get Job**.
|
|
33
|
+
- **Render Video**: Turn a mockup (or an existing image URL) into a short product video (always asynchronous). Choose a supported duration, optional audio/motion, an optional one-off webhook, and optionally **Wait for Completion** to return the finished clip.
|
|
34
|
+
|
|
35
|
+
### Fonts and Order Artwork
|
|
36
|
+
|
|
37
|
+
- **Fonts**: List available fonts, fetch one by UUID, upload a custom TTF or OTF from a public URL, and delete your custom fonts
|
|
38
|
+
- **Order Artwork**: Store customer artwork and previews for fulfillment, then delete them by URL or mockup UUID when needed
|
|
30
39
|
|
|
31
40
|
### Async Jobs
|
|
41
|
+
|
|
32
42
|
- **Get Job**: Get the status and result of an async render, upload, video, or 2D mockup job by its `job_id`. Terminal statuses are `succeeded`, `failed`, and `cancelled` (pending jobs report `queued`). On success it surfaces `result_url` (render/video) or `mockup_uuid` (upload and 2D creation). Optionally **Wait for Completion** to poll until the job finishes.
|
|
33
|
-
- **List Jobs**: List your async render, upload, and
|
|
43
|
+
- **List Jobs**: List your async render, upload, video, and 2D jobs (keyset paginated, with optional `kind` and Mockup UUID filters).
|
|
34
44
|
|
|
35
45
|
### Webhooks
|
|
36
|
-
|
|
46
|
+
|
|
47
|
+
- **SudoMock Trigger**: Start a workflow from selected SudoMock events with automatic signature verification
|
|
48
|
+
- Manage webhook endpoints that receive a signed HTTPS request the moment a job finishes:
|
|
37
49
|
- **Webhook: List Endpoints**
|
|
38
50
|
- **Webhook: Get Endpoint**
|
|
39
|
-
- **Webhook: Create Endpoint** (set an optional description and choose any
|
|
51
|
+
- **Webhook: Create Endpoint** (set an optional description and choose any current event, or leave empty for all)
|
|
40
52
|
- **Webhook: Update Endpoint**
|
|
41
53
|
- **Webhook: Delete Endpoint**
|
|
42
54
|
- **Webhook: Rotate Secret**
|
|
@@ -46,7 +58,7 @@ Manage webhook endpoints that receive a signed HTTPS request the moment a job fi
|
|
|
46
58
|
- **Webhook: Replay Failed Deliveries**
|
|
47
59
|
- **Webhook: Events Feed** (recent deliveries across all of your endpoints)
|
|
48
60
|
|
|
49
|
-
Canonical events: `render.succeeded`, `render.failed`, `upload.succeeded`, `video.succeeded`, `video.failed`, `webhook.test`. Deliveries are
|
|
61
|
+
Canonical events: `render.succeeded`, `render.failed`, `upload.succeeded`, `video.succeeded`, `video.failed`, `2d_mockup.ready`, `2d_mockup.rejected`, `2d_mockup.failed`, `2d_render.succeeded`, `2d_render.failed`, `webhook.test`. Deliveries are signed; see https://sudomock.com/docs/api/webhooks for verification details.
|
|
50
62
|
|
|
51
63
|
## Installation
|
|
52
64
|
|
|
@@ -89,12 +101,14 @@ Restart n8n after installation.
|
|
|
89
101
|
Retrieve your account information, subscription details, and credit usage.
|
|
90
102
|
|
|
91
103
|
**Output:**
|
|
104
|
+
|
|
92
105
|
- Account: UUID, email, name, created date
|
|
93
106
|
- Subscription: Plan name, status, billing period
|
|
94
107
|
- Usage: Credits used/remaining, billing dates
|
|
95
108
|
- API Key: Name, creation date, last used, total requests
|
|
96
109
|
|
|
97
110
|
**Example Output:**
|
|
111
|
+
|
|
98
112
|
```json
|
|
99
113
|
{
|
|
100
114
|
"success": true,
|
|
@@ -124,16 +138,19 @@ Retrieve your account information, subscription details, and credit usage.
|
|
|
124
138
|
Upload a PSD template from a public URL.
|
|
125
139
|
|
|
126
140
|
**Parameters:**
|
|
141
|
+
|
|
127
142
|
- **PSD File URL** (required): Public URL to your PSD file (up to Adobe's official PSD file size limit)
|
|
128
143
|
- **Template Name** (optional): Custom name for the template (auto-generated if not provided)
|
|
129
144
|
|
|
130
145
|
**Example:**
|
|
146
|
+
|
|
131
147
|
```
|
|
132
148
|
PSD URL: https://storage.example.com/mockup.psd
|
|
133
149
|
Name: T-Shirt Mockup Front
|
|
134
150
|
```
|
|
135
151
|
|
|
136
152
|
**Output:**
|
|
153
|
+
|
|
137
154
|
- Mockup UUID (use for rendering)
|
|
138
155
|
- Smart object UUIDs and details
|
|
139
156
|
- Thumbnail URLs
|
|
@@ -145,6 +162,7 @@ Name: T-Shirt Mockup Front
|
|
|
145
162
|
List all your uploaded mockup templates with optional filtering and pagination.
|
|
146
163
|
|
|
147
164
|
**Parameters:**
|
|
165
|
+
|
|
148
166
|
- **Return All**: Fetch all mockups or limit results
|
|
149
167
|
- **Limit**: Number of results (1-100, default: 20)
|
|
150
168
|
- **Additional Options**:
|
|
@@ -155,6 +173,7 @@ List all your uploaded mockup templates with optional filtering and pagination.
|
|
|
155
173
|
- Sort Order: `asc` or `desc`
|
|
156
174
|
|
|
157
175
|
**Example:**
|
|
176
|
+
|
|
158
177
|
```
|
|
159
178
|
Limit: 20
|
|
160
179
|
Sort By: Created At
|
|
@@ -171,9 +190,11 @@ Each mockup as a separate item with full details (UUID, name, smart objects, thu
|
|
|
171
190
|
Retrieve detailed information about a specific mockup template.
|
|
172
191
|
|
|
173
192
|
**Parameters:**
|
|
193
|
+
|
|
174
194
|
- **Mockup UUID** (required): UUID of the mockup to retrieve
|
|
175
195
|
|
|
176
196
|
**Example:**
|
|
197
|
+
|
|
177
198
|
```
|
|
178
199
|
Mockup UUID: c315f78f-d2c7-4541-b240-a9372842de94
|
|
179
200
|
```
|
|
@@ -188,10 +209,12 @@ Complete mockup details including all smart objects, thumbnails, and metadata.
|
|
|
188
209
|
Update the name of a mockup template.
|
|
189
210
|
|
|
190
211
|
**Parameters:**
|
|
212
|
+
|
|
191
213
|
- **Mockup UUID** (required): UUID of the mockup to update
|
|
192
214
|
- **New Name** (required): New name for the template
|
|
193
215
|
|
|
194
216
|
**Example:**
|
|
217
|
+
|
|
195
218
|
```
|
|
196
219
|
Mockup UUID: c315f78f-d2c7-4541-b240-a9372842de94
|
|
197
220
|
New Name: Updated T-Shirt Mockup
|
|
@@ -207,6 +230,7 @@ Updated mockup details with the new name.
|
|
|
207
230
|
Generate a mockup by filling smart objects with your designs.
|
|
208
231
|
|
|
209
232
|
**Parameters:**
|
|
233
|
+
|
|
210
234
|
- **Mockup UUID** (required): UUID from Upload PSD response
|
|
211
235
|
- **Smart Objects** (required): One or more smart objects to fill
|
|
212
236
|
- Smart Object UUID
|
|
@@ -227,6 +251,7 @@ Generate a mockup by filling smart objects with your designs.
|
|
|
227
251
|
- Export Label: Custom label for file naming
|
|
228
252
|
|
|
229
253
|
**Example:**
|
|
254
|
+
|
|
230
255
|
```
|
|
231
256
|
Mockup UUID: abc123-def456
|
|
232
257
|
Smart Object 1:
|
|
@@ -243,6 +268,7 @@ Export Options:
|
|
|
243
268
|
```
|
|
244
269
|
|
|
245
270
|
**Output:**
|
|
271
|
+
|
|
246
272
|
```json
|
|
247
273
|
{
|
|
248
274
|
"success": true,
|
|
@@ -263,9 +289,11 @@ Export Options:
|
|
|
263
289
|
Delete a specific mockup template.
|
|
264
290
|
|
|
265
291
|
**Parameters:**
|
|
292
|
+
|
|
266
293
|
- **Mockup UUID** (required): UUID of the mockup to delete
|
|
267
294
|
|
|
268
295
|
**Example:**
|
|
296
|
+
|
|
269
297
|
```
|
|
270
298
|
Mockup UUID: c315f78f-d2c7-4541-b240-a9372842de94
|
|
271
299
|
```
|
|
@@ -295,6 +323,7 @@ Create must reach `ready` through **2D: Get Mockup** before **2D: Render Mockup*
|
|
|
295
323
|
Turn a mockup (or an existing image URL) into a short product video. Always asynchronous: returns a `job_id` you can track with **Get Job**.
|
|
296
324
|
|
|
297
325
|
**Parameters:**
|
|
326
|
+
|
|
298
327
|
- **Input Mode**: `Render Mockup` (render a mockup with your designs first) or `Animate Image URL` (animate a public image directly)
|
|
299
328
|
- **Mockup UUID** (required in Render Mockup mode): UUID of the mockup to animate
|
|
300
329
|
- **Smart Objects** (required in Render Mockup mode): one or more smart objects with a Design URL and Fit Mode
|
|
@@ -318,6 +347,7 @@ The 202 acknowledgement (`job_id`, `kind`, `status`, `status_url`, `estimated_cr
|
|
|
318
347
|
Track an asynchronous render, upload, video, or 2D mockup job by its `job_id`.
|
|
319
348
|
|
|
320
349
|
**Parameters:**
|
|
350
|
+
|
|
321
351
|
- **Job ID** (required): the `job_id` from an async render, upload, video, or 2D mockup request
|
|
322
352
|
- **Wait for Completion**: poll until a terminal status (`succeeded`, `failed`, `cancelled`)
|
|
323
353
|
- **Poll Timeout (Seconds)**: max wait when Wait for Completion is on
|
|
@@ -332,6 +362,7 @@ The job object. On success it surfaces `result_url` / `resultUrl` (render/video)
|
|
|
332
362
|
List your async render, upload, and video jobs (newest first, keyset paginated).
|
|
333
363
|
|
|
334
364
|
**Parameters (all optional, under Filters):**
|
|
365
|
+
|
|
335
366
|
- **Kind**: `render`, `upload`, or `video`
|
|
336
367
|
- **Mockup UUID**: only jobs derived from this source mockup
|
|
337
368
|
- **Limit**: 1-50 (default 20)
|
|
@@ -349,6 +380,7 @@ List your async render, upload, and video jobs (newest first, keyset paginated).
|
|
|
349
380
|
Manage webhook endpoints and their deliveries. See the [Webhooks](#webhooks) feature list above for the full operation set and the canonical event types.
|
|
350
381
|
|
|
351
382
|
**Common parameters:**
|
|
383
|
+
|
|
352
384
|
- **Webhook Endpoint ID** (required for get/update/delete/rotate/test/deliveries/replay/replay-failed)
|
|
353
385
|
- **Endpoint URL** + **Description** (create) and **Events** (create/update): leave Events empty to subscribe to all
|
|
354
386
|
- **Delivery ID** (replay)
|
|
@@ -361,9 +393,11 @@ Manage webhook endpoints and their deliveries. See the [Webhooks](#webhooks) fea
|
|
|
361
393
|
Ready-to-use n8n workflows are available in the [`examples/`](./examples) folder:
|
|
362
394
|
|
|
363
395
|
### 1. Complete API Test Workflow
|
|
396
|
+
|
|
364
397
|
**File**: [`examples/complete-test-workflow.json`](./examples/complete-test-workflow.json)
|
|
365
398
|
|
|
366
399
|
Tests the core mockup operations in sequence:
|
|
400
|
+
|
|
367
401
|
- Get Account Info → Upload PSD → Get Mockup → List Mockups
|
|
368
402
|
- Render Mockup → Update Name → Verify Update → Delete Mockup
|
|
369
403
|
|
|
@@ -372,9 +406,11 @@ Perfect for verifying your setup and understanding the complete workflow.
|
|
|
372
406
|
[View Details →](./examples/README.md#1-complete-api-test-complete-test-workflowjson)
|
|
373
407
|
|
|
374
408
|
### 2. Rate Limit Handling Workflow
|
|
409
|
+
|
|
375
410
|
**File**: [`examples/rate-limit-test-workflow.json`](./examples/rate-limit-test-workflow.json)
|
|
376
411
|
|
|
377
412
|
Demonstrates proper rate limit error handling with automatic retry logic:
|
|
413
|
+
|
|
378
414
|
- Detects 429 errors
|
|
379
415
|
- Extracts retry-after value
|
|
380
416
|
- Waits and automatically retries
|
|
@@ -383,9 +419,11 @@ Demonstrates proper rate limit error handling with automatic retry logic:
|
|
|
383
419
|
[View Details →](./examples/README.md#2-rate-limit-error-handling-test-rate-limit-test-workflowjson)
|
|
384
420
|
|
|
385
421
|
### 3. Sequential Batch Render Workflow
|
|
422
|
+
|
|
386
423
|
**File**: [`examples/batch-render-workflow.json`](./examples/batch-render-workflow.json)
|
|
387
424
|
|
|
388
425
|
Demonstrates the power of n8n workflows with sequential batch processing:
|
|
426
|
+
|
|
389
427
|
- Renders 10 mockups one after another
|
|
390
428
|
- Uses different designs for each render
|
|
391
429
|
- 2-second delay between renders to avoid rate limits
|
|
@@ -398,11 +436,13 @@ Perfect for understanding batch processing and workflow automation.
|
|
|
398
436
|
### Quick Start with Examples
|
|
399
437
|
|
|
400
438
|
1. Import a workflow:
|
|
439
|
+
|
|
401
440
|
```
|
|
402
441
|
n8n UI → Workflows → Import from File → Select workflow JSON
|
|
403
442
|
```
|
|
404
443
|
|
|
405
444
|
2. Configure credentials:
|
|
445
|
+
|
|
406
446
|
```
|
|
407
447
|
Click any SudoMock node → Credentials → Select your API key
|
|
408
448
|
```
|
|
@@ -481,12 +521,12 @@ Unauthenticated requests (IP-based): **30 requests per minute**
|
|
|
481
521
|
|
|
482
522
|
### Concurrent Request Limits (Plan-Based)
|
|
483
523
|
|
|
484
|
-
| Plan
|
|
485
|
-
|
|
486
|
-
| Free
|
|
487
|
-
| Starter | 3
|
|
488
|
-
| Pro
|
|
489
|
-
| Scale
|
|
524
|
+
| Plan | Concurrent Renders | Concurrent Uploads |
|
|
525
|
+
| ------- | ------------------ | ------------------ |
|
|
526
|
+
| Free | 1 | 1 |
|
|
527
|
+
| Starter | 3 | 2 |
|
|
528
|
+
| Pro | 10 | 5 |
|
|
529
|
+
| Scale | 25 | 10 |
|
|
490
530
|
|
|
491
531
|
### Rate Limit Error Handling
|
|
492
532
|
|
|
@@ -495,6 +535,7 @@ The node automatically detects and handles two types of rate limit errors:
|
|
|
495
535
|
#### 1. Request Rate Limit Exceeded (1000 RPM)
|
|
496
536
|
|
|
497
537
|
**Error Output:**
|
|
538
|
+
|
|
498
539
|
```json
|
|
499
540
|
{
|
|
500
541
|
"error": "Rate limit exceeded (1000 requests/minute). Please retry after 42 seconds.",
|
|
@@ -513,6 +554,7 @@ The node automatically detects and handles two types of rate limit errors:
|
|
|
513
554
|
#### 2. Concurrent Limit Exceeded (Plan-Based)
|
|
514
555
|
|
|
515
556
|
**Error Output:**
|
|
557
|
+
|
|
516
558
|
```json
|
|
517
559
|
{
|
|
518
560
|
"error": "Concurrent render limit reached (11/10). Please wait 5 seconds and try again.",
|
|
@@ -549,11 +591,13 @@ The node automatically detects and handles two types of rate limit errors:
|
|
|
549
591
|
## Error Handling
|
|
550
592
|
|
|
551
593
|
All operations support the **Continue On Fail** option in n8n. When enabled:
|
|
594
|
+
|
|
552
595
|
- Errors are captured as output items
|
|
553
596
|
- Workflow continues to next item
|
|
554
597
|
- Error details included in output
|
|
555
598
|
|
|
556
599
|
**Example Error Output:**
|
|
600
|
+
|
|
557
601
|
```json
|
|
558
602
|
{
|
|
559
603
|
"error": "Rate limit exceeded. Retry after 42 seconds.",
|
|
@@ -2,7 +2,24 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SudoMock = void 0;
|
|
4
4
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const webhooks_1 = require("./webhooks");
|
|
5
6
|
const TERMINAL_JOB_STATUSES = ['succeeded', 'failed', 'cancelled'];
|
|
7
|
+
function format2DPrintAreas(printAreas) {
|
|
8
|
+
return printAreas.map((area) => ({
|
|
9
|
+
points: [
|
|
10
|
+
[area.point1X, area.point1Y],
|
|
11
|
+
[area.point2X, area.point2Y],
|
|
12
|
+
[area.point3X, area.point3Y],
|
|
13
|
+
[area.point4X, area.point4Y],
|
|
14
|
+
],
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
function parseJsonArray(value, name) {
|
|
18
|
+
const parsed = typeof value === 'string' ? JSON.parse(value) : value;
|
|
19
|
+
if (!Array.isArray(parsed))
|
|
20
|
+
throw new Error(`${name} must be a JSON array`);
|
|
21
|
+
return parsed;
|
|
22
|
+
}
|
|
6
23
|
/**
|
|
7
24
|
* Poll GET /api/v1/jobs/{job_id} until the job reaches a terminal status
|
|
8
25
|
* (succeeded, failed, cancelled) or the timeout elapses. Uses a capped backoff.
|
|
@@ -61,7 +78,7 @@ class SudoMock {
|
|
|
61
78
|
{
|
|
62
79
|
name: '2D: Create Mockup',
|
|
63
80
|
value: 'create2DMockup',
|
|
64
|
-
description: 'Create a 2D mockup
|
|
81
|
+
description: 'Create a 2D mockup now or queue it for background processing',
|
|
65
82
|
action: 'Create a 2D mockup',
|
|
66
83
|
},
|
|
67
84
|
{
|
|
@@ -94,12 +111,48 @@ class SudoMock {
|
|
|
94
111
|
description: 'Delete a 2D mockup',
|
|
95
112
|
action: 'Delete a 2D mockup',
|
|
96
113
|
},
|
|
114
|
+
{
|
|
115
|
+
name: 'Artwork: Delete Stored Files',
|
|
116
|
+
value: 'deleteArtworks',
|
|
117
|
+
description: 'Delete stored order artwork by URL or mockup UUID',
|
|
118
|
+
action: 'Delete stored artwork',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: 'Artwork: Store Files',
|
|
122
|
+
value: 'storeArtworks',
|
|
123
|
+
description: 'Store customer artwork and an optional preview for order fulfillment',
|
|
124
|
+
action: 'Store artwork',
|
|
125
|
+
},
|
|
97
126
|
{
|
|
98
127
|
name: 'Delete Mockup',
|
|
99
128
|
value: 'deleteMockup',
|
|
100
129
|
description: 'Delete a specific mockup template',
|
|
101
130
|
action: 'Delete a mockup',
|
|
102
131
|
},
|
|
132
|
+
{
|
|
133
|
+
name: 'Font: Delete Custom Font',
|
|
134
|
+
value: 'deleteFont',
|
|
135
|
+
description: 'Delete one of your uploaded fonts',
|
|
136
|
+
action: 'Delete a custom font',
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: 'Font: Get Font',
|
|
140
|
+
value: 'getFont',
|
|
141
|
+
description: 'Get one available font by UUID',
|
|
142
|
+
action: 'Get a font',
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
name: 'Font: List Fonts',
|
|
146
|
+
value: 'listFonts',
|
|
147
|
+
description: 'List system fonts and your uploaded fonts',
|
|
148
|
+
action: 'List fonts',
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
name: 'Font: Upload From URL',
|
|
152
|
+
value: 'uploadFont',
|
|
153
|
+
description: 'Upload a custom TTF or OTF font from a public URL',
|
|
154
|
+
action: 'Upload a custom font',
|
|
155
|
+
},
|
|
103
156
|
{
|
|
104
157
|
name: 'Get Account Info',
|
|
105
158
|
value: 'getAccountInfo',
|
|
@@ -292,6 +345,14 @@ class SudoMock {
|
|
|
292
345
|
placeholder: 'T-Shirt Front',
|
|
293
346
|
description: 'Optional human-readable name for the new 2D mockup',
|
|
294
347
|
},
|
|
348
|
+
{
|
|
349
|
+
displayName: 'Run Asynchronously',
|
|
350
|
+
name: 'twoDCreateIsAsync',
|
|
351
|
+
type: 'boolean',
|
|
352
|
+
displayOptions: { show: { operation: ['create2DMockup'] } },
|
|
353
|
+
default: false,
|
|
354
|
+
description: 'Whether to queue creation and return a job_id (kind: 2d_create) immediately',
|
|
355
|
+
},
|
|
295
356
|
{
|
|
296
357
|
displayName: 'Mockup UUID',
|
|
297
358
|
name: 'twoDMockupUuid',
|
|
@@ -299,12 +360,7 @@ class SudoMock {
|
|
|
299
360
|
required: true,
|
|
300
361
|
displayOptions: {
|
|
301
362
|
show: {
|
|
302
|
-
operation: [
|
|
303
|
-
'get2DMockup',
|
|
304
|
-
'set2DPrintAreas',
|
|
305
|
-
'render2DMockup',
|
|
306
|
-
'delete2DMockup',
|
|
307
|
-
],
|
|
363
|
+
operation: ['get2DMockup', 'set2DPrintAreas', 'render2DMockup', 'delete2DMockup'],
|
|
308
364
|
},
|
|
309
365
|
},
|
|
310
366
|
default: '',
|
|
@@ -318,15 +374,14 @@ class SudoMock {
|
|
|
318
374
|
typeOptions: {
|
|
319
375
|
multipleValues: true,
|
|
320
376
|
},
|
|
321
|
-
required: true,
|
|
322
377
|
displayOptions: {
|
|
323
378
|
show: {
|
|
324
|
-
operation: ['set2DPrintAreas'],
|
|
379
|
+
operation: ['create2DMockup', 'set2DPrintAreas'],
|
|
325
380
|
},
|
|
326
381
|
},
|
|
327
382
|
default: {},
|
|
328
383
|
placeholder: 'Add Print Area',
|
|
329
|
-
description:
|
|
384
|
+
description: "Optional during creation; required when replacing a mockup's print areas",
|
|
330
385
|
options: [
|
|
331
386
|
{
|
|
332
387
|
name: 'items',
|
|
@@ -710,6 +765,14 @@ class SudoMock {
|
|
|
710
765
|
},
|
|
711
766
|
],
|
|
712
767
|
},
|
|
768
|
+
{
|
|
769
|
+
displayName: 'Run Asynchronously',
|
|
770
|
+
name: 'twoDRenderIsAsync',
|
|
771
|
+
type: 'boolean',
|
|
772
|
+
displayOptions: { show: { operation: ['render2DMockup'] } },
|
|
773
|
+
default: false,
|
|
774
|
+
description: 'Whether to queue the render and return a job_id (kind: 2d_render) immediately',
|
|
775
|
+
},
|
|
713
776
|
// ============================================
|
|
714
777
|
// UPLOAD PSD PARAMETERS
|
|
715
778
|
// ============================================
|
|
@@ -1001,6 +1064,14 @@ class SudoMock {
|
|
|
1001
1064
|
},
|
|
1002
1065
|
],
|
|
1003
1066
|
},
|
|
1067
|
+
{
|
|
1068
|
+
displayName: 'Text Layers',
|
|
1069
|
+
name: 'textLayers',
|
|
1070
|
+
type: 'json',
|
|
1071
|
+
displayOptions: { show: { operation: ['render'] } },
|
|
1072
|
+
default: '[]',
|
|
1073
|
+
description: 'Optional text layer override array. Each item needs uuid plus text or segments, and can include font, font_size, color, stroke_color, and fit (overflow, shrink, or clip).',
|
|
1074
|
+
},
|
|
1004
1075
|
{
|
|
1005
1076
|
displayName: 'Export Options',
|
|
1006
1077
|
name: 'exportOptions',
|
|
@@ -1190,9 +1261,21 @@ class SudoMock {
|
|
|
1190
1261
|
name: 'fit',
|
|
1191
1262
|
type: 'options',
|
|
1192
1263
|
options: [
|
|
1193
|
-
{
|
|
1194
|
-
|
|
1195
|
-
|
|
1264
|
+
{
|
|
1265
|
+
name: 'Fill',
|
|
1266
|
+
value: 'fill',
|
|
1267
|
+
description: 'Stretch to fill entire area',
|
|
1268
|
+
},
|
|
1269
|
+
{
|
|
1270
|
+
name: 'Contain',
|
|
1271
|
+
value: 'contain',
|
|
1272
|
+
description: 'Fit inside, may leave space',
|
|
1273
|
+
},
|
|
1274
|
+
{
|
|
1275
|
+
name: 'Cover',
|
|
1276
|
+
value: 'cover',
|
|
1277
|
+
description: 'Fill area, may crop edges (recommended)',
|
|
1278
|
+
},
|
|
1196
1279
|
],
|
|
1197
1280
|
default: 'cover',
|
|
1198
1281
|
description: 'How to fit the design in the smart object bounds',
|
|
@@ -1249,7 +1332,11 @@ class SudoMock {
|
|
|
1249
1332
|
name: 'motion',
|
|
1250
1333
|
type: 'options',
|
|
1251
1334
|
options: [
|
|
1252
|
-
{
|
|
1335
|
+
{
|
|
1336
|
+
name: 'Ambient',
|
|
1337
|
+
value: 'ambient',
|
|
1338
|
+
description: 'Subtle ambient motion (default)',
|
|
1339
|
+
},
|
|
1253
1340
|
{
|
|
1254
1341
|
name: 'Showcase',
|
|
1255
1342
|
value: 'showcase',
|
|
@@ -1365,6 +1452,8 @@ class SudoMock {
|
|
|
1365
1452
|
{ name: 'Render', value: 'render' },
|
|
1366
1453
|
{ name: 'Upload', value: 'upload' },
|
|
1367
1454
|
{ name: 'Video', value: 'video' },
|
|
1455
|
+
{ name: '2D Create', value: '2d_create' },
|
|
1456
|
+
{ name: '2D Render', value: '2d_render' },
|
|
1368
1457
|
],
|
|
1369
1458
|
default: 'render',
|
|
1370
1459
|
description: 'Only return jobs of this kind',
|
|
@@ -1397,6 +1486,173 @@ class SudoMock {
|
|
|
1397
1486
|
],
|
|
1398
1487
|
},
|
|
1399
1488
|
// ============================================
|
|
1489
|
+
// FONT PARAMETERS
|
|
1490
|
+
// ============================================
|
|
1491
|
+
{
|
|
1492
|
+
displayName: 'Font UUID',
|
|
1493
|
+
name: 'fontUuid',
|
|
1494
|
+
type: 'string',
|
|
1495
|
+
required: true,
|
|
1496
|
+
displayOptions: { show: { operation: ['getFont', 'deleteFont'] } },
|
|
1497
|
+
default: '',
|
|
1498
|
+
description: 'Font UUID from Font: List Fonts',
|
|
1499
|
+
},
|
|
1500
|
+
{
|
|
1501
|
+
displayName: 'Font URL',
|
|
1502
|
+
name: 'fontUrl',
|
|
1503
|
+
type: 'string',
|
|
1504
|
+
required: true,
|
|
1505
|
+
displayOptions: { show: { operation: ['uploadFont'] } },
|
|
1506
|
+
default: '',
|
|
1507
|
+
placeholder: 'https://example.com/fonts/Brand-Bold.ttf',
|
|
1508
|
+
description: 'Public URL of a TTF or OTF font file',
|
|
1509
|
+
},
|
|
1510
|
+
{
|
|
1511
|
+
displayName: 'License Confirmed',
|
|
1512
|
+
name: 'fontLicenseConfirmed',
|
|
1513
|
+
type: 'boolean',
|
|
1514
|
+
displayOptions: { show: { operation: ['uploadFont'] } },
|
|
1515
|
+
default: false,
|
|
1516
|
+
description: 'Whether you confirm you have the right to use and embed this font',
|
|
1517
|
+
},
|
|
1518
|
+
{
|
|
1519
|
+
displayName: 'Filters',
|
|
1520
|
+
name: 'fontFilters',
|
|
1521
|
+
type: 'collection',
|
|
1522
|
+
placeholder: 'Add Filter',
|
|
1523
|
+
displayOptions: { show: { operation: ['listFonts'] } },
|
|
1524
|
+
default: {},
|
|
1525
|
+
options: [
|
|
1526
|
+
{
|
|
1527
|
+
displayName: 'Page',
|
|
1528
|
+
name: 'page',
|
|
1529
|
+
type: 'number',
|
|
1530
|
+
typeOptions: { minValue: 1 },
|
|
1531
|
+
default: 1,
|
|
1532
|
+
},
|
|
1533
|
+
{
|
|
1534
|
+
displayName: 'Results Per Page',
|
|
1535
|
+
name: 'perPage',
|
|
1536
|
+
type: 'number',
|
|
1537
|
+
typeOptions: { minValue: 1, maxValue: 100 },
|
|
1538
|
+
default: 50,
|
|
1539
|
+
},
|
|
1540
|
+
{
|
|
1541
|
+
displayName: 'Category',
|
|
1542
|
+
name: 'category',
|
|
1543
|
+
type: 'string',
|
|
1544
|
+
default: '',
|
|
1545
|
+
},
|
|
1546
|
+
{
|
|
1547
|
+
displayName: 'Search',
|
|
1548
|
+
name: 'search',
|
|
1549
|
+
type: 'string',
|
|
1550
|
+
default: '',
|
|
1551
|
+
description: 'Filter by font family name',
|
|
1552
|
+
},
|
|
1553
|
+
{
|
|
1554
|
+
displayName: 'Scope',
|
|
1555
|
+
name: 'scope',
|
|
1556
|
+
type: 'options',
|
|
1557
|
+
options: [
|
|
1558
|
+
{ name: 'All', value: 'all' },
|
|
1559
|
+
{ name: 'System', value: 'system' },
|
|
1560
|
+
{ name: 'Custom', value: 'custom' },
|
|
1561
|
+
],
|
|
1562
|
+
default: 'all',
|
|
1563
|
+
},
|
|
1564
|
+
],
|
|
1565
|
+
},
|
|
1566
|
+
// ============================================
|
|
1567
|
+
// ARTWORK PARAMETERS
|
|
1568
|
+
// ============================================
|
|
1569
|
+
{
|
|
1570
|
+
displayName: 'Mockup UUID',
|
|
1571
|
+
name: 'artworkMockupUuid',
|
|
1572
|
+
type: 'string',
|
|
1573
|
+
required: true,
|
|
1574
|
+
displayOptions: { show: { operation: ['storeArtworks'] } },
|
|
1575
|
+
default: '',
|
|
1576
|
+
description: 'Mockup UUID the stored artwork belongs to',
|
|
1577
|
+
},
|
|
1578
|
+
{
|
|
1579
|
+
displayName: 'Artwork Items',
|
|
1580
|
+
name: 'artworkItems',
|
|
1581
|
+
type: 'fixedCollection',
|
|
1582
|
+
typeOptions: { multipleValues: true },
|
|
1583
|
+
displayOptions: { show: { operation: ['storeArtworks'] } },
|
|
1584
|
+
default: {},
|
|
1585
|
+
placeholder: 'Add Artwork',
|
|
1586
|
+
description: 'Up to 10 artwork files to keep for order fulfillment',
|
|
1587
|
+
options: [
|
|
1588
|
+
{
|
|
1589
|
+
name: 'items',
|
|
1590
|
+
displayName: 'Artwork',
|
|
1591
|
+
values: [
|
|
1592
|
+
{
|
|
1593
|
+
displayName: 'Smart Object UUID',
|
|
1594
|
+
name: 'smartObjectUuid',
|
|
1595
|
+
type: 'string',
|
|
1596
|
+
required: true,
|
|
1597
|
+
default: '',
|
|
1598
|
+
},
|
|
1599
|
+
{
|
|
1600
|
+
displayName: 'Base64 Artwork',
|
|
1601
|
+
name: 'base64',
|
|
1602
|
+
type: 'string',
|
|
1603
|
+
required: true,
|
|
1604
|
+
default: '',
|
|
1605
|
+
description: 'Raw base64 image bytes without a data URL prefix',
|
|
1606
|
+
},
|
|
1607
|
+
],
|
|
1608
|
+
},
|
|
1609
|
+
],
|
|
1610
|
+
},
|
|
1611
|
+
{
|
|
1612
|
+
displayName: 'Preview URL',
|
|
1613
|
+
name: 'artworkPreviewUrl',
|
|
1614
|
+
type: 'string',
|
|
1615
|
+
displayOptions: { show: { operation: ['storeArtworks'] } },
|
|
1616
|
+
default: '',
|
|
1617
|
+
description: 'Optional render URL to keep with the order',
|
|
1618
|
+
},
|
|
1619
|
+
{
|
|
1620
|
+
displayName: 'Delete By',
|
|
1621
|
+
name: 'artworkDeleteMode',
|
|
1622
|
+
type: 'options',
|
|
1623
|
+
displayOptions: { show: { operation: ['deleteArtworks'] } },
|
|
1624
|
+
options: [
|
|
1625
|
+
{ name: 'URLs', value: 'urls' },
|
|
1626
|
+
{ name: 'Mockup UUID', value: 'mockup' },
|
|
1627
|
+
],
|
|
1628
|
+
default: 'urls',
|
|
1629
|
+
},
|
|
1630
|
+
{
|
|
1631
|
+
displayName: 'URLs',
|
|
1632
|
+
name: 'artworkDeleteUrls',
|
|
1633
|
+
type: 'json',
|
|
1634
|
+
required: true,
|
|
1635
|
+
displayOptions: {
|
|
1636
|
+
show: { operation: ['deleteArtworks'], artworkDeleteMode: ['urls'] },
|
|
1637
|
+
},
|
|
1638
|
+
default: '[]',
|
|
1639
|
+
description: 'JSON array of stored artwork or preview URLs to delete',
|
|
1640
|
+
},
|
|
1641
|
+
{
|
|
1642
|
+
displayName: 'Mockup UUID',
|
|
1643
|
+
name: 'artworkDeleteMockupUuid',
|
|
1644
|
+
type: 'string',
|
|
1645
|
+
required: true,
|
|
1646
|
+
displayOptions: {
|
|
1647
|
+
show: {
|
|
1648
|
+
operation: ['deleteArtworks'],
|
|
1649
|
+
artworkDeleteMode: ['mockup'],
|
|
1650
|
+
},
|
|
1651
|
+
},
|
|
1652
|
+
default: '',
|
|
1653
|
+
description: 'Delete all stored artwork belonging to this mockup',
|
|
1654
|
+
},
|
|
1655
|
+
// ============================================
|
|
1400
1656
|
// WEBHOOK ENDPOINT PARAMETERS
|
|
1401
1657
|
// ============================================
|
|
1402
1658
|
{
|
|
@@ -1434,14 +1690,7 @@ class SudoMock {
|
|
|
1434
1690
|
operation: ['webhookCreate', 'webhookUpdate'],
|
|
1435
1691
|
},
|
|
1436
1692
|
},
|
|
1437
|
-
options:
|
|
1438
|
-
{ name: 'render.succeeded', value: 'render.succeeded' },
|
|
1439
|
-
{ name: 'render.failed', value: 'render.failed' },
|
|
1440
|
-
{ name: 'upload.succeeded', value: 'upload.succeeded' },
|
|
1441
|
-
{ name: 'video.succeeded', value: 'video.succeeded' },
|
|
1442
|
-
{ name: 'video.failed', value: 'video.failed' },
|
|
1443
|
-
{ name: 'webhook.test', value: 'webhook.test' },
|
|
1444
|
-
],
|
|
1693
|
+
options: webhooks_1.WEBHOOK_EVENT_OPTIONS,
|
|
1445
1694
|
default: [],
|
|
1446
1695
|
description: 'Events this endpoint receives. Leave empty to subscribe to all events, including ones added in the future.',
|
|
1447
1696
|
},
|
|
@@ -1545,14 +1794,7 @@ class SudoMock {
|
|
|
1545
1794
|
displayName: 'Event Type',
|
|
1546
1795
|
name: 'eventType',
|
|
1547
1796
|
type: 'options',
|
|
1548
|
-
options:
|
|
1549
|
-
{ name: 'render.succeeded', value: 'render.succeeded' },
|
|
1550
|
-
{ name: 'render.failed', value: 'render.failed' },
|
|
1551
|
-
{ name: 'upload.succeeded', value: 'upload.succeeded' },
|
|
1552
|
-
{ name: 'video.succeeded', value: 'video.succeeded' },
|
|
1553
|
-
{ name: 'video.failed', value: 'video.failed' },
|
|
1554
|
-
{ name: 'webhook.test', value: 'webhook.test' },
|
|
1555
|
-
],
|
|
1797
|
+
options: webhooks_1.WEBHOOK_EVENT_OPTIONS,
|
|
1556
1798
|
default: 'render.succeeded',
|
|
1557
1799
|
description: 'Only return deliveries for this event type',
|
|
1558
1800
|
},
|
|
@@ -1598,14 +1840,7 @@ class SudoMock {
|
|
|
1598
1840
|
displayName: 'Event Type',
|
|
1599
1841
|
name: 'eventType',
|
|
1600
1842
|
type: 'options',
|
|
1601
|
-
options:
|
|
1602
|
-
{ name: 'render.succeeded', value: 'render.succeeded' },
|
|
1603
|
-
{ name: 'render.failed', value: 'render.failed' },
|
|
1604
|
-
{ name: 'upload.succeeded', value: 'upload.succeeded' },
|
|
1605
|
-
{ name: 'video.succeeded', value: 'video.succeeded' },
|
|
1606
|
-
{ name: 'video.failed', value: 'video.failed' },
|
|
1607
|
-
{ name: 'webhook.test', value: 'webhook.test' },
|
|
1608
|
-
],
|
|
1843
|
+
options: webhooks_1.WEBHOOK_EVENT_OPTIONS,
|
|
1609
1844
|
default: 'render.succeeded',
|
|
1610
1845
|
description: 'Only return deliveries for this event type',
|
|
1611
1846
|
},
|
|
@@ -1818,6 +2053,8 @@ class SudoMock {
|
|
|
1818
2053
|
else if (operation === 'create2DMockup') {
|
|
1819
2054
|
const sourceMode = this.getNodeParameter('twoDSourceMode', i);
|
|
1820
2055
|
const name = this.getNodeParameter('twoDName', i, '');
|
|
2056
|
+
const isAsync = this.getNodeParameter('twoDCreateIsAsync', i, false);
|
|
2057
|
+
const printAreas = this.getNodeParameter('twoDSetPrintAreas.items', i, []);
|
|
1821
2058
|
const body = {};
|
|
1822
2059
|
if (sourceMode === 'base64') {
|
|
1823
2060
|
body.source_base64 = this.getNodeParameter('twoDSourceBase64', i);
|
|
@@ -1828,13 +2065,22 @@ class SudoMock {
|
|
|
1828
2065
|
if (name) {
|
|
1829
2066
|
body.name = name;
|
|
1830
2067
|
}
|
|
2068
|
+
if (isAsync) {
|
|
2069
|
+
body.is_async = true;
|
|
2070
|
+
}
|
|
2071
|
+
if (printAreas.length > 0) {
|
|
2072
|
+
body.print_areas = format2DPrintAreas(printAreas);
|
|
2073
|
+
}
|
|
1831
2074
|
const response = await this.helpers.httpRequestWithAuthentication.call(this, 'sudoMockApi', {
|
|
1832
2075
|
method: 'POST',
|
|
1833
2076
|
url: 'https://api.sudomock.com/api/v1/sudoai/2d-mockups',
|
|
1834
2077
|
body,
|
|
1835
2078
|
json: true,
|
|
1836
2079
|
});
|
|
1837
|
-
returnData.push({
|
|
2080
|
+
returnData.push({
|
|
2081
|
+
json: response,
|
|
2082
|
+
pairedItem: { item: i },
|
|
2083
|
+
});
|
|
1838
2084
|
}
|
|
1839
2085
|
// ========================================
|
|
1840
2086
|
// 2D: GET MOCKUP
|
|
@@ -1843,10 +2089,13 @@ class SudoMock {
|
|
|
1843
2089
|
const mockupUuid = this.getNodeParameter('twoDMockupUuid', i);
|
|
1844
2090
|
const response = await this.helpers.httpRequestWithAuthentication.call(this, 'sudoMockApi', {
|
|
1845
2091
|
method: 'GET',
|
|
1846
|
-
url: `https://api.sudomock.com/api/v1/sudoai/2d-
|
|
2092
|
+
url: `https://api.sudomock.com/api/v1/sudoai/2d-mockups/${mockupUuid}`,
|
|
1847
2093
|
json: true,
|
|
1848
2094
|
});
|
|
1849
|
-
returnData.push({
|
|
2095
|
+
returnData.push({
|
|
2096
|
+
json: response,
|
|
2097
|
+
pairedItem: { item: i },
|
|
2098
|
+
});
|
|
1850
2099
|
}
|
|
1851
2100
|
// ========================================
|
|
1852
2101
|
// 2D: LIST MOCKUPS
|
|
@@ -1857,7 +2106,10 @@ class SudoMock {
|
|
|
1857
2106
|
url: 'https://api.sudomock.com/api/v1/sudoai/2d-mockups',
|
|
1858
2107
|
json: true,
|
|
1859
2108
|
});
|
|
1860
|
-
returnData.push({
|
|
2109
|
+
returnData.push({
|
|
2110
|
+
json: response,
|
|
2111
|
+
pairedItem: { item: i },
|
|
2112
|
+
});
|
|
1861
2113
|
}
|
|
1862
2114
|
// ========================================
|
|
1863
2115
|
// 2D: SET PRINT AREAS
|
|
@@ -1865,23 +2117,20 @@ class SudoMock {
|
|
|
1865
2117
|
else if (operation === 'set2DPrintAreas') {
|
|
1866
2118
|
const mockupUuid = this.getNodeParameter('twoDMockupUuid', i);
|
|
1867
2119
|
const printAreas = this.getNodeParameter('twoDSetPrintAreas.items', i, []);
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
[area.point2X, area.point2Y],
|
|
1873
|
-
[area.point3X, area.point3Y],
|
|
1874
|
-
[area.point4X, area.point4Y],
|
|
1875
|
-
],
|
|
1876
|
-
})),
|
|
1877
|
-
};
|
|
2120
|
+
if (printAreas.length === 0) {
|
|
2121
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Add at least one print area');
|
|
2122
|
+
}
|
|
2123
|
+
const body = { print_areas: format2DPrintAreas(printAreas) };
|
|
1878
2124
|
const response = await this.helpers.httpRequestWithAuthentication.call(this, 'sudoMockApi', {
|
|
1879
2125
|
method: 'PUT',
|
|
1880
|
-
url: `https://api.sudomock.com/api/v1/sudoai/2d-
|
|
2126
|
+
url: `https://api.sudomock.com/api/v1/sudoai/2d-mockups/${mockupUuid}/print-areas`,
|
|
1881
2127
|
body,
|
|
1882
2128
|
json: true,
|
|
1883
2129
|
});
|
|
1884
|
-
returnData.push({
|
|
2130
|
+
returnData.push({
|
|
2131
|
+
json: response,
|
|
2132
|
+
pairedItem: { item: i },
|
|
2133
|
+
});
|
|
1885
2134
|
}
|
|
1886
2135
|
// ========================================
|
|
1887
2136
|
// 2D: RENDER MOCKUP
|
|
@@ -1909,20 +2158,26 @@ class SudoMock {
|
|
|
1909
2158
|
return printArea;
|
|
1910
2159
|
});
|
|
1911
2160
|
const exportOptions = this.getNodeParameter('twoDExportOptions', i, {});
|
|
2161
|
+
const isAsync = this.getNodeParameter('twoDRenderIsAsync', i, false);
|
|
1912
2162
|
const body = {
|
|
1913
|
-
mockup_uuid: mockupUuid,
|
|
1914
2163
|
print_areas: printAreas,
|
|
1915
2164
|
};
|
|
1916
2165
|
if (Object.keys(exportOptions).length > 0) {
|
|
1917
2166
|
body.export_options = exportOptions;
|
|
1918
2167
|
}
|
|
2168
|
+
if (isAsync) {
|
|
2169
|
+
body.is_async = true;
|
|
2170
|
+
}
|
|
1919
2171
|
const response = await this.helpers.httpRequestWithAuthentication.call(this, 'sudoMockApi', {
|
|
1920
2172
|
method: 'POST',
|
|
1921
|
-
url:
|
|
2173
|
+
url: `https://api.sudomock.com/api/v1/sudoai/2d-mockups/${mockupUuid}/render`,
|
|
1922
2174
|
body,
|
|
1923
2175
|
json: true,
|
|
1924
2176
|
});
|
|
1925
|
-
returnData.push({
|
|
2177
|
+
returnData.push({
|
|
2178
|
+
json: response,
|
|
2179
|
+
pairedItem: { item: i },
|
|
2180
|
+
});
|
|
1926
2181
|
}
|
|
1927
2182
|
// ========================================
|
|
1928
2183
|
// 2D: DELETE MOCKUP
|
|
@@ -1931,7 +2186,7 @@ class SudoMock {
|
|
|
1931
2186
|
const mockupUuid = this.getNodeParameter('twoDMockupUuid', i);
|
|
1932
2187
|
await this.helpers.httpRequestWithAuthentication.call(this, 'sudoMockApi', {
|
|
1933
2188
|
method: 'DELETE',
|
|
1934
|
-
url: `https://api.sudomock.com/api/v1/sudoai/2d-
|
|
2189
|
+
url: `https://api.sudomock.com/api/v1/sudoai/2d-mockups/${mockupUuid}`,
|
|
1935
2190
|
});
|
|
1936
2191
|
returnData.push({
|
|
1937
2192
|
json: {
|
|
@@ -1944,11 +2199,138 @@ class SudoMock {
|
|
|
1944
2199
|
});
|
|
1945
2200
|
}
|
|
1946
2201
|
// ========================================
|
|
2202
|
+
// FONTS
|
|
2203
|
+
// ========================================
|
|
2204
|
+
else if (operation === 'listFonts') {
|
|
2205
|
+
const filters = this.getNodeParameter('fontFilters', i, {});
|
|
2206
|
+
const qs = {};
|
|
2207
|
+
if (filters.page !== undefined)
|
|
2208
|
+
qs.page = filters.page;
|
|
2209
|
+
if (filters.perPage !== undefined)
|
|
2210
|
+
qs.per_page = filters.perPage;
|
|
2211
|
+
if (filters.category)
|
|
2212
|
+
qs.category = filters.category;
|
|
2213
|
+
if (filters.search)
|
|
2214
|
+
qs.search = filters.search;
|
|
2215
|
+
if (filters.scope)
|
|
2216
|
+
qs.scope = filters.scope;
|
|
2217
|
+
const response = await this.helpers.httpRequestWithAuthentication.call(this, 'sudoMockApi', {
|
|
2218
|
+
method: 'GET',
|
|
2219
|
+
url: 'https://api.sudomock.com/api/v1/fonts',
|
|
2220
|
+
qs,
|
|
2221
|
+
json: true,
|
|
2222
|
+
});
|
|
2223
|
+
returnData.push({
|
|
2224
|
+
json: response,
|
|
2225
|
+
pairedItem: { item: i },
|
|
2226
|
+
});
|
|
2227
|
+
}
|
|
2228
|
+
else if (operation === 'getFont') {
|
|
2229
|
+
const fontUuid = this.getNodeParameter('fontUuid', i);
|
|
2230
|
+
const response = await this.helpers.httpRequestWithAuthentication.call(this, 'sudoMockApi', {
|
|
2231
|
+
method: 'GET',
|
|
2232
|
+
url: `https://api.sudomock.com/api/v1/fonts/${fontUuid}`,
|
|
2233
|
+
json: true,
|
|
2234
|
+
});
|
|
2235
|
+
returnData.push({
|
|
2236
|
+
json: response,
|
|
2237
|
+
pairedItem: { item: i },
|
|
2238
|
+
});
|
|
2239
|
+
}
|
|
2240
|
+
else if (operation === 'uploadFont') {
|
|
2241
|
+
const licenseConfirmed = this.getNodeParameter('fontLicenseConfirmed', i, false);
|
|
2242
|
+
if (!licenseConfirmed) {
|
|
2243
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Confirm you have the right to use and embed this font');
|
|
2244
|
+
}
|
|
2245
|
+
const response = await this.helpers.httpRequestWithAuthentication.call(this, 'sudoMockApi', {
|
|
2246
|
+
method: 'POST',
|
|
2247
|
+
url: 'https://api.sudomock.com/api/v1/fonts',
|
|
2248
|
+
body: {
|
|
2249
|
+
url: this.getNodeParameter('fontUrl', i),
|
|
2250
|
+
license_confirmed: true,
|
|
2251
|
+
},
|
|
2252
|
+
json: true,
|
|
2253
|
+
});
|
|
2254
|
+
returnData.push({
|
|
2255
|
+
json: response,
|
|
2256
|
+
pairedItem: { item: i },
|
|
2257
|
+
});
|
|
2258
|
+
}
|
|
2259
|
+
else if (operation === 'deleteFont') {
|
|
2260
|
+
const fontUuid = this.getNodeParameter('fontUuid', i);
|
|
2261
|
+
const response = await this.helpers.httpRequestWithAuthentication.call(this, 'sudoMockApi', {
|
|
2262
|
+
method: 'DELETE',
|
|
2263
|
+
url: `https://api.sudomock.com/api/v1/fonts/${fontUuid}`,
|
|
2264
|
+
json: true,
|
|
2265
|
+
});
|
|
2266
|
+
returnData.push({
|
|
2267
|
+
json: response,
|
|
2268
|
+
pairedItem: { item: i },
|
|
2269
|
+
});
|
|
2270
|
+
}
|
|
2271
|
+
// ========================================
|
|
2272
|
+
// ARTWORKS
|
|
2273
|
+
// ========================================
|
|
2274
|
+
else if (operation === 'storeArtworks') {
|
|
2275
|
+
const items = this.getNodeParameter('artworkItems.items', i, []);
|
|
2276
|
+
const previewUrl = this.getNodeParameter('artworkPreviewUrl', i, '');
|
|
2277
|
+
if (items.length === 0 && !previewUrl) {
|
|
2278
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Add at least one artwork item or a preview URL');
|
|
2279
|
+
}
|
|
2280
|
+
if (items.length > 10) {
|
|
2281
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Artwork Items supports up to 10 files');
|
|
2282
|
+
}
|
|
2283
|
+
const body = {
|
|
2284
|
+
mockup_uuid: this.getNodeParameter('artworkMockupUuid', i),
|
|
2285
|
+
items: items.map((item) => ({
|
|
2286
|
+
smart_object_uuid: item.smartObjectUuid,
|
|
2287
|
+
base64: item.base64,
|
|
2288
|
+
})),
|
|
2289
|
+
};
|
|
2290
|
+
if (previewUrl)
|
|
2291
|
+
body.preview_url = previewUrl;
|
|
2292
|
+
const response = await this.helpers.httpRequestWithAuthentication.call(this, 'sudoMockApi', {
|
|
2293
|
+
method: 'POST',
|
|
2294
|
+
url: 'https://api.sudomock.com/api/v1/artworks',
|
|
2295
|
+
body,
|
|
2296
|
+
json: true,
|
|
2297
|
+
});
|
|
2298
|
+
returnData.push({
|
|
2299
|
+
json: response,
|
|
2300
|
+
pairedItem: { item: i },
|
|
2301
|
+
});
|
|
2302
|
+
}
|
|
2303
|
+
else if (operation === 'deleteArtworks') {
|
|
2304
|
+
const mode = this.getNodeParameter('artworkDeleteMode', i);
|
|
2305
|
+
const body = {};
|
|
2306
|
+
if (mode === 'mockup') {
|
|
2307
|
+
body.mockup_uuid = this.getNodeParameter('artworkDeleteMockupUuid', i);
|
|
2308
|
+
}
|
|
2309
|
+
else {
|
|
2310
|
+
const urls = parseJsonArray(this.getNodeParameter('artworkDeleteUrls', i, []), 'URLs');
|
|
2311
|
+
if (urls.length === 0 || !urls.every((url) => typeof url === 'string')) {
|
|
2312
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'URLs must contain at least one URL');
|
|
2313
|
+
}
|
|
2314
|
+
body.urls = urls;
|
|
2315
|
+
}
|
|
2316
|
+
const response = await this.helpers.httpRequestWithAuthentication.call(this, 'sudoMockApi', {
|
|
2317
|
+
method: 'POST',
|
|
2318
|
+
url: 'https://api.sudomock.com/api/v1/artworks/delete',
|
|
2319
|
+
body,
|
|
2320
|
+
json: true,
|
|
2321
|
+
});
|
|
2322
|
+
returnData.push({
|
|
2323
|
+
json: response,
|
|
2324
|
+
pairedItem: { item: i },
|
|
2325
|
+
});
|
|
2326
|
+
}
|
|
2327
|
+
// ========================================
|
|
1947
2328
|
// RENDER MOCKUP
|
|
1948
2329
|
// ========================================
|
|
1949
2330
|
else if (operation === 'render') {
|
|
1950
2331
|
const mockupUuid = this.getNodeParameter('mockupUuid', i);
|
|
1951
2332
|
const smartObjectsData = this.getNodeParameter('smartObjects.items', i, []);
|
|
2333
|
+
const textLayers = parseJsonArray(this.getNodeParameter('textLayers', i, []), 'Text Layers');
|
|
1952
2334
|
const exportOptions = this.getNodeParameter('exportOptions', i, {});
|
|
1953
2335
|
// Convert smart objects array to API format
|
|
1954
2336
|
const smartObjects = smartObjectsData.map((so) => {
|
|
@@ -2035,6 +2417,12 @@ class SudoMock {
|
|
|
2035
2417
|
mockup_uuid: mockupUuid,
|
|
2036
2418
|
smart_objects: smartObjects,
|
|
2037
2419
|
};
|
|
2420
|
+
if (textLayers.length > 0) {
|
|
2421
|
+
body.text_layers = textLayers;
|
|
2422
|
+
}
|
|
2423
|
+
if (smartObjects.length === 0 && textLayers.length === 0) {
|
|
2424
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Add at least one smart object or text layer override');
|
|
2425
|
+
}
|
|
2038
2426
|
if (isAsync) {
|
|
2039
2427
|
body.is_async = true;
|
|
2040
2428
|
}
|
|
@@ -2136,7 +2524,10 @@ class SudoMock {
|
|
|
2136
2524
|
returnData.push({ json: out, pairedItem: { item: i } });
|
|
2137
2525
|
}
|
|
2138
2526
|
else {
|
|
2139
|
-
returnData.push({
|
|
2527
|
+
returnData.push({
|
|
2528
|
+
json: accepted,
|
|
2529
|
+
pairedItem: { item: i },
|
|
2530
|
+
});
|
|
2140
2531
|
}
|
|
2141
2532
|
}
|
|
2142
2533
|
// ========================================
|
|
@@ -2191,7 +2582,10 @@ class SudoMock {
|
|
|
2191
2582
|
qs,
|
|
2192
2583
|
json: true,
|
|
2193
2584
|
});
|
|
2194
|
-
returnData.push({
|
|
2585
|
+
returnData.push({
|
|
2586
|
+
json: response,
|
|
2587
|
+
pairedItem: { item: i },
|
|
2588
|
+
});
|
|
2195
2589
|
}
|
|
2196
2590
|
// ========================================
|
|
2197
2591
|
// WEBHOOK: LIST ENDPOINTS
|
|
@@ -2202,7 +2596,10 @@ class SudoMock {
|
|
|
2202
2596
|
url: 'https://api.sudomock.com/api/v1/webhook-endpoints',
|
|
2203
2597
|
json: true,
|
|
2204
2598
|
});
|
|
2205
|
-
returnData.push({
|
|
2599
|
+
returnData.push({
|
|
2600
|
+
json: response,
|
|
2601
|
+
pairedItem: { item: i },
|
|
2602
|
+
});
|
|
2206
2603
|
}
|
|
2207
2604
|
// ========================================
|
|
2208
2605
|
// WEBHOOK: EVENTS FEED
|
|
@@ -2225,7 +2622,10 @@ class SudoMock {
|
|
|
2225
2622
|
qs,
|
|
2226
2623
|
json: true,
|
|
2227
2624
|
});
|
|
2228
|
-
returnData.push({
|
|
2625
|
+
returnData.push({
|
|
2626
|
+
json: { deliveries: response },
|
|
2627
|
+
pairedItem: { item: i },
|
|
2628
|
+
});
|
|
2229
2629
|
}
|
|
2230
2630
|
// ========================================
|
|
2231
2631
|
// WEBHOOK: GET ENDPOINT
|
|
@@ -2237,7 +2637,10 @@ class SudoMock {
|
|
|
2237
2637
|
url: `https://api.sudomock.com/api/v1/webhook-endpoints/${webhookId}`,
|
|
2238
2638
|
json: true,
|
|
2239
2639
|
});
|
|
2240
|
-
returnData.push({
|
|
2640
|
+
returnData.push({
|
|
2641
|
+
json: response,
|
|
2642
|
+
pairedItem: { item: i },
|
|
2643
|
+
});
|
|
2241
2644
|
}
|
|
2242
2645
|
// ========================================
|
|
2243
2646
|
// WEBHOOK: CREATE ENDPOINT
|
|
@@ -2259,7 +2662,10 @@ class SudoMock {
|
|
|
2259
2662
|
body,
|
|
2260
2663
|
json: true,
|
|
2261
2664
|
});
|
|
2262
|
-
returnData.push({
|
|
2665
|
+
returnData.push({
|
|
2666
|
+
json: response,
|
|
2667
|
+
pairedItem: { item: i },
|
|
2668
|
+
});
|
|
2263
2669
|
}
|
|
2264
2670
|
// ========================================
|
|
2265
2671
|
// WEBHOOK: UPDATE ENDPOINT
|
|
@@ -2287,7 +2693,10 @@ class SudoMock {
|
|
|
2287
2693
|
body,
|
|
2288
2694
|
json: true,
|
|
2289
2695
|
});
|
|
2290
|
-
returnData.push({
|
|
2696
|
+
returnData.push({
|
|
2697
|
+
json: response,
|
|
2698
|
+
pairedItem: { item: i },
|
|
2699
|
+
});
|
|
2291
2700
|
}
|
|
2292
2701
|
// ========================================
|
|
2293
2702
|
// WEBHOOK: DELETE ENDPOINT
|
|
@@ -2318,7 +2727,10 @@ class SudoMock {
|
|
|
2318
2727
|
url: `https://api.sudomock.com/api/v1/webhook-endpoints/${webhookId}/rotate-secret`,
|
|
2319
2728
|
json: true,
|
|
2320
2729
|
});
|
|
2321
|
-
returnData.push({
|
|
2730
|
+
returnData.push({
|
|
2731
|
+
json: response,
|
|
2732
|
+
pairedItem: { item: i },
|
|
2733
|
+
});
|
|
2322
2734
|
}
|
|
2323
2735
|
// ========================================
|
|
2324
2736
|
// WEBHOOK: SEND TEST
|
|
@@ -2330,7 +2742,10 @@ class SudoMock {
|
|
|
2330
2742
|
url: `https://api.sudomock.com/api/v1/webhook-endpoints/${webhookId}/test`,
|
|
2331
2743
|
json: true,
|
|
2332
2744
|
});
|
|
2333
|
-
returnData.push({
|
|
2745
|
+
returnData.push({
|
|
2746
|
+
json: response,
|
|
2747
|
+
pairedItem: { item: i },
|
|
2748
|
+
});
|
|
2334
2749
|
}
|
|
2335
2750
|
// ========================================
|
|
2336
2751
|
// WEBHOOK: LIST DELIVERIES
|
|
@@ -2354,7 +2769,10 @@ class SudoMock {
|
|
|
2354
2769
|
qs,
|
|
2355
2770
|
json: true,
|
|
2356
2771
|
});
|
|
2357
|
-
returnData.push({
|
|
2772
|
+
returnData.push({
|
|
2773
|
+
json: response,
|
|
2774
|
+
pairedItem: { item: i },
|
|
2775
|
+
});
|
|
2358
2776
|
}
|
|
2359
2777
|
// ========================================
|
|
2360
2778
|
// WEBHOOK: REPLAY DELIVERY
|
|
@@ -2367,7 +2785,10 @@ class SudoMock {
|
|
|
2367
2785
|
url: `https://api.sudomock.com/api/v1/webhook-endpoints/${webhookId}/deliveries/${deliveryId}/replay`,
|
|
2368
2786
|
json: true,
|
|
2369
2787
|
});
|
|
2370
|
-
returnData.push({
|
|
2788
|
+
returnData.push({
|
|
2789
|
+
json: response,
|
|
2790
|
+
pairedItem: { item: i },
|
|
2791
|
+
});
|
|
2371
2792
|
}
|
|
2372
2793
|
// ========================================
|
|
2373
2794
|
// WEBHOOK: REPLAY FAILED DELIVERIES
|
|
@@ -2379,7 +2800,10 @@ class SudoMock {
|
|
|
2379
2800
|
url: `https://api.sudomock.com/api/v1/webhook-endpoints/${webhookId}/deliveries/replay-failed`,
|
|
2380
2801
|
json: true,
|
|
2381
2802
|
});
|
|
2382
|
-
returnData.push({
|
|
2803
|
+
returnData.push({
|
|
2804
|
+
json: response,
|
|
2805
|
+
pairedItem: { item: i },
|
|
2806
|
+
});
|
|
2383
2807
|
}
|
|
2384
2808
|
// ========================================
|
|
2385
2809
|
// GET ACCOUNT INFO
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { IHookFunctions, INodeType, INodeTypeDescription, IWebhookFunctions, IWebhookResponseData } from 'n8n-workflow';
|
|
2
|
+
export declare class SudoMockTrigger implements INodeType {
|
|
3
|
+
description: INodeTypeDescription;
|
|
4
|
+
webhookMethods: {
|
|
5
|
+
default: {
|
|
6
|
+
checkExists(this: IHookFunctions): Promise<boolean>;
|
|
7
|
+
create(this: IHookFunctions): Promise<boolean>;
|
|
8
|
+
delete(this: IHookFunctions): Promise<boolean>;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
webhook(this: IWebhookFunctions): Promise<IWebhookResponseData>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SudoMockTrigger = void 0;
|
|
4
|
+
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
|
+
const webhooks_1 = require("./webhooks");
|
|
6
|
+
const API_URL = 'https://api.sudomock.com/api/v1/webhook-endpoints';
|
|
7
|
+
function firstHeader(value) {
|
|
8
|
+
return Array.isArray(value) ? (value[0] ?? '') : (value ?? '');
|
|
9
|
+
}
|
|
10
|
+
class SudoMockTrigger {
|
|
11
|
+
description = {
|
|
12
|
+
displayName: 'SudoMock Trigger',
|
|
13
|
+
name: 'sudoMockTrigger',
|
|
14
|
+
icon: 'file:sudomock.svg',
|
|
15
|
+
group: ['trigger'],
|
|
16
|
+
version: 1,
|
|
17
|
+
description: 'Start a workflow when a SudoMock job or test event finishes',
|
|
18
|
+
defaults: { name: 'SudoMock Trigger' },
|
|
19
|
+
inputs: [],
|
|
20
|
+
outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
|
|
21
|
+
credentials: [{ name: 'sudoMockApi', required: true }],
|
|
22
|
+
webhooks: [
|
|
23
|
+
{
|
|
24
|
+
name: 'default',
|
|
25
|
+
httpMethod: 'POST',
|
|
26
|
+
responseMode: 'onReceived',
|
|
27
|
+
path: 'sudomock',
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
properties: [
|
|
31
|
+
{
|
|
32
|
+
displayName: 'Events',
|
|
33
|
+
name: 'events',
|
|
34
|
+
type: 'multiOptions',
|
|
35
|
+
options: webhooks_1.WEBHOOK_EVENT_OPTIONS,
|
|
36
|
+
default: [],
|
|
37
|
+
description: 'Events that start this workflow. Leave empty to receive all events, including ones added in the future.',
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
webhookMethods = {
|
|
42
|
+
default: {
|
|
43
|
+
async checkExists() {
|
|
44
|
+
const data = this.getWorkflowStaticData('node');
|
|
45
|
+
if (!data.webhookId || !data.webhookSecret)
|
|
46
|
+
return false;
|
|
47
|
+
try {
|
|
48
|
+
await this.helpers.httpRequestWithAuthentication.call(this, 'sudoMockApi', {
|
|
49
|
+
method: 'GET',
|
|
50
|
+
url: `${API_URL}/${data.webhookId}`,
|
|
51
|
+
json: true,
|
|
52
|
+
});
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (Number(error.statusCode) !== 404)
|
|
57
|
+
throw error;
|
|
58
|
+
delete data.webhookId;
|
|
59
|
+
delete data.webhookSecret;
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
async create() {
|
|
64
|
+
const url = this.getNodeWebhookUrl('default');
|
|
65
|
+
if (!url)
|
|
66
|
+
return false;
|
|
67
|
+
const response = (await this.helpers.httpRequestWithAuthentication.call(this, 'sudoMockApi', {
|
|
68
|
+
method: 'POST',
|
|
69
|
+
url: API_URL,
|
|
70
|
+
body: {
|
|
71
|
+
url,
|
|
72
|
+
description: 'Workflow trigger',
|
|
73
|
+
event_types: this.getNodeParameter('events', []),
|
|
74
|
+
},
|
|
75
|
+
json: true,
|
|
76
|
+
}));
|
|
77
|
+
if (typeof response.id !== 'string' || typeof response.secret !== 'string')
|
|
78
|
+
return false;
|
|
79
|
+
const data = this.getWorkflowStaticData('node');
|
|
80
|
+
data.webhookId = response.id;
|
|
81
|
+
data.webhookSecret = response.secret;
|
|
82
|
+
return true;
|
|
83
|
+
},
|
|
84
|
+
async delete() {
|
|
85
|
+
const data = this.getWorkflowStaticData('node');
|
|
86
|
+
if (!data.webhookId)
|
|
87
|
+
return true;
|
|
88
|
+
try {
|
|
89
|
+
await this.helpers.httpRequestWithAuthentication.call(this, 'sudoMockApi', {
|
|
90
|
+
method: 'DELETE',
|
|
91
|
+
url: `${API_URL}/${data.webhookId}`,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
delete data.webhookId;
|
|
98
|
+
delete data.webhookSecret;
|
|
99
|
+
return true;
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
async webhook() {
|
|
104
|
+
const request = this.getRequestObject();
|
|
105
|
+
if (!request.rawBody && request.readRawBody)
|
|
106
|
+
await request.readRawBody();
|
|
107
|
+
const rawBody = request.rawBody?.toString('utf8') ?? '';
|
|
108
|
+
const headers = this.getHeaderData();
|
|
109
|
+
const data = this.getWorkflowStaticData('node');
|
|
110
|
+
const valid = (0, webhooks_1.verifyWebhookSignature)(rawBody, firstHeader(headers['x-sudomock-signature']), firstHeader(headers['x-sudomock-timestamp']), typeof data.webhookSecret === 'string' ? data.webhookSecret : '');
|
|
111
|
+
if (!rawBody || !valid) {
|
|
112
|
+
this.getResponseObject().status(401).json({ message: 'Invalid webhook signature' });
|
|
113
|
+
return { noWebhookResponse: true };
|
|
114
|
+
}
|
|
115
|
+
return { workflowData: [[{ json: this.getBodyData() }]] };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
exports.SudoMockTrigger = SudoMockTrigger;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const WEBHOOK_EVENT_OPTIONS: {
|
|
2
|
+
name: string;
|
|
3
|
+
value: string;
|
|
4
|
+
}[];
|
|
5
|
+
export declare function verifyWebhookSignature(payload: string, signature: string, timestamp: string | number, secret: string, toleranceSeconds?: number, nowSeconds?: number): boolean;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WEBHOOK_EVENT_OPTIONS = void 0;
|
|
4
|
+
exports.verifyWebhookSignature = verifyWebhookSignature;
|
|
5
|
+
const node_crypto_1 = require("node:crypto");
|
|
6
|
+
exports.WEBHOOK_EVENT_OPTIONS = [
|
|
7
|
+
{ name: 'render.succeeded', value: 'render.succeeded' },
|
|
8
|
+
{ name: 'render.failed', value: 'render.failed' },
|
|
9
|
+
{ name: 'upload.succeeded', value: 'upload.succeeded' },
|
|
10
|
+
{ name: 'video.succeeded', value: 'video.succeeded' },
|
|
11
|
+
{ name: 'video.failed', value: 'video.failed' },
|
|
12
|
+
{ name: '2d_mockup.ready', value: '2d_mockup.ready' },
|
|
13
|
+
{ name: '2d_mockup.rejected', value: '2d_mockup.rejected' },
|
|
14
|
+
{ name: '2d_mockup.failed', value: '2d_mockup.failed' },
|
|
15
|
+
{ name: '2d_render.succeeded', value: '2d_render.succeeded' },
|
|
16
|
+
{ name: '2d_render.failed', value: '2d_render.failed' },
|
|
17
|
+
{ name: 'webhook.test', value: 'webhook.test' },
|
|
18
|
+
];
|
|
19
|
+
function verifyWebhookSignature(payload, signature, timestamp, secret, toleranceSeconds = 300, nowSeconds = Math.floor(Date.now() / 1000)) {
|
|
20
|
+
if (!signature || !secret)
|
|
21
|
+
return false;
|
|
22
|
+
const parsedTimestamp = typeof timestamp === 'number' ? timestamp : Number.parseInt(timestamp, 10);
|
|
23
|
+
if (!Number.isFinite(parsedTimestamp) ||
|
|
24
|
+
Math.abs(nowSeconds - parsedTimestamp) > toleranceSeconds) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
const expected = (0, node_crypto_1.createHmac)('sha256', secret)
|
|
28
|
+
.update(`${parsedTimestamp}.${payload}`)
|
|
29
|
+
.digest('hex');
|
|
30
|
+
if (signature.length !== expected.length)
|
|
31
|
+
return false;
|
|
32
|
+
try {
|
|
33
|
+
return (0, node_crypto_1.timingSafeEqual)(Buffer.from(signature, 'hex'), Buffer.from(expected, 'hex'));
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-sudomock",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "n8n community node for SudoMock mockup rendering API - POD automation",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://sudomock.com",
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
"dist/credentials/SudoMockApi.credentials.js"
|
|
41
41
|
],
|
|
42
42
|
"nodes": [
|
|
43
|
-
"dist/nodes/SudoMock/SudoMock.node.js"
|
|
43
|
+
"dist/nodes/SudoMock/SudoMock.node.js",
|
|
44
|
+
"dist/nodes/SudoMock/SudoMockTrigger.node.js"
|
|
44
45
|
]
|
|
45
46
|
},
|
|
46
47
|
"scripts": {
|