n8n-nodes-nvk-call-api 0.0.6 → 0.0.8

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.
@@ -12,6 +12,20 @@ exports.nvkBrowserApiDescription = {
12
12
  defaults: {
13
13
  name: 'NVK Browser Call API',
14
14
  },
15
+ codex: {
16
+ categories: ['Development'],
17
+ subcategories: {
18
+ Development: ['Browser Automation'],
19
+ },
20
+ resources: {
21
+ primaryDocumentation: [
22
+ {
23
+ url: 'https://your-docs-url.com',
24
+ },
25
+ ],
26
+ },
27
+ alias: ['Run Multiple Profiles', 'requests', 'HTTP', 'HTTP requests', 'Make HTTP requests using Browser', 'HTTP requests using Browser', 'Get Network Response', 'Move And Click', 'Download Browser', 'Update Profile', 'Stop Profile', 'Delete Profile', 'Create profile', 'recaptcha', 'captcha', 'token', 'get recaptcha token', 'recaptcha solver', 'browser', 'automation', 'puppeteer'],
28
+ },
15
29
  inputs: ['main'],
16
30
  outputs: ['main'],
17
31
  credentials: [],
@@ -65,6 +79,10 @@ exports.nvkBrowserApiDescription = {
65
79
  name: 'Page Interaction',
66
80
  value: 'pageInteraction',
67
81
  },
82
+ {
83
+ name: 'Browser Automation',
84
+ value: 'browserAutomation',
85
+ },
68
86
  ],
69
87
  default: 'profileManagement',
70
88
  },
@@ -143,9 +161,166 @@ exports.nvkBrowserApiDescription = {
143
161
  value: 'browserHttpRequest',
144
162
  action: 'Make HTTP requests using Browser',
145
163
  },
164
+ {
165
+ name: 'Get Recaptcha Token',
166
+ value: 'getRecaptchaToken',
167
+ action: 'Get Recaptcha Token',
168
+ },
146
169
  ],
147
170
  default: 'moveAndClick',
148
171
  },
172
+ {
173
+ displayName: 'Operation',
174
+ name: 'operation',
175
+ type: 'options',
176
+ noDataExpression: true,
177
+ displayOptions: {
178
+ show: {
179
+ resource: ['browserAutomation'],
180
+ },
181
+ },
182
+ options: [
183
+ {
184
+ name: 'Run Multiple Profiles',
185
+ value: 'runMultipleProfiles',
186
+ action: 'Run Multiple Profiles',
187
+ },
188
+ ],
189
+ default: 'runMultipleProfiles',
190
+ },
191
+ // Run Multiple Profiles Fields
192
+ {
193
+ displayName: 'Data',
194
+ name: 'data',
195
+ type: 'string',
196
+ typeOptions: {
197
+ rows: 10,
198
+ },
199
+ displayOptions: {
200
+ show: {
201
+ resource: ['browserAutomation'],
202
+ operation: ['runMultipleProfiles'],
203
+ },
204
+ },
205
+ default: '',
206
+ required: true,
207
+ description: 'Enter data in format: line|profileId (one per line)',
208
+ placeholder: '1|212e2d01-0c8a-4373-9c9f-9153354de0a4\n2|212e2d01-0c8a-4373-9c9f-9153354de0a4',
209
+ },
210
+ {
211
+ displayName: 'Number of Threads',
212
+ name: 'numberOfThreads',
213
+ type: 'number',
214
+ displayOptions: {
215
+ show: {
216
+ resource: ['browserAutomation'],
217
+ operation: ['runMultipleProfiles'],
218
+ },
219
+ },
220
+ default: 1,
221
+ description: 'Number of parallel threads to run',
222
+ },
223
+ {
224
+ displayName: 'Define Columns',
225
+ name: 'defineColumns',
226
+ type: 'number',
227
+ displayOptions: {
228
+ show: {
229
+ resource: ['browserAutomation'],
230
+ operation: ['runMultipleProfiles'],
231
+ },
232
+ },
233
+ default: 3,
234
+ description: 'Number of columns in grid layout',
235
+ },
236
+ {
237
+ displayName: 'Define Rows',
238
+ name: 'defineRows',
239
+ type: 'number',
240
+ displayOptions: {
241
+ show: {
242
+ resource: ['browserAutomation'],
243
+ operation: ['runMultipleProfiles'],
244
+ },
245
+ },
246
+ default: 2,
247
+ description: 'Number of rows in grid layout',
248
+ },
249
+ {
250
+ displayName: 'Win Scale',
251
+ name: 'winScale',
252
+ type: 'number',
253
+ displayOptions: {
254
+ show: {
255
+ resource: ['browserAutomation'],
256
+ operation: ['runMultipleProfiles'],
257
+ },
258
+ },
259
+ default: 100,
260
+ description: 'Window scale percentage (100 = 100%)',
261
+ },
262
+ {
263
+ displayName: 'Webhook URL',
264
+ name: 'webhookUrl',
265
+ type: 'string',
266
+ displayOptions: {
267
+ show: {
268
+ resource: ['browserAutomation'],
269
+ operation: ['runMultipleProfiles'],
270
+ },
271
+ },
272
+ default: '',
273
+ description: 'Webhook URL to send results to (optional)',
274
+ },
275
+ {
276
+ displayName: 'Webhook Method',
277
+ name: 'webhookMethod',
278
+ type: 'options',
279
+ displayOptions: {
280
+ show: {
281
+ resource: ['browserAutomation'],
282
+ operation: ['runMultipleProfiles'],
283
+ },
284
+ },
285
+ options: [
286
+ {
287
+ name: 'GET',
288
+ value: 'GET',
289
+ },
290
+ {
291
+ name: 'POST',
292
+ value: 'POST',
293
+ },
294
+ ],
295
+ default: 'POST',
296
+ description: 'HTTP method to use for webhook call',
297
+ },
298
+ {
299
+ displayName: 'Timeout (Milliseconds)',
300
+ name: 'timeout',
301
+ type: 'number',
302
+ displayOptions: {
303
+ show: {
304
+ resource: ['browserAutomation'],
305
+ operation: ['runMultipleProfiles'],
306
+ },
307
+ },
308
+ default: 100000000,
309
+ description: 'Maximum timeout in milliseconds',
310
+ },
311
+ {
312
+ displayName: 'Wait For The Previous Session To Complete',
313
+ name: 'waitForPrevious',
314
+ type: 'boolean',
315
+ displayOptions: {
316
+ show: {
317
+ resource: ['browserAutomation'],
318
+ operation: ['runMultipleProfiles'],
319
+ },
320
+ },
321
+ default: true,
322
+ description: 'Whether to wait for previous session to complete before starting next',
323
+ },
149
324
  // Create Profile Fields
150
325
  {
151
326
  displayName: 'Profile Name',
@@ -396,7 +571,7 @@ exports.nvkBrowserApiDescription = {
396
571
  operation: ['updateProfile'],
397
572
  },
398
573
  },
399
- default: 'http:127.0.0.1:8080:user:pass hoặc socks5:127.0.0.1:1080:user:pass',
574
+ default: '',
400
575
  description: 'New proxy configuration',
401
576
  },
402
577
  {
@@ -410,7 +585,7 @@ exports.nvkBrowserApiDescription = {
410
585
  },
411
586
  },
412
587
  default: '',
413
- description: 'Updated notes',
588
+ description: 'New note',
414
589
  },
415
590
  {
416
591
  displayName: 'Extensions',
@@ -426,7 +601,7 @@ exports.nvkBrowserApiDescription = {
426
601
  },
427
602
  },
428
603
  default: '',
429
- description: 'Updated extensions',
604
+ description: 'New extensions (one per line)',
430
605
  },
431
606
  // Move and Click Fields
432
607
  {
@@ -444,12 +619,9 @@ exports.nvkBrowserApiDescription = {
444
619
  description: 'ID of the profile',
445
620
  },
446
621
  {
447
- displayName: 'Selector or Puppeteer Locator Code',
622
+ displayName: 'Selector',
448
623
  name: 'selector',
449
624
  type: 'string',
450
- typeOptions: {
451
- rows: 4,
452
- },
453
625
  displayOptions: {
454
626
  show: {
455
627
  resource: ['pageInteraction'],
@@ -458,7 +630,7 @@ exports.nvkBrowserApiDescription = {
458
630
  },
459
631
  default: '',
460
632
  required: true,
461
- description: 'CSS selector or Puppeteer locator code',
633
+ description: 'CSS selector for the element',
462
634
  },
463
635
  {
464
636
  displayName: 'Click Method',
@@ -472,19 +644,19 @@ exports.nvkBrowserApiDescription = {
472
644
  },
473
645
  options: [
474
646
  {
475
- name: 'Puppeteer Locator',
647
+ name: 'Puppeteer',
476
648
  value: 'puppeteer',
477
649
  },
478
650
  {
479
- name: 'Standard',
480
- value: 'standard',
651
+ name: 'Coordinates',
652
+ value: 'coordinates',
481
653
  },
482
654
  ],
483
655
  default: 'puppeteer',
484
- description: 'Method for clicking',
656
+ description: 'Method to use for clicking',
485
657
  },
486
658
  {
487
- displayName: 'Timeout (Milliseconds)',
659
+ displayName: 'Timeout',
488
660
  name: 'timeout',
489
661
  type: 'number',
490
662
  displayOptions: {
@@ -494,7 +666,7 @@ exports.nvkBrowserApiDescription = {
494
666
  },
495
667
  },
496
668
  default: 30000,
497
- description: 'Maximum wait time',
669
+ description: 'Timeout in milliseconds',
498
670
  },
499
671
  {
500
672
  displayName: 'Tab Index',
@@ -523,7 +695,7 @@ exports.nvkBrowserApiDescription = {
523
695
  description: 'Whether to auto-start profile if not running',
524
696
  },
525
697
  {
526
- displayName: 'Wait Before Click (Milliseconds)',
698
+ displayName: 'Wait For Click',
527
699
  name: 'waitForClick',
528
700
  type: 'number',
529
701
  displayOptions: {
@@ -533,10 +705,10 @@ exports.nvkBrowserApiDescription = {
533
705
  },
534
706
  },
535
707
  default: 500,
536
- description: 'Delay before clicking',
708
+ description: 'Wait time before click in milliseconds',
537
709
  },
538
710
  {
539
- displayName: 'Mouse Button',
711
+ displayName: 'Button',
540
712
  name: 'button',
541
713
  type: 'options',
542
714
  displayOptions: {
@@ -589,7 +761,7 @@ exports.nvkBrowserApiDescription = {
589
761
  description: 'Whether to upload a binary file',
590
762
  },
591
763
  {
592
- displayName: 'Binary Property',
764
+ displayName: 'Input Data Field Name',
593
765
  name: 'binaryPropertyName',
594
766
  type: 'string',
595
767
  displayOptions: {
@@ -601,7 +773,7 @@ exports.nvkBrowserApiDescription = {
601
773
  },
602
774
  default: 'data',
603
775
  required: true,
604
- description: 'Name of the binary property containing the file',
776
+ description: 'Name of the binary property',
605
777
  },
606
778
  // Run JavaScript Fields
607
779
  {
@@ -677,7 +849,7 @@ exports.nvkBrowserApiDescription = {
677
849
  description: 'ID of the profile',
678
850
  },
679
851
  {
680
- displayName: 'Request Name or URL',
852
+ displayName: 'Request Filter',
681
853
  name: 'requestFilter',
682
854
  type: 'string',
683
855
  displayOptions: {
@@ -709,24 +881,16 @@ exports.nvkBrowserApiDescription = {
709
881
  name: 'Exact',
710
882
  value: 'exact',
711
883
  },
712
- {
713
- name: 'Starts With',
714
- value: 'startsWith',
715
- },
716
- {
717
- name: 'Ends With',
718
- value: 'endsWith',
719
- },
720
884
  {
721
885
  name: 'Regex',
722
886
  value: 'regex',
723
887
  },
724
888
  ],
725
889
  default: 'contains',
726
- description: 'How to match the request filter',
890
+ description: 'Type of matching to use',
727
891
  },
728
892
  {
729
- displayName: 'Timeout (Milliseconds)',
893
+ displayName: 'Timeout',
730
894
  name: 'timeout',
731
895
  type: 'number',
732
896
  displayOptions: {
@@ -736,7 +900,7 @@ exports.nvkBrowserApiDescription = {
736
900
  },
737
901
  },
738
902
  default: 30000,
739
- description: 'Timeout for waiting',
903
+ description: 'Timeout in milliseconds',
740
904
  },
741
905
  {
742
906
  displayName: 'Wait For Request',
@@ -880,6 +1044,99 @@ exports.nvkBrowserApiDescription = {
880
1044
  default: 'formData',
881
1045
  description: 'Type of body content',
882
1046
  },
1047
+ // Get Recaptcha Token Fields
1048
+ {
1049
+ displayName: 'Profile ID',
1050
+ name: 'profileId',
1051
+ type: 'string',
1052
+ displayOptions: {
1053
+ show: {
1054
+ resource: ['pageInteraction'],
1055
+ operation: ['getRecaptchaToken'],
1056
+ },
1057
+ },
1058
+ default: '',
1059
+ required: true,
1060
+ description: 'ID of the profile',
1061
+ },
1062
+ {
1063
+ displayName: 'Site Key',
1064
+ name: 'siteKey',
1065
+ type: 'string',
1066
+ displayOptions: {
1067
+ show: {
1068
+ resource: ['pageInteraction'],
1069
+ operation: ['getRecaptchaToken'],
1070
+ },
1071
+ },
1072
+ default: '',
1073
+ description: 'reCAPTCHA site key (auto-detect if empty)',
1074
+ },
1075
+ {
1076
+ displayName: 'Tab Index',
1077
+ name: 'tabIndex',
1078
+ type: 'number',
1079
+ displayOptions: {
1080
+ show: {
1081
+ resource: ['pageInteraction'],
1082
+ operation: ['getRecaptchaToken'],
1083
+ },
1084
+ },
1085
+ default: 0,
1086
+ description: 'Browser tab index',
1087
+ },
1088
+ {
1089
+ displayName: 'Timeout',
1090
+ name: 'timeout',
1091
+ type: 'number',
1092
+ displayOptions: {
1093
+ show: {
1094
+ resource: ['pageInteraction'],
1095
+ operation: ['getRecaptchaToken'],
1096
+ },
1097
+ },
1098
+ default: 10000,
1099
+ description: 'Timeout in milliseconds',
1100
+ },
1101
+ {
1102
+ displayName: 'Action',
1103
+ name: 'action',
1104
+ type: 'string',
1105
+ displayOptions: {
1106
+ show: {
1107
+ resource: ['pageInteraction'],
1108
+ operation: ['getRecaptchaToken'],
1109
+ },
1110
+ },
1111
+ default: 'FLOW_GENERATION',
1112
+ description: 'reCAPTCHA action parameter',
1113
+ },
1114
+ {
1115
+ displayName: 'Max Retries',
1116
+ name: 'maxRetries',
1117
+ type: 'number',
1118
+ displayOptions: {
1119
+ show: {
1120
+ resource: ['pageInteraction'],
1121
+ operation: ['getRecaptchaToken'],
1122
+ },
1123
+ },
1124
+ default: 3,
1125
+ description: 'Maximum number of retry attempts',
1126
+ },
1127
+ {
1128
+ displayName: 'Auto Start Profile',
1129
+ name: 'autoStart',
1130
+ type: 'boolean',
1131
+ displayOptions: {
1132
+ show: {
1133
+ resource: ['pageInteraction'],
1134
+ operation: ['getRecaptchaToken'],
1135
+ },
1136
+ },
1137
+ default: false,
1138
+ description: 'Whether to auto-start profile if not running',
1139
+ },
883
1140
  // n8n Binary File - Input Data Field Name
884
1141
  {
885
1142
  displayName: 'Input Data Field Name',
@@ -14,6 +14,16 @@ 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
+ // 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
17
27
  let baseUrl;
18
28
  if (environment === 'docker') {
19
29
  baseUrl = 'http://host.docker.internal:3000';
@@ -151,6 +161,23 @@ class NvkBrowserApi {
151
161
  };
152
162
  break;
153
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
+ }
154
181
  case 'browserHttpRequest': {
155
182
  endpoint = '/api/browser/request';
156
183
  const method = this.getNodeParameter('method', i, 'GET');
@@ -313,3 +340,227 @@ class NvkBrowserApi {
313
340
  }
314
341
  }
315
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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-nvk-call-api",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "n8n node for NVK Browser automation API",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",