n8n-nodes-nvk-call-api 0.0.5 → 0.0.7
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.
|
@@ -29,10 +29,28 @@ exports.nvkBrowserApiDescription = {
|
|
|
29
29
|
name: 'Docker',
|
|
30
30
|
value: 'docker',
|
|
31
31
|
},
|
|
32
|
+
{
|
|
33
|
+
name: 'Tunnel (Custom URL)',
|
|
34
|
+
value: 'tunnel',
|
|
35
|
+
},
|
|
32
36
|
],
|
|
33
37
|
default: 'local',
|
|
34
38
|
description: 'Choose the environment to connect to',
|
|
35
39
|
},
|
|
40
|
+
{
|
|
41
|
+
displayName: 'Tunnel URL',
|
|
42
|
+
name: 'tunnelUrl',
|
|
43
|
+
type: 'string',
|
|
44
|
+
displayOptions: {
|
|
45
|
+
show: {
|
|
46
|
+
environment: ['tunnel'],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
default: '',
|
|
50
|
+
placeholder: 'https://abc123.ngrok.io',
|
|
51
|
+
description: 'Enter your tunnel URL (ngrok, Cloudflare Tunnel, etc.)',
|
|
52
|
+
required: true,
|
|
53
|
+
},
|
|
36
54
|
{
|
|
37
55
|
displayName: 'Resource',
|
|
38
56
|
name: 'resource',
|
|
@@ -47,6 +65,10 @@ exports.nvkBrowserApiDescription = {
|
|
|
47
65
|
name: 'Page Interaction',
|
|
48
66
|
value: 'pageInteraction',
|
|
49
67
|
},
|
|
68
|
+
{
|
|
69
|
+
name: 'Browser Automation',
|
|
70
|
+
value: 'browserAutomation',
|
|
71
|
+
},
|
|
50
72
|
],
|
|
51
73
|
default: 'profileManagement',
|
|
52
74
|
},
|
|
@@ -125,9 +147,166 @@ exports.nvkBrowserApiDescription = {
|
|
|
125
147
|
value: 'browserHttpRequest',
|
|
126
148
|
action: 'Make HTTP requests using Browser',
|
|
127
149
|
},
|
|
150
|
+
{
|
|
151
|
+
name: 'Get Recaptcha Token',
|
|
152
|
+
value: 'getRecaptchaToken',
|
|
153
|
+
action: 'Get Recaptcha Token',
|
|
154
|
+
},
|
|
128
155
|
],
|
|
129
156
|
default: 'moveAndClick',
|
|
130
157
|
},
|
|
158
|
+
{
|
|
159
|
+
displayName: 'Operation',
|
|
160
|
+
name: 'operation',
|
|
161
|
+
type: 'options',
|
|
162
|
+
noDataExpression: true,
|
|
163
|
+
displayOptions: {
|
|
164
|
+
show: {
|
|
165
|
+
resource: ['browserAutomation'],
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
options: [
|
|
169
|
+
{
|
|
170
|
+
name: 'Run Multiple Profiles',
|
|
171
|
+
value: 'runMultipleProfiles',
|
|
172
|
+
action: 'Run Multiple Profiles',
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
default: 'runMultipleProfiles',
|
|
176
|
+
},
|
|
177
|
+
// Run Multiple Profiles Fields
|
|
178
|
+
{
|
|
179
|
+
displayName: 'Data',
|
|
180
|
+
name: 'data',
|
|
181
|
+
type: 'string',
|
|
182
|
+
typeOptions: {
|
|
183
|
+
rows: 10,
|
|
184
|
+
},
|
|
185
|
+
displayOptions: {
|
|
186
|
+
show: {
|
|
187
|
+
resource: ['browserAutomation'],
|
|
188
|
+
operation: ['runMultipleProfiles'],
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
default: '',
|
|
192
|
+
required: true,
|
|
193
|
+
description: 'Enter data in format: line|profileId (one per line)',
|
|
194
|
+
placeholder: '1|212e2d01-0c8a-4373-9c9f-9153354de0a4\n2|212e2d01-0c8a-4373-9c9f-9153354de0a4',
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
displayName: 'Number of Threads',
|
|
198
|
+
name: 'numberOfThreads',
|
|
199
|
+
type: 'number',
|
|
200
|
+
displayOptions: {
|
|
201
|
+
show: {
|
|
202
|
+
resource: ['browserAutomation'],
|
|
203
|
+
operation: ['runMultipleProfiles'],
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
default: 1,
|
|
207
|
+
description: 'Number of parallel threads to run',
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
displayName: 'Define Columns',
|
|
211
|
+
name: 'defineColumns',
|
|
212
|
+
type: 'number',
|
|
213
|
+
displayOptions: {
|
|
214
|
+
show: {
|
|
215
|
+
resource: ['browserAutomation'],
|
|
216
|
+
operation: ['runMultipleProfiles'],
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
default: 3,
|
|
220
|
+
description: 'Number of columns in grid layout',
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
displayName: 'Define Rows',
|
|
224
|
+
name: 'defineRows',
|
|
225
|
+
type: 'number',
|
|
226
|
+
displayOptions: {
|
|
227
|
+
show: {
|
|
228
|
+
resource: ['browserAutomation'],
|
|
229
|
+
operation: ['runMultipleProfiles'],
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
default: 2,
|
|
233
|
+
description: 'Number of rows in grid layout',
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
displayName: 'Win Scale',
|
|
237
|
+
name: 'winScale',
|
|
238
|
+
type: 'number',
|
|
239
|
+
displayOptions: {
|
|
240
|
+
show: {
|
|
241
|
+
resource: ['browserAutomation'],
|
|
242
|
+
operation: ['runMultipleProfiles'],
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
default: 100,
|
|
246
|
+
description: 'Window scale percentage (100 = 100%)',
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
displayName: 'Webhook URL',
|
|
250
|
+
name: 'webhookUrl',
|
|
251
|
+
type: 'string',
|
|
252
|
+
displayOptions: {
|
|
253
|
+
show: {
|
|
254
|
+
resource: ['browserAutomation'],
|
|
255
|
+
operation: ['runMultipleProfiles'],
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
default: '',
|
|
259
|
+
description: 'Webhook URL to send results to (optional)',
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
displayName: 'Webhook Method',
|
|
263
|
+
name: 'webhookMethod',
|
|
264
|
+
type: 'options',
|
|
265
|
+
displayOptions: {
|
|
266
|
+
show: {
|
|
267
|
+
resource: ['browserAutomation'],
|
|
268
|
+
operation: ['runMultipleProfiles'],
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
options: [
|
|
272
|
+
{
|
|
273
|
+
name: 'GET',
|
|
274
|
+
value: 'GET',
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
name: 'POST',
|
|
278
|
+
value: 'POST',
|
|
279
|
+
},
|
|
280
|
+
],
|
|
281
|
+
default: 'POST',
|
|
282
|
+
description: 'HTTP method to use for webhook call',
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
displayName: 'Timeout (Milliseconds)',
|
|
286
|
+
name: 'timeout',
|
|
287
|
+
type: 'number',
|
|
288
|
+
displayOptions: {
|
|
289
|
+
show: {
|
|
290
|
+
resource: ['browserAutomation'],
|
|
291
|
+
operation: ['runMultipleProfiles'],
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
default: 100000000,
|
|
295
|
+
description: 'Maximum timeout in milliseconds',
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
displayName: 'Wait For The Previous Session To Complete',
|
|
299
|
+
name: 'waitForPrevious',
|
|
300
|
+
type: 'boolean',
|
|
301
|
+
displayOptions: {
|
|
302
|
+
show: {
|
|
303
|
+
resource: ['browserAutomation'],
|
|
304
|
+
operation: ['runMultipleProfiles'],
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
default: true,
|
|
308
|
+
description: 'Whether to wait for previous session to complete before starting next',
|
|
309
|
+
},
|
|
131
310
|
// Create Profile Fields
|
|
132
311
|
{
|
|
133
312
|
displayName: 'Profile Name',
|
|
@@ -378,7 +557,7 @@ exports.nvkBrowserApiDescription = {
|
|
|
378
557
|
operation: ['updateProfile'],
|
|
379
558
|
},
|
|
380
559
|
},
|
|
381
|
-
default: '
|
|
560
|
+
default: '',
|
|
382
561
|
description: 'New proxy configuration',
|
|
383
562
|
},
|
|
384
563
|
{
|
|
@@ -392,7 +571,7 @@ exports.nvkBrowserApiDescription = {
|
|
|
392
571
|
},
|
|
393
572
|
},
|
|
394
573
|
default: '',
|
|
395
|
-
description: '
|
|
574
|
+
description: 'New note',
|
|
396
575
|
},
|
|
397
576
|
{
|
|
398
577
|
displayName: 'Extensions',
|
|
@@ -408,7 +587,7 @@ exports.nvkBrowserApiDescription = {
|
|
|
408
587
|
},
|
|
409
588
|
},
|
|
410
589
|
default: '',
|
|
411
|
-
description: '
|
|
590
|
+
description: 'New extensions (one per line)',
|
|
412
591
|
},
|
|
413
592
|
// Move and Click Fields
|
|
414
593
|
{
|
|
@@ -426,12 +605,9 @@ exports.nvkBrowserApiDescription = {
|
|
|
426
605
|
description: 'ID of the profile',
|
|
427
606
|
},
|
|
428
607
|
{
|
|
429
|
-
displayName: 'Selector
|
|
608
|
+
displayName: 'Selector',
|
|
430
609
|
name: 'selector',
|
|
431
610
|
type: 'string',
|
|
432
|
-
typeOptions: {
|
|
433
|
-
rows: 4,
|
|
434
|
-
},
|
|
435
611
|
displayOptions: {
|
|
436
612
|
show: {
|
|
437
613
|
resource: ['pageInteraction'],
|
|
@@ -440,7 +616,7 @@ exports.nvkBrowserApiDescription = {
|
|
|
440
616
|
},
|
|
441
617
|
default: '',
|
|
442
618
|
required: true,
|
|
443
|
-
description: 'CSS selector
|
|
619
|
+
description: 'CSS selector for the element',
|
|
444
620
|
},
|
|
445
621
|
{
|
|
446
622
|
displayName: 'Click Method',
|
|
@@ -454,19 +630,19 @@ exports.nvkBrowserApiDescription = {
|
|
|
454
630
|
},
|
|
455
631
|
options: [
|
|
456
632
|
{
|
|
457
|
-
name: 'Puppeteer
|
|
633
|
+
name: 'Puppeteer',
|
|
458
634
|
value: 'puppeteer',
|
|
459
635
|
},
|
|
460
636
|
{
|
|
461
|
-
name: '
|
|
462
|
-
value: '
|
|
637
|
+
name: 'Coordinates',
|
|
638
|
+
value: 'coordinates',
|
|
463
639
|
},
|
|
464
640
|
],
|
|
465
641
|
default: 'puppeteer',
|
|
466
|
-
description: 'Method for clicking',
|
|
642
|
+
description: 'Method to use for clicking',
|
|
467
643
|
},
|
|
468
644
|
{
|
|
469
|
-
displayName: 'Timeout
|
|
645
|
+
displayName: 'Timeout',
|
|
470
646
|
name: 'timeout',
|
|
471
647
|
type: 'number',
|
|
472
648
|
displayOptions: {
|
|
@@ -476,7 +652,7 @@ exports.nvkBrowserApiDescription = {
|
|
|
476
652
|
},
|
|
477
653
|
},
|
|
478
654
|
default: 30000,
|
|
479
|
-
description: '
|
|
655
|
+
description: 'Timeout in milliseconds',
|
|
480
656
|
},
|
|
481
657
|
{
|
|
482
658
|
displayName: 'Tab Index',
|
|
@@ -505,7 +681,7 @@ exports.nvkBrowserApiDescription = {
|
|
|
505
681
|
description: 'Whether to auto-start profile if not running',
|
|
506
682
|
},
|
|
507
683
|
{
|
|
508
|
-
displayName: 'Wait
|
|
684
|
+
displayName: 'Wait For Click',
|
|
509
685
|
name: 'waitForClick',
|
|
510
686
|
type: 'number',
|
|
511
687
|
displayOptions: {
|
|
@@ -515,10 +691,10 @@ exports.nvkBrowserApiDescription = {
|
|
|
515
691
|
},
|
|
516
692
|
},
|
|
517
693
|
default: 500,
|
|
518
|
-
description: '
|
|
694
|
+
description: 'Wait time before click in milliseconds',
|
|
519
695
|
},
|
|
520
696
|
{
|
|
521
|
-
displayName: '
|
|
697
|
+
displayName: 'Button',
|
|
522
698
|
name: 'button',
|
|
523
699
|
type: 'options',
|
|
524
700
|
displayOptions: {
|
|
@@ -571,7 +747,7 @@ exports.nvkBrowserApiDescription = {
|
|
|
571
747
|
description: 'Whether to upload a binary file',
|
|
572
748
|
},
|
|
573
749
|
{
|
|
574
|
-
displayName: '
|
|
750
|
+
displayName: 'Input Data Field Name',
|
|
575
751
|
name: 'binaryPropertyName',
|
|
576
752
|
type: 'string',
|
|
577
753
|
displayOptions: {
|
|
@@ -583,7 +759,7 @@ exports.nvkBrowserApiDescription = {
|
|
|
583
759
|
},
|
|
584
760
|
default: 'data',
|
|
585
761
|
required: true,
|
|
586
|
-
description: 'Name of the binary property
|
|
762
|
+
description: 'Name of the binary property',
|
|
587
763
|
},
|
|
588
764
|
// Run JavaScript Fields
|
|
589
765
|
{
|
|
@@ -659,7 +835,7 @@ exports.nvkBrowserApiDescription = {
|
|
|
659
835
|
description: 'ID of the profile',
|
|
660
836
|
},
|
|
661
837
|
{
|
|
662
|
-
displayName: 'Request
|
|
838
|
+
displayName: 'Request Filter',
|
|
663
839
|
name: 'requestFilter',
|
|
664
840
|
type: 'string',
|
|
665
841
|
displayOptions: {
|
|
@@ -691,24 +867,16 @@ exports.nvkBrowserApiDescription = {
|
|
|
691
867
|
name: 'Exact',
|
|
692
868
|
value: 'exact',
|
|
693
869
|
},
|
|
694
|
-
{
|
|
695
|
-
name: 'Starts With',
|
|
696
|
-
value: 'startsWith',
|
|
697
|
-
},
|
|
698
|
-
{
|
|
699
|
-
name: 'Ends With',
|
|
700
|
-
value: 'endsWith',
|
|
701
|
-
},
|
|
702
870
|
{
|
|
703
871
|
name: 'Regex',
|
|
704
872
|
value: 'regex',
|
|
705
873
|
},
|
|
706
874
|
],
|
|
707
875
|
default: 'contains',
|
|
708
|
-
description: '
|
|
876
|
+
description: 'Type of matching to use',
|
|
709
877
|
},
|
|
710
878
|
{
|
|
711
|
-
displayName: 'Timeout
|
|
879
|
+
displayName: 'Timeout',
|
|
712
880
|
name: 'timeout',
|
|
713
881
|
type: 'number',
|
|
714
882
|
displayOptions: {
|
|
@@ -718,7 +886,7 @@ exports.nvkBrowserApiDescription = {
|
|
|
718
886
|
},
|
|
719
887
|
},
|
|
720
888
|
default: 30000,
|
|
721
|
-
description: 'Timeout
|
|
889
|
+
description: 'Timeout in milliseconds',
|
|
722
890
|
},
|
|
723
891
|
{
|
|
724
892
|
displayName: 'Wait For Request',
|
|
@@ -862,6 +1030,99 @@ exports.nvkBrowserApiDescription = {
|
|
|
862
1030
|
default: 'formData',
|
|
863
1031
|
description: 'Type of body content',
|
|
864
1032
|
},
|
|
1033
|
+
// Get Recaptcha Token Fields
|
|
1034
|
+
{
|
|
1035
|
+
displayName: 'Profile ID',
|
|
1036
|
+
name: 'profileId',
|
|
1037
|
+
type: 'string',
|
|
1038
|
+
displayOptions: {
|
|
1039
|
+
show: {
|
|
1040
|
+
resource: ['pageInteraction'],
|
|
1041
|
+
operation: ['getRecaptchaToken'],
|
|
1042
|
+
},
|
|
1043
|
+
},
|
|
1044
|
+
default: '',
|
|
1045
|
+
required: true,
|
|
1046
|
+
description: 'ID of the profile',
|
|
1047
|
+
},
|
|
1048
|
+
{
|
|
1049
|
+
displayName: 'Site Key',
|
|
1050
|
+
name: 'siteKey',
|
|
1051
|
+
type: 'string',
|
|
1052
|
+
displayOptions: {
|
|
1053
|
+
show: {
|
|
1054
|
+
resource: ['pageInteraction'],
|
|
1055
|
+
operation: ['getRecaptchaToken'],
|
|
1056
|
+
},
|
|
1057
|
+
},
|
|
1058
|
+
default: '',
|
|
1059
|
+
description: 'reCAPTCHA site key (auto-detect if empty)',
|
|
1060
|
+
},
|
|
1061
|
+
{
|
|
1062
|
+
displayName: 'Tab Index',
|
|
1063
|
+
name: 'tabIndex',
|
|
1064
|
+
type: 'number',
|
|
1065
|
+
displayOptions: {
|
|
1066
|
+
show: {
|
|
1067
|
+
resource: ['pageInteraction'],
|
|
1068
|
+
operation: ['getRecaptchaToken'],
|
|
1069
|
+
},
|
|
1070
|
+
},
|
|
1071
|
+
default: 0,
|
|
1072
|
+
description: 'Browser tab index',
|
|
1073
|
+
},
|
|
1074
|
+
{
|
|
1075
|
+
displayName: 'Timeout',
|
|
1076
|
+
name: 'timeout',
|
|
1077
|
+
type: 'number',
|
|
1078
|
+
displayOptions: {
|
|
1079
|
+
show: {
|
|
1080
|
+
resource: ['pageInteraction'],
|
|
1081
|
+
operation: ['getRecaptchaToken'],
|
|
1082
|
+
},
|
|
1083
|
+
},
|
|
1084
|
+
default: 10000,
|
|
1085
|
+
description: 'Timeout in milliseconds',
|
|
1086
|
+
},
|
|
1087
|
+
{
|
|
1088
|
+
displayName: 'Action',
|
|
1089
|
+
name: 'action',
|
|
1090
|
+
type: 'string',
|
|
1091
|
+
displayOptions: {
|
|
1092
|
+
show: {
|
|
1093
|
+
resource: ['pageInteraction'],
|
|
1094
|
+
operation: ['getRecaptchaToken'],
|
|
1095
|
+
},
|
|
1096
|
+
},
|
|
1097
|
+
default: 'FLOW_GENERATION',
|
|
1098
|
+
description: 'reCAPTCHA action parameter',
|
|
1099
|
+
},
|
|
1100
|
+
{
|
|
1101
|
+
displayName: 'Max Retries',
|
|
1102
|
+
name: 'maxRetries',
|
|
1103
|
+
type: 'number',
|
|
1104
|
+
displayOptions: {
|
|
1105
|
+
show: {
|
|
1106
|
+
resource: ['pageInteraction'],
|
|
1107
|
+
operation: ['getRecaptchaToken'],
|
|
1108
|
+
},
|
|
1109
|
+
},
|
|
1110
|
+
default: 3,
|
|
1111
|
+
description: 'Maximum number of retry attempts',
|
|
1112
|
+
},
|
|
1113
|
+
{
|
|
1114
|
+
displayName: 'Auto Start Profile',
|
|
1115
|
+
name: 'autoStart',
|
|
1116
|
+
type: 'boolean',
|
|
1117
|
+
displayOptions: {
|
|
1118
|
+
show: {
|
|
1119
|
+
resource: ['pageInteraction'],
|
|
1120
|
+
operation: ['getRecaptchaToken'],
|
|
1121
|
+
},
|
|
1122
|
+
},
|
|
1123
|
+
default: false,
|
|
1124
|
+
description: 'Whether to auto-start profile if not running',
|
|
1125
|
+
},
|
|
865
1126
|
// n8n Binary File - Input Data Field Name
|
|
866
1127
|
{
|
|
867
1128
|
displayName: 'Input Data Field Name',
|
|
@@ -14,9 +14,26 @@ class NvkBrowserApi {
|
|
|
14
14
|
const environment = this.getNodeParameter('environment', i);
|
|
15
15
|
const resource = this.getNodeParameter('resource', i);
|
|
16
16
|
const operation = this.getNodeParameter('operation', i);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
// Handle Run Multiple Profiles - No API call, process locally in n8n
|
|
18
|
+
if (resource === 'browserAutomation' && operation === 'runMultipleProfiles') {
|
|
19
|
+
const result = await runMultipleProfiles.call(this, i);
|
|
20
|
+
returnData.push({
|
|
21
|
+
json: result,
|
|
22
|
+
pairedItem: { item: i },
|
|
23
|
+
});
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
// All other operations - Call API as before
|
|
27
|
+
let baseUrl;
|
|
28
|
+
if (environment === 'docker') {
|
|
29
|
+
baseUrl = 'http://host.docker.internal:3000';
|
|
30
|
+
}
|
|
31
|
+
else if (environment === 'tunnel') {
|
|
32
|
+
baseUrl = this.getNodeParameter('tunnelUrl', i).replace(/\/$/, '');
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
baseUrl = 'http://localhost:3000';
|
|
36
|
+
}
|
|
20
37
|
let endpoint = '';
|
|
21
38
|
let body = {};
|
|
22
39
|
if (resource === 'profileManagement') {
|
|
@@ -144,6 +161,23 @@ class NvkBrowserApi {
|
|
|
144
161
|
};
|
|
145
162
|
break;
|
|
146
163
|
}
|
|
164
|
+
case 'getRecaptchaToken': {
|
|
165
|
+
endpoint = '/api/recaptcha/get-token';
|
|
166
|
+
body = {
|
|
167
|
+
profileId: this.getNodeParameter('profileId', i),
|
|
168
|
+
tabIndex: this.getNodeParameter('tabIndex', i, 0),
|
|
169
|
+
timeout: this.getNodeParameter('timeout', i, 10000),
|
|
170
|
+
action: this.getNodeParameter('action', i, 'FLOW_GENERATION'),
|
|
171
|
+
maxRetries: this.getNodeParameter('maxRetries', i, 3),
|
|
172
|
+
autoStart: this.getNodeParameter('autoStart', i, false),
|
|
173
|
+
};
|
|
174
|
+
// Site key là optional
|
|
175
|
+
const siteKey = this.getNodeParameter('siteKey', i, '');
|
|
176
|
+
if (siteKey && siteKey.trim() !== '') {
|
|
177
|
+
body.siteKey = siteKey.trim();
|
|
178
|
+
}
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
147
181
|
case 'browserHttpRequest': {
|
|
148
182
|
endpoint = '/api/browser/request';
|
|
149
183
|
const method = this.getNodeParameter('method', i, 'GET');
|
|
@@ -306,3 +340,227 @@ class NvkBrowserApi {
|
|
|
306
340
|
}
|
|
307
341
|
}
|
|
308
342
|
exports.NvkBrowserApi = NvkBrowserApi;
|
|
343
|
+
/**
|
|
344
|
+
* Run Multiple Profiles - Process locally in n8n without API call
|
|
345
|
+
*/
|
|
346
|
+
async function runMultipleProfiles(itemIndex) {
|
|
347
|
+
// Get parameters
|
|
348
|
+
const data = this.getNodeParameter('data', itemIndex, '');
|
|
349
|
+
const numberOfThreads = this.getNodeParameter('numberOfThreads', itemIndex, 1);
|
|
350
|
+
const defineColumns = this.getNodeParameter('defineColumns', itemIndex, 3);
|
|
351
|
+
const defineRows = this.getNodeParameter('defineRows', itemIndex, 2);
|
|
352
|
+
const winScale = this.getNodeParameter('winScale', itemIndex, 100);
|
|
353
|
+
const webhookUrl = this.getNodeParameter('webhookUrl', itemIndex, '');
|
|
354
|
+
const webhookMethod = this.getNodeParameter('webhookMethod', itemIndex, 'POST');
|
|
355
|
+
const timeout = this.getNodeParameter('timeout', itemIndex, 100000000);
|
|
356
|
+
const waitForPrevious = this.getNodeParameter('waitForPrevious', itemIndex, true);
|
|
357
|
+
// Parse data into lines
|
|
358
|
+
const lines = data.trim().split('\n').filter((line) => line.trim() !== '');
|
|
359
|
+
const totalLines = lines.length;
|
|
360
|
+
// Calculate window size and position for grid layout
|
|
361
|
+
const screenWidth = 1920; // Default screen width
|
|
362
|
+
const screenHeight = 1080; // Default screen height
|
|
363
|
+
const windowWidth = Math.floor((screenWidth / defineColumns) * (winScale / 100));
|
|
364
|
+
const windowHeight = Math.floor((screenHeight / defineRows) * (winScale / 100));
|
|
365
|
+
// Prepare tasks
|
|
366
|
+
const tasks = lines.map((line, index) => {
|
|
367
|
+
const parts = line.split('|').map((p) => p.trim());
|
|
368
|
+
// Calculate grid position
|
|
369
|
+
const row = Math.floor(index / defineColumns);
|
|
370
|
+
const col = index % defineColumns;
|
|
371
|
+
const x = col * windowWidth;
|
|
372
|
+
const y = row * windowHeight;
|
|
373
|
+
return {
|
|
374
|
+
line,
|
|
375
|
+
parts,
|
|
376
|
+
threadId: index,
|
|
377
|
+
winPosition: `${x},${y}`,
|
|
378
|
+
winSize: `${windowWidth},${windowHeight}`,
|
|
379
|
+
};
|
|
380
|
+
});
|
|
381
|
+
const results = [];
|
|
382
|
+
let completedLines = 0;
|
|
383
|
+
// Helper function to send individual result to webhook
|
|
384
|
+
const sendToWebhook = async (result, index, total) => {
|
|
385
|
+
if (!webhookUrl || webhookUrl.trim() === '') {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
const cleanWebhookUrl = webhookUrl.trim();
|
|
389
|
+
try {
|
|
390
|
+
const payload = {
|
|
391
|
+
...result,
|
|
392
|
+
index: index + 1,
|
|
393
|
+
total,
|
|
394
|
+
timestamp: new Date().toISOString(),
|
|
395
|
+
};
|
|
396
|
+
console.log(`Sending result ${index + 1}/${total} to webhook (${webhookMethod}):`, cleanWebhookUrl);
|
|
397
|
+
if (webhookMethod === 'GET') {
|
|
398
|
+
// For GET, send each field as separate query parameter
|
|
399
|
+
const params = new URLSearchParams();
|
|
400
|
+
// Add basic fields
|
|
401
|
+
params.append('line', result.line);
|
|
402
|
+
params.append('threadId', String(result.threadId));
|
|
403
|
+
params.append('winPosition', result.winPosition);
|
|
404
|
+
params.append('winSize', result.winSize);
|
|
405
|
+
params.append('winScale', String(winScale)); // Add winScale from main params
|
|
406
|
+
params.append('success', String(result.success));
|
|
407
|
+
params.append('index', String(index + 1));
|
|
408
|
+
params.append('total', String(total));
|
|
409
|
+
params.append('timestamp', new Date().toISOString());
|
|
410
|
+
// Add response as JSON string (if exists)
|
|
411
|
+
if (result.response) {
|
|
412
|
+
params.append('response', JSON.stringify(result.response));
|
|
413
|
+
}
|
|
414
|
+
// Add error if exists
|
|
415
|
+
if (result.error) {
|
|
416
|
+
params.append('error', result.error);
|
|
417
|
+
}
|
|
418
|
+
const urlWithParams = `${cleanWebhookUrl}?${params.toString()}`;
|
|
419
|
+
await this.helpers.request({
|
|
420
|
+
method: 'GET',
|
|
421
|
+
url: urlWithParams,
|
|
422
|
+
json: true,
|
|
423
|
+
headers: {
|
|
424
|
+
'User-Agent': 'n8n-nvk-browser-api',
|
|
425
|
+
},
|
|
426
|
+
timeout: 30000,
|
|
427
|
+
resolveWithFullResponse: false,
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
else {
|
|
431
|
+
// For POST, send full payload in body
|
|
432
|
+
await this.helpers.request({
|
|
433
|
+
method: 'POST',
|
|
434
|
+
url: cleanWebhookUrl,
|
|
435
|
+
body: payload,
|
|
436
|
+
json: true,
|
|
437
|
+
headers: {
|
|
438
|
+
'Content-Type': 'application/json',
|
|
439
|
+
'User-Agent': 'n8n-nvk-browser-api',
|
|
440
|
+
},
|
|
441
|
+
timeout: 30000,
|
|
442
|
+
resolveWithFullResponse: false,
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
console.log(`✓ Result ${index + 1}/${total} sent successfully`);
|
|
446
|
+
}
|
|
447
|
+
catch (error) {
|
|
448
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
449
|
+
console.error(`✗ Failed to send result ${index + 1}/${total}:`, errorMessage);
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
// Process tasks
|
|
453
|
+
if (waitForPrevious) {
|
|
454
|
+
// Sequential processing - wait for each to complete
|
|
455
|
+
for (let taskIndex = 0; taskIndex < tasks.length; taskIndex++) {
|
|
456
|
+
const task = tasks[taskIndex];
|
|
457
|
+
try {
|
|
458
|
+
const result = await processProfileTask(task);
|
|
459
|
+
results.push(result);
|
|
460
|
+
completedLines++;
|
|
461
|
+
// Send to webhook immediately after processing
|
|
462
|
+
await sendToWebhook(result, taskIndex, tasks.length);
|
|
463
|
+
}
|
|
464
|
+
catch (error) {
|
|
465
|
+
const errorResult = {
|
|
466
|
+
line: task.line,
|
|
467
|
+
threadId: task.threadId,
|
|
468
|
+
winPosition: task.winPosition,
|
|
469
|
+
winSize: task.winSize,
|
|
470
|
+
success: false,
|
|
471
|
+
error: error instanceof Error ? error.message : String(error),
|
|
472
|
+
};
|
|
473
|
+
results.push(errorResult);
|
|
474
|
+
completedLines++;
|
|
475
|
+
// Send error result to webhook too
|
|
476
|
+
await sendToWebhook(errorResult, taskIndex, tasks.length);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
// Parallel processing with thread limit
|
|
482
|
+
const processInBatches = async (tasks, batchSize) => {
|
|
483
|
+
for (let i = 0; i < tasks.length; i += batchSize) {
|
|
484
|
+
const batch = tasks.slice(i, i + batchSize);
|
|
485
|
+
const batchPromises = batch.map(async (task, batchIndex) => {
|
|
486
|
+
const taskIndex = i + batchIndex;
|
|
487
|
+
try {
|
|
488
|
+
const result = await processProfileTask(task);
|
|
489
|
+
results.push(result);
|
|
490
|
+
completedLines++;
|
|
491
|
+
// Send to webhook immediately after processing
|
|
492
|
+
await sendToWebhook(result, taskIndex, tasks.length);
|
|
493
|
+
return result;
|
|
494
|
+
}
|
|
495
|
+
catch (error) {
|
|
496
|
+
const errorResult = {
|
|
497
|
+
line: task.line,
|
|
498
|
+
threadId: task.threadId,
|
|
499
|
+
winPosition: task.winPosition,
|
|
500
|
+
winSize: task.winSize,
|
|
501
|
+
success: false,
|
|
502
|
+
error: error instanceof Error ? error.message : String(error),
|
|
503
|
+
};
|
|
504
|
+
results.push(errorResult);
|
|
505
|
+
completedLines++;
|
|
506
|
+
// Send error result to webhook too
|
|
507
|
+
await sendToWebhook(errorResult, taskIndex, tasks.length);
|
|
508
|
+
return errorResult;
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
await Promise.all(batchPromises);
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
await processInBatches(tasks, numberOfThreads);
|
|
515
|
+
}
|
|
516
|
+
// Prepare final response
|
|
517
|
+
const finalResponse = {
|
|
518
|
+
totalLines,
|
|
519
|
+
completedLines,
|
|
520
|
+
results,
|
|
521
|
+
timeout,
|
|
522
|
+
defineColumn: defineColumns,
|
|
523
|
+
defineRow: defineRows,
|
|
524
|
+
message: `All ${completedLines} threads completed with grid ${defineColumns}x${defineRows}, maximum timeout ${timeout}ms`,
|
|
525
|
+
};
|
|
526
|
+
// Add webhook summary if webhook was used
|
|
527
|
+
if (webhookUrl && webhookUrl.trim() !== '') {
|
|
528
|
+
finalResponse.webhookSummary = {
|
|
529
|
+
enabled: true,
|
|
530
|
+
url: webhookUrl.trim(),
|
|
531
|
+
method: webhookMethod,
|
|
532
|
+
totalSent: completedLines,
|
|
533
|
+
message: `Sent ${completedLines} individual results to webhook`,
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
finalResponse.webhookSummary = {
|
|
538
|
+
enabled: false,
|
|
539
|
+
message: 'No webhook URL provided',
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
return finalResponse;
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Process a single profile task
|
|
546
|
+
*/
|
|
547
|
+
async function processProfileTask(task) {
|
|
548
|
+
// Simulate processing - parse the data
|
|
549
|
+
const responseData = [];
|
|
550
|
+
// Parse each part from the line (separated by |)
|
|
551
|
+
task.parts.forEach((part, index) => {
|
|
552
|
+
const obj = {};
|
|
553
|
+
obj[`part${index + 1}`] = part;
|
|
554
|
+
responseData.push(obj);
|
|
555
|
+
});
|
|
556
|
+
// Simulate some delay (optional)
|
|
557
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
558
|
+
return {
|
|
559
|
+
line: task.line,
|
|
560
|
+
threadId: task.threadId,
|
|
561
|
+
winPosition: task.winPosition,
|
|
562
|
+
winSize: task.winSize,
|
|
563
|
+
success: true,
|
|
564
|
+
response: responseData,
|
|
565
|
+
};
|
|
566
|
+
}
|