n8n-nodes-kingsoft-airscript 2.0.4 → 2.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.
@@ -71,6 +71,49 @@ class KingsoftAirscript {
71
71
  default: '',
72
72
  description: '支持同步/异步执行脚本、自动分批处理和智能参数生成。',
73
73
  },
74
+ {
75
+ displayName: '数据输入模式',
76
+ name: 'payloadMode',
77
+ type: 'options',
78
+ default: 'argvFromUI',
79
+ options: [
80
+ {
81
+ name: '从 UI 配置 Argv(当前方式)',
82
+ value: 'argvFromUI',
83
+ description: 'Argv 完全由 UI 中的 JSON 模板决定,适合固定参数场景'
84
+ },
85
+ {
86
+ name: '从输入项直接作为 Argv',
87
+ value: 'argvFromItem',
88
+ description: '每个输入项的 $JSON 直接作为 argv,适合上游已整理好结构的场景'
89
+ },
90
+ {
91
+ name: '追加输入项到 Argv 数组字段',
92
+ value: 'appendItemsToArrayField',
93
+ description: '将所有输入项聚合成数组写入 argv,适合批量处理场景(只执行一次)'
94
+ },
95
+ ],
96
+ description: '选择如何将 n8n 输入数据传递给脚本。',
97
+ displayOptions: { show: { operation: ['runScriptSync', 'runScriptAsync'] } },
98
+ },
99
+ {
100
+ displayName: '目标数组字段路径',
101
+ name: 'targetArrayField',
102
+ type: 'string',
103
+ default: 'data',
104
+ hint: '例如:data 或 写表行列表',
105
+ description: '当选择「追加输入项到 argv 数组字段」时,指定 argv 中的目标数组字段。例如设置为 "data",则所有输入项会被聚合到 argv.data 数组中。',
106
+ displayOptions: { show: { operation: ['runScriptSync', 'runScriptAsync'], payloadMode: ['appendItemsToArrayField'] } },
107
+ },
108
+ {
109
+ displayName: '项目数据字段路径',
110
+ name: 'itemDataPath',
111
+ type: 'string',
112
+ default: '',
113
+ hint: '留空表示使用整个 $json',
114
+ description: '当选择「从输入项直接作为 argv」或「追加输入项到 argv 数组字段」时,指定从输入项中提取数据的字段路径。例如设置为 "payload",则会使用 $JSON.payload 作为数据来源。',
115
+ displayOptions: { show: { operation: ['runScriptSync', 'runScriptAsync'], payloadMode: ['argvFromItem', 'appendItemsToArrayField'] } },
116
+ },
74
117
  {
75
118
  displayName: '操作',
76
119
  name: 'operation',
@@ -188,7 +231,7 @@ class KingsoftAirscript {
188
231
  default: '{\n "message": "Hello from n8n!"\n}',
189
232
  required: true,
190
233
  displayOptions: { show: { operation: ['runScriptSync', 'runScriptAsync'], argvTemplate: ['custom'] } },
191
- description: '自定义 JSON 参数',
234
+ description: '自定义 JSON 参数。 数据输入模式说明: - argvFromUI:完全使用此模板作为 argv - argvFromItem:此模板被忽略,使用输入项的 $JSON - appendItemsToArrayField:此模板作为基础,输入项会被聚合成数组添加到指定字段',
192
235
  },
193
236
  {
194
237
  displayName: '脚本参数 (Argv)',
@@ -319,7 +362,7 @@ class KingsoftAirscript {
319
362
  type: 'number',
320
363
  default: 300,
321
364
  typeOptions: { minValue: 5 },
322
- displayOptions: { show: { '/operation': ['runScriptAsync'], '/c_waitForCompletion': [true] } },
365
+ displayOptions: { show: { '/operation': ['runScriptAsync'], '/options/c_waitForCompletion': [true] } },
323
366
  description: '异步等待完成模式下,最多等待的总时长(秒)。',
324
367
  },
325
368
  {
@@ -346,7 +389,7 @@ class KingsoftAirscript {
346
389
  { name: '逐批输出(推荐)', value: 'split' },
347
390
  { name: '合并为一个 Item(批次输出列表)', value: 'merge' },
348
391
  ],
349
- displayOptions: { show: { '/r_autoChunkEnabled': [true] } },
392
+ displayOptions: { show: { '/options/r_autoChunkEnabled': [true] } },
350
393
  description: '自动分批时的输出策略。',
351
394
  },
352
395
  {
@@ -356,7 +399,7 @@ class KingsoftAirscript {
356
399
  default: '写表行列表',
357
400
  hint: '指定包含大量数据的数组字段',
358
401
  description: '例:写表行列表 或 data.写表行列表(从 argv 根开始)',
359
- displayOptions: { show: { '/r_autoChunkEnabled': [true] } },
402
+ displayOptions: { show: { '/options/r_autoChunkEnabled': [true] } },
360
403
  },
361
404
  {
362
405
  displayName: '分批最大并发数(同一 Item 内)',
@@ -364,7 +407,7 @@ class KingsoftAirscript {
364
407
  type: 'number',
365
408
  default: 3,
366
409
  typeOptions: { minValue: 1, maxValue: 20 },
367
- displayOptions: { show: { '/r_autoChunkEnabled': [true] } },
410
+ displayOptions: { show: { '/options/r_autoChunkEnabled': [true] } },
368
411
  description: '自动分批时,同一输入 item 内批次执行的最大并发数。',
369
412
  },
370
413
  {
@@ -381,7 +424,7 @@ class KingsoftAirscript {
381
424
  type: 'number',
382
425
  default: 5,
383
426
  typeOptions: { minValue: 1 },
384
- displayOptions: { show: { '/operation': ['runScriptAsync'], '/c_waitForCompletion': [true] } },
427
+ displayOptions: { show: { '/operation': ['runScriptAsync'], '/options/c_waitForCompletion': [true] } },
385
428
  description: '异步等待完成模式下的轮询间隔(秒)。',
386
429
  },
387
430
  {
@@ -391,7 +434,7 @@ class KingsoftAirscript {
391
434
  default: 200,
392
435
  hint: '处理大量数据时建议减小此值',
393
436
  typeOptions: { minValue: 1 },
394
- displayOptions: { show: { '/r_autoChunkEnabled': [true] } },
437
+ displayOptions: { show: { '/options/r_autoChunkEnabled': [true] } },
395
438
  description: '自动分批时,每批数组元素数量。',
396
439
  },
397
440
  {
@@ -400,7 +443,7 @@ class KingsoftAirscript {
400
443
  type: 'number',
401
444
  default: 10,
402
445
  typeOptions: { minValue: 1 },
403
- displayOptions: { show: { '/a_parallelExecution': [true] } },
446
+ displayOptions: { show: { '/options/a_parallelExecution': [true] } },
404
447
  description: '并行执行开启时,每批并发处理的输入 item 数量。',
405
448
  },
406
449
  {
@@ -496,8 +539,57 @@ class KingsoftAirscript {
496
539
  async execute() {
497
540
  const 输入数据项列表 = this.getInputData();
498
541
  const 凭证 = (await this.getCredentials('kingsoftAirscriptApi'));
542
+ const 读取高级选项 = (索引) => {
543
+ const raw = this.getNodeParameter('options', 索引, {});
544
+ const 取数 = (k, d) => {
545
+ const v = raw[k];
546
+ const n = typeof v === 'number' ? v : Number(v);
547
+ return Number.isFinite(n) ? n : d;
548
+ };
549
+ const 取布尔 = (k, d) => {
550
+ const v = raw[k];
551
+ return typeof v === 'boolean' ? v : d;
552
+ };
553
+ const 取字符串 = (k, d) => {
554
+ const v = raw[k];
555
+ return typeof v === 'string' ? v : d;
556
+ };
557
+ return {
558
+ a_parallelExecution: 取布尔('a_parallelExecution', false),
559
+ b_timeoutSeconds: 取数('b_timeoutSeconds', 300),
560
+ c_waitForCompletion: 取布尔('c_waitForCompletion', false),
561
+ d_pollIntervalSeconds: 取数('d_pollIntervalSeconds', 5),
562
+ e_batchSize: 取数('e_batchSize', 10),
563
+ f_outputFormat: 取字符串('f_outputFormat', 'fullResponse'),
564
+ g_parseResultString: 取布尔('g_parseResultString', false),
565
+ x_globalMaxConcurrency: 取数('x_globalMaxConcurrency', 5),
566
+ h_requestTimeoutSeconds: 取数('h_requestTimeoutSeconds', 120),
567
+ i_statusTimeoutSeconds: 取数('i_statusTimeoutSeconds', 30),
568
+ j_maxRetries: 取数('j_maxRetries', 2),
569
+ k_retryInitialDelayMs: 取数('k_retryInitialDelayMs', 800),
570
+ l_retryBackoffFactor: 取数('l_retryBackoffFactor', 2),
571
+ m_honorRetryAfter: 取布尔('m_honorRetryAfter', true),
572
+ n_failOnScriptError: 取布尔('n_failOnScriptError', true),
573
+ o_pollJitterMs: 取数('o_pollJitterMs', 300),
574
+ r_autoChunkEnabled: 取布尔('r_autoChunkEnabled', false),
575
+ s_chunkFieldPath: 取字符串('s_chunkFieldPath', '写表行列表'),
576
+ t_chunkSize: 取数('t_chunkSize', 200),
577
+ u_chunkMaxConcurrency: 取数('u_chunkMaxConcurrency', 3),
578
+ v_chunkOutputMode: 取字符串('v_chunkOutputMode', 'split'),
579
+ w_debug: 取布尔('w_debug', false),
580
+ };
581
+ };
582
+ const opt0 = 读取高级选项(0);
583
+ const 全局并发闸门 = 创建并发闸门(Math.max(1, opt0.x_globalMaxConcurrency));
499
584
  const 等待毫秒 = async (ms) => {
500
- await this.helpers.sleep(ms);
585
+ if (ms <= 0)
586
+ return;
587
+ const 开始时间 = Date.now();
588
+ while (Date.now() - 开始时间 < ms) {
589
+ await new Promise((resolve) => {
590
+ Promise.resolve().then(() => resolve());
591
+ });
592
+ }
501
593
  };
502
594
  const 脱敏ID = (id) => {
503
595
  const s = (id !== null && id !== void 0 ? id : '').toString();
@@ -522,9 +614,20 @@ class KingsoftAirscript {
522
614
  const 是IDataObject = (v) => {
523
615
  return typeof v === 'object' && v !== null && !Array.isArray(v);
524
616
  };
617
+ const getStatusCode = (err) => {
618
+ var _a, _b, _c, _d;
619
+ return (_c = (_b = (_a = err.response) === null || _a === void 0 ? void 0 : _a.status) !== null && _b !== void 0 ? _b : err.statusCode) !== null && _c !== void 0 ? _c : (_d = err.response) === null || _d === void 0 ? void 0 : _d.statusCode;
620
+ };
621
+ const getBody = (err) => {
622
+ var _a, _b, _c, _d;
623
+ return ((_c = (_b = (_a = err.response) === null || _a === void 0 ? void 0 : _a.data) !== null && _b !== void 0 ? _b : err.body) !== null && _c !== void 0 ? _c : (_d = err.response) === null || _d === void 0 ? void 0 : _d.body);
624
+ };
625
+ const getHeaders = (err) => {
626
+ var _a, _b, _c, _d;
627
+ return (_c = (_b = (_a = err.response) === null || _a === void 0 ? void 0 : _a.headers) !== null && _b !== void 0 ? _b : err.headers) !== null && _c !== void 0 ? _c : (_d = err.response) === null || _d === void 0 ? void 0 : _d.headers;
628
+ };
525
629
  const 提取错误消息 = (err) => {
526
- var _a;
527
- const data = (_a = err.response) === null || _a === void 0 ? void 0 : _a.data;
630
+ const data = getBody(err);
528
631
  if (是IDataObject(data)) {
529
632
  const errorDetails = data.error_details;
530
633
  if (是IDataObject(errorDetails)) {
@@ -541,15 +644,14 @@ class KingsoftAirscript {
541
644
  return '未知错误';
542
645
  };
543
646
  const 判断是否可重试 = (e) => {
544
- var _a;
545
647
  const err = 提取Http错误(e);
546
648
  const 错误码 = err.code;
547
- const 状态码 = (_a = err.response) === null || _a === void 0 ? void 0 : _a.status;
649
+ const 状态码 = getStatusCode(err);
548
650
  return (['ETIMEDOUT', 'ECONNRESET', 'EAI_AGAIN', 'ECONNREFUSED', 'ECONNABORTED'].includes(String(错误码 !== null && 错误码 !== void 0 ? 错误码 : '')) ||
549
651
  [408, 425, 429, 500, 502, 503, 504].includes(Number(状态码 !== null && 状态码 !== void 0 ? 状态码 : 0)));
550
652
  };
551
653
  const 带重试 = async (执行函数, 配置, 调试) => {
552
- var _a, _b, _c, _d;
654
+ var _a, _b;
553
655
  let 尝试 = 0;
554
656
  while (true) {
555
657
  try {
@@ -560,7 +662,7 @@ class KingsoftAirscript {
560
662
  }
561
663
  catch (e) {
562
664
  const err = 提取Http错误(e);
563
- const 状态码 = (_a = err.response) === null || _a === void 0 ? void 0 : _a.status;
665
+ const 状态码 = getStatusCode(err);
564
666
  if (!判断是否可重试(e) || 尝试 >= 配置.最大重试次数) {
565
667
  if (调试)
566
668
  调试.重试次数 = 尝试;
@@ -568,8 +670,8 @@ class KingsoftAirscript {
568
670
  }
569
671
  let 等待 = Math.round(配置.初始等待毫秒 * Math.pow(配置.退避倍数, 尝试) + Math.random() * 200);
570
672
  if (配置.尊重RetryAfter && 状态码 === 429) {
571
- const headers = (_c = (_b = err.response) === null || _b === void 0 ? void 0 : _b.headers) !== null && _c !== void 0 ? _c : {};
572
- const ra = (_d = headers['retry-after']) !== null && _d !== void 0 ? _d : headers['Retry-After'];
673
+ const headers = (_a = getHeaders(err)) !== null && _a !== void 0 ? _a : {};
674
+ const ra = (_b = headers['retry-after']) !== null && _b !== void 0 ? _b : headers['Retry-After'];
573
675
  const raMs = 解析RetryAfter毫秒(ra);
574
676
  if (raMs !== null)
575
677
  等待 = Math.max(等待, raMs);
@@ -615,58 +717,19 @@ class KingsoftAirscript {
615
717
  const 递归 = (cur, idx) => {
616
718
  const k = keys[idx];
617
719
  const isLast = idx === keys.length - 1;
618
- const base = (cur && typeof cur === 'object') ? cur : {};
720
+ if (Array.isArray(cur) && !isLast) {
721
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `路径中间节点不能是数组:${keys.slice(0, idx + 1).join('.')} 是数组,无法在其下创建子字段`);
722
+ }
723
+ const base = (cur && typeof cur === 'object' && !Array.isArray(cur)) ? cur : {};
619
724
  const clone = { ...base };
620
- if (isLast) {
725
+ if (isLast)
621
726
  clone[k] = value;
622
- }
623
- else {
727
+ else
624
728
  clone[k] = 递归(base[k], idx + 1);
625
- }
626
729
  return clone;
627
730
  };
628
731
  return 递归(obj, 0);
629
732
  };
630
- const 读取高级选项 = (索引) => {
631
- const raw = this.getNodeParameter('options', 索引, {});
632
- const 取数 = (k, d) => {
633
- const v = raw[k];
634
- const n = typeof v === 'number' ? v : Number(v);
635
- return Number.isFinite(n) ? n : d;
636
- };
637
- const 取布尔 = (k, d) => {
638
- const v = raw[k];
639
- return typeof v === 'boolean' ? v : d;
640
- };
641
- const 取字符串 = (k, d) => {
642
- const v = raw[k];
643
- return typeof v === 'string' ? v : d;
644
- };
645
- return {
646
- a_parallelExecution: 取布尔('a_parallelExecution', false),
647
- b_timeoutSeconds: 取数('b_timeoutSeconds', 300),
648
- c_waitForCompletion: 取布尔('c_waitForCompletion', false),
649
- d_pollIntervalSeconds: 取数('d_pollIntervalSeconds', 5),
650
- e_batchSize: 取数('e_batchSize', 10),
651
- f_outputFormat: 取字符串('f_outputFormat', 'fullResponse'),
652
- g_parseResultString: 取布尔('g_parseResultString', false),
653
- x_globalMaxConcurrency: 取数('x_globalMaxConcurrency', 5),
654
- h_requestTimeoutSeconds: 取数('h_requestTimeoutSeconds', 120),
655
- i_statusTimeoutSeconds: 取数('i_statusTimeoutSeconds', 30),
656
- j_maxRetries: 取数('j_maxRetries', 2),
657
- k_retryInitialDelayMs: 取数('k_retryInitialDelayMs', 800),
658
- l_retryBackoffFactor: 取数('l_retryBackoffFactor', 2),
659
- m_honorRetryAfter: 取布尔('m_honorRetryAfter', true),
660
- n_failOnScriptError: 取布尔('n_failOnScriptError', true),
661
- o_pollJitterMs: 取数('o_pollJitterMs', 300),
662
- r_autoChunkEnabled: 取布尔('r_autoChunkEnabled', false),
663
- s_chunkFieldPath: 取字符串('s_chunkFieldPath', '写表行列表'),
664
- t_chunkSize: 取数('t_chunkSize', 200),
665
- u_chunkMaxConcurrency: 取数('u_chunkMaxConcurrency', 3),
666
- v_chunkOutputMode: 取字符串('v_chunkOutputMode', 'split'),
667
- w_debug: 取布尔('w_debug', false),
668
- };
669
- };
670
733
  const 提取脚本错误消息 = (响应) => {
671
734
  var _a;
672
735
  const error = String((_a = 响应.error) !== null && _a !== void 0 ? _a : '').trim();
@@ -695,8 +758,8 @@ class KingsoftAirscript {
695
758
  const fromTop = 响应.task_id;
696
759
  return String((_b = fromData !== null && fromData !== void 0 ? fromData : fromTop) !== null && _b !== void 0 ? _b : '').trim();
697
760
  };
698
- const 解析执行信息 = (itemIndex) => {
699
- var _a;
761
+ const 解析执行信息 = (itemIndex, inputData) => {
762
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
700
763
  const id输入模式 = this.getNodeParameter('idInputMode', itemIndex, 'url');
701
764
  let 文件ID = '';
702
765
  let 脚本ID = '';
@@ -715,8 +778,7 @@ class KingsoftAirscript {
715
778
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Webhook 链接格式不正确,无法解析出 File ID 和 Script ID。', { itemIndex });
716
779
  }
717
780
  }
718
- catch (e) {
719
- void e;
781
+ catch {
720
782
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Webhook 链接格式不正确,无法解析出 File ID 和 Script ID。', { itemIndex });
721
783
  }
722
784
  }
@@ -727,8 +789,14 @@ class KingsoftAirscript {
727
789
  if (!文件ID || !脚本ID) {
728
790
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), '未能获取到有效的 File ID 和 Script ID。', { itemIndex });
729
791
  }
730
- const argvTemplate = this.getNodeParameter('argvTemplate', itemIndex, 'custom');
792
+ const payloadMode = this.getNodeParameter('payloadMode', itemIndex, 'argvFromUI');
793
+ let argv参数 = {};
731
794
  const 可选上下文参数 = this.getNodeParameter('contextParameters', itemIndex, {});
795
+ let 最终_sheet_name = '';
796
+ let 最终_range = '';
797
+ let 最终_link_from = '';
798
+ let 最终_db_active_view = '';
799
+ let 最终_db_selection = '';
732
800
  const 模板到字段名 = {
733
801
  custom: 'argv_custom',
734
802
  basicInput: 'argv_basicInput',
@@ -742,20 +810,75 @@ class KingsoftAirscript {
742
810
  compositeKey: 'argv_compositeKey',
743
811
  createSheet: 'argv_createSheet',
744
812
  };
745
- const argv字段名 = (_a = 模板到字段名[argvTemplate]) !== null && _a !== void 0 ? _a : 'argv_custom';
746
- const argv原始 = this.getNodeParameter(argv字段名, itemIndex, {});
747
- let argv参数 = {};
748
- if (typeof argv原始 === 'string') {
749
- try {
750
- argv参数 = JSON.parse(argv原始);
813
+ if (payloadMode === 'argvFromUI') {
814
+ const argvTemplate = this.getNodeParameter('argvTemplate', itemIndex, 'custom');
815
+ const argv字段名 = (_a = 模板到字段名[argvTemplate]) !== null && _a !== void 0 ? _a : 'argv_custom';
816
+ const argv原始 = this.getNodeParameter(argv字段名, itemIndex, {});
817
+ if (typeof argv原始 === 'string') {
818
+ try {
819
+ argv参数 = JSON.parse(argv原始);
820
+ }
821
+ catch {
822
+ argv参数 = { value: argv原始 };
823
+ }
751
824
  }
752
- catch (e) {
753
- void e;
754
- argv参数 = { value: argv原始 };
825
+ else if (argv原始 && typeof argv原始 === 'object' && !Array.isArray(argv原始)) {
826
+ argv参数 = argv原始;
827
+ }
828
+ }
829
+ else if (payloadMode === 'argvFromItem') {
830
+ const itemDataPath = this.getNodeParameter('itemDataPath', itemIndex, '');
831
+ const item = (inputData === null || inputData === void 0 ? void 0 : inputData[itemIndex]) || 输入数据项列表[itemIndex];
832
+ if (item === null || item === void 0 ? void 0 : item.json) {
833
+ if (itemDataPath) {
834
+ const 数据值 = 取路径值(item.json, itemDataPath);
835
+ if (数据值 !== undefined) {
836
+ if (typeof 数据值 === 'object' && 数据值 !== null && !Array.isArray(数据值))
837
+ argv参数 = { ...数据值 };
838
+ else
839
+ argv参数 = { value: 数据值 };
840
+ }
841
+ }
842
+ else {
843
+ argv参数 = { ...item.json };
844
+ }
755
845
  }
756
846
  }
757
- else if (argv原始 && typeof argv原始 === 'object' && !Array.isArray(argv原始)) {
758
- argv参数 = argv原始;
847
+ else if (payloadMode === 'appendItemsToArrayField') {
848
+ const targetArrayField = this.getNodeParameter('targetArrayField', itemIndex, 'data');
849
+ const itemDataPath = this.getNodeParameter('itemDataPath', itemIndex, '');
850
+ const 输入数据 = inputData || 输入数据项列表;
851
+ const argvTemplate = this.getNodeParameter('argvTemplate', itemIndex, 'custom');
852
+ const argv字段名 = (_b = 模板到字段名[argvTemplate]) !== null && _b !== void 0 ? _b : 'argv_custom';
853
+ const argv原始 = this.getNodeParameter(argv字段名, itemIndex, {});
854
+ if (typeof argv原始 === 'string') {
855
+ try {
856
+ argv参数 = JSON.parse(argv原始);
857
+ }
858
+ catch {
859
+ argv参数 = { value: argv原始 };
860
+ }
861
+ }
862
+ else if (argv原始 && typeof argv原始 === 'object' && !Array.isArray(argv原始)) {
863
+ argv参数 = argv原始;
864
+ }
865
+ const 目标数组 = [];
866
+ for (const item of 输入数据) {
867
+ if (!(item === null || item === void 0 ? void 0 : item.json))
868
+ continue;
869
+ if (itemDataPath) {
870
+ const 数据值 = 取路径值(item.json, itemDataPath);
871
+ if (数据值 !== undefined)
872
+ 目标数组.push(数据值);
873
+ }
874
+ else {
875
+ 目标数组.push(item.json);
876
+ }
877
+ }
878
+ if (targetArrayField.includes('.'))
879
+ argv参数 = 以不可变方式写入路径(argv参数, targetArrayField, 目标数组);
880
+ else
881
+ argv参数[targetArrayField] = 目标数组;
759
882
  }
760
883
  for (const key in argv参数) {
761
884
  if (!Object.prototype.hasOwnProperty.call(argv参数, key))
@@ -764,8 +887,7 @@ class KingsoftAirscript {
764
887
  if (typeof value !== 'string')
765
888
  continue;
766
889
  const trimmed = value.trim();
767
- if ((trimmed.startsWith('{') && trimmed.endsWith('}')) ||
768
- (trimmed.startsWith('[') && trimmed.endsWith(']'))) {
890
+ if ((trimmed.startsWith('{') && trimmed.endsWith('}')) || (trimmed.startsWith('[') && trimmed.endsWith(']'))) {
769
891
  try {
770
892
  argv参数[key] = JSON.parse(trimmed);
771
893
  }
@@ -774,24 +896,18 @@ class KingsoftAirscript {
774
896
  }
775
897
  }
776
898
  }
777
- const 规范化字符串 = (v) => (typeof v === 'string' ? v.trim() : '');
778
- const 从Argv取 = (snake, camel) => {
779
- const v1 = 规范化字符串(argv参数[snake]);
780
- if (v1)
781
- return v1;
782
- if (camel) {
783
- const v2 = 规范化字符串(argv参数[camel]);
784
- if (v2)
785
- return v2;
786
- }
787
- return '';
899
+ const 从Argv提取 = (snakeKey, camelKey) => {
900
+ if (argv参数[snakeKey] !== undefined)
901
+ return argv参数[snakeKey];
902
+ if (argv参数[camelKey] !== undefined)
903
+ return argv参数[camelKey];
904
+ return undefined;
788
905
  };
789
- const 从UI取 = (key) => 规范化字符串(可选上下文参数[key]);
790
- const 最终_sheet_name = 从Argv('sheet_name', 'sheetName') || 从UI取('sheetName');
791
- const 最终_range = 从Argv('range') || 从UI取('range');
792
- const 最终_link_from = 从Argv('link_from', 'linkFrom') || 从UI取('linkFrom');
793
- const 最终_db_active_view = 从Argv('db_active_view', 'dbActiveView') || 从UI取('dbActiveView');
794
- const 最终_db_selection = 从Argv取('db_selection', 'dbSelection') || 从UI取('dbSelection');
906
+ 最终_sheet_name = String((_d = (_c = 从Argv提取('sheet_name', 'sheetName')) !== null && _c !== void 0 ? _c : 可选上下文参数.sheetName) !== null && _d !== void 0 ? _d : '').trim();
907
+ 最终_range = String((_f = (_e = 从Argv提取('range', 'range')) !== null && _e !== void 0 ? _e : 可选上下文参数.range) !== null && _f !== void 0 ? _f : '').trim();
908
+ 最终_link_from = String((_h = (_g = 从Argv提取('link_from', 'linkFrom')) !== null && _g !== void 0 ? _g : 可选上下文参数.linkFrom) !== null && _h !== void 0 ? _h : '').trim();
909
+ 最终_db_active_view = String((_k = (_j = 从Argv提取('db_active_view', 'dbActiveView')) !== null && _j !== void 0 ? _j : 可选上下文参数.dbActiveView) !== null && _k !== void 0 ? _k : '').trim();
910
+ 最终_db_selection = String((_m = (_l = 从Argv提取('db_selection', 'dbSelection')) !== null && _l !== void 0 ? _l : 可选上下文参数.dbSelection) !== null && _m !== void 0 ? _m : '').trim();
795
911
  if (最终_sheet_name)
796
912
  argv参数.sheet_name = 最终_sheet_name;
797
913
  if (最终_range)
@@ -904,9 +1020,16 @@ class KingsoftAirscript {
904
1020
  调试: 参数.调试,
905
1021
  并发闸门: 参数.并发闸门,
906
1022
  });
907
- const 状态 = typeof 状态响应.status === 'string' ? 状态响应.status : '';
908
- if (状态 === 'finished') {
909
- 校验脚本是否失败(状态响应, 参数.itemIndex, 参数.finished但error算失败);
1023
+ const 状态 = typeof 状态响应.status === 'string' ? 状态响应.status.toLowerCase() : '';
1024
+ const 终端状态 = ['finished', 'failed', 'canceled', 'cancelled', 'error'];
1025
+ if (终端状态.includes(状态)) {
1026
+ if (状态 === 'finished') {
1027
+ 校验脚本是否失败(状态响应, 参数.itemIndex, 参数.finished但error算失败);
1028
+ }
1029
+ else {
1030
+ const 错误信息 = `任务执行${状态}:${状态响应.error || 状态响应.message || '未知错误'}`;
1031
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 错误信息, { itemIndex: 参数.itemIndex });
1032
+ }
910
1033
  if (参数.调试)
911
1034
  参数.调试['轮询次数'] = (轮询次数 + 1);
912
1035
  return 状态响应;
@@ -920,20 +1043,17 @@ class KingsoftAirscript {
920
1043
  });
921
1044
  };
922
1045
  const 格式化输出 = (响应数据, 索引, opt, 附加, operation) => {
923
- var _a, _b, _c, _d;
1046
+ var _a, _b, _c, _d, _e;
924
1047
  const data = ((_a = 响应数据.data) !== null && _a !== void 0 ? _a : undefined);
925
1048
  if (opt.g_parseResultString && data && typeof data.result === 'string') {
926
1049
  try {
927
1050
  data.result = JSON.parse(data.result);
928
1051
  }
929
- catch (e) {
930
- void e;
1052
+ catch {
931
1053
  data.result = data.result.replace(/\\n/g, '\n');
932
1054
  }
933
1055
  }
934
- const _meta = {
935
- operation: operation || 'unknown',
936
- };
1056
+ const _meta = { operation: operation || 'unknown' };
937
1057
  const sheetNameFromData = (data === null || data === void 0 ? void 0 : data.sheet_name) || (data === null || data === void 0 ? void 0 : data.sheetName);
938
1058
  const sheetNameFromResponse = 是IDataObject(响应数据) ? (响应数据.sheet_name || 响应数据.sheetName) : undefined;
939
1059
  const sheetNameFromArgv = 是IDataObject(附加) && 是IDataObject(附加.argv) ? (附加.argv.sheet_name || 附加.argv.sheetName) : undefined;
@@ -949,18 +1069,18 @@ class KingsoftAirscript {
949
1069
  _meta.task_id = taskIdFromData;
950
1070
  else if (taskIdFromResponse)
951
1071
  _meta.task_id = taskIdFromResponse;
952
- if ((附加 === null || 附加 === void 0 ? void 0 : 附加.批次索引) !== undefined) {
953
- _meta.batchIndex = 附加.批次索引;
954
- }
1072
+ const batchIndex = (_b = 附加 === null || 附加 === void 0 ? void 0 : 附加.批次索引) !== null && _b !== void 0 ? _b : 附加 === null || 附加 === void 0 ? void 0 : 附加.batchIndex;
1073
+ if (batchIndex !== undefined)
1074
+ _meta.batchIndex = batchIndex;
955
1075
  const out = [];
956
1076
  if (opt.f_outputFormat === 'resultOnly') {
957
1077
  out.push({
958
1078
  json: {
959
1079
  ...(附加 !== null && 附加 !== void 0 ? 附加 : {}),
960
1080
  _meta,
961
- result: (_b = data === null || data === void 0 ? void 0 : data.result) !== null && _b !== void 0 ? _b : null,
962
- status: ((_c = 响应数据.status) !== null && _c !== void 0 ? _c : null),
963
- error: ((_d = 响应数据.error) !== null && _d !== void 0 ? _d : ''),
1081
+ result: (_c = data === null || data === void 0 ? void 0 : data.result) !== null && _c !== void 0 ? _c : null,
1082
+ status: ((_d = 响应数据.status) !== null && _d !== void 0 ? _d : null),
1083
+ error: ((_e = 响应数据.error) !== null && _e !== void 0 ? _e : ''),
964
1084
  },
965
1085
  pairedItem: { item: 索引 },
966
1086
  });
@@ -993,7 +1113,7 @@ class KingsoftAirscript {
993
1113
  out.push({ json: { ...(附加 !== null && 附加 !== void 0 ? 附加 : {}), _meta, ...响应数据 }, pairedItem: { item: 索引 } });
994
1114
  return out;
995
1115
  };
996
- const 处理单个项目 = async (索引) => {
1116
+ const 处理单个项目 = async (索引, 并发闸门) => {
997
1117
  const 操作类型 = this.getNodeParameter('operation', 索引, 'runScriptSync');
998
1118
  const opt = 读取高级选项(索引);
999
1119
  const 重试 = {
@@ -1003,7 +1123,6 @@ class KingsoftAirscript {
1003
1123
  尊重RetryAfter: opt.m_honorRetryAfter,
1004
1124
  };
1005
1125
  const 调试字段 = opt.w_debug ? {} : undefined;
1006
- const 并发闸门 = 创建并发闸门(opt.x_globalMaxConcurrency);
1007
1126
  if (操作类型 === 'getTaskStatus') {
1008
1127
  const taskId = this.getNodeParameter('taskId', 索引, '');
1009
1128
  if (!taskId || !taskId.trim()) {
@@ -1020,7 +1139,7 @@ class KingsoftAirscript {
1020
1139
  const 附加 = opt.w_debug ? { _调试: 调试字段 } : undefined;
1021
1140
  return 格式化输出(状态响应, 索引, opt, 附加, 操作类型);
1022
1141
  }
1023
- const { 文件ID, 脚本ID, argv参数, 上下文 } = 解析执行信息(索引);
1142
+ const { 文件ID, 脚本ID, argv参数, 上下文 } = 解析执行信息(索引, 输入数据项列表);
1024
1143
  const 组装批次失败响应 = (错误信息, 堆栈) => ({
1025
1144
  status: 'finished',
1026
1145
  error: 错误信息,
@@ -1058,9 +1177,8 @@ class KingsoftAirscript {
1058
1177
  调试: 调试对象,
1059
1178
  并发闸门,
1060
1179
  });
1061
- if (!opt.c_waitForCompletion) {
1180
+ if (!opt.c_waitForCompletion)
1062
1181
  return 初始响应;
1063
- }
1064
1182
  const taskId = 提取TaskId(初始响应);
1065
1183
  if (!taskId) {
1066
1184
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), '异步执行返回的响应中未找到 task_id(data.task_id 或 task_id)。', { itemIndex: 索引 });
@@ -1083,18 +1201,13 @@ class KingsoftAirscript {
1083
1201
  if (opt.r_autoChunkEnabled) {
1084
1202
  const 数组路径 = opt.s_chunkFieldPath;
1085
1203
  const 目标数组 = 取路径值(argv参数, 数组路径);
1086
- if (!Array.isArray(目标数组)) {
1204
+ if (!Array.isArray(目标数组) || 目标数组.length === 0) {
1087
1205
  const 响应 = await 执行一次(上下文, 调试字段);
1088
1206
  const 附加 = opt.w_debug ? { _调试: 调试字段 } : undefined;
1089
1207
  return 格式化输出(响应, 索引, opt, 附加, 操作类型);
1090
1208
  }
1091
1209
  const 批次大小 = Math.max(1, opt.t_chunkSize);
1092
1210
  const 并发数 = Math.max(1, opt.u_chunkMaxConcurrency);
1093
- if (目标数组.length === 0) {
1094
- const 响应 = await 执行一次(上下文, 调试字段);
1095
- const 附加 = opt.w_debug ? { _调试: 调试字段 } : undefined;
1096
- return 格式化输出(响应, 索引, opt, 附加, 操作类型);
1097
- }
1098
1211
  const 任务列表 = [];
1099
1212
  for (let i = 0; i < 目标数组.length; i += 批次大小) {
1100
1213
  const 批次 = 目标数组.slice(i, i + 批次大小);
@@ -1108,18 +1221,17 @@ class KingsoftAirscript {
1108
1221
  };
1109
1222
  const 响应 = await 执行一次(批次上下文, 批次调试对象);
1110
1223
  const 批次附加 = opt.w_debug
1111
- ? { _调试: { ...(批次调试对象 !== null && 批次调试对象 !== void 0 ? 批次调试对象 : {}), 批次索引 } }
1224
+ ? { 批次索引, _调试: { ...(批次调试对象 !== null && 批次调试对象 !== void 0 ? 批次调试对象 : {}) } }
1112
1225
  : { 批次索引 };
1113
1226
  return 格式化输出(响应, 索引, opt, 批次附加, 操作类型);
1114
1227
  }
1115
1228
  catch (错误) {
1116
- if (!this.continueOnFail()) {
1229
+ if (!this.continueOnFail())
1117
1230
  throw 错误;
1118
- }
1119
1231
  const err = 错误 instanceof Error ? 错误 : new Error(String(错误));
1120
1232
  const 错误对象 = 组装批次失败响应(err.message, err.stack);
1121
1233
  const 错误附加 = opt.w_debug
1122
- ? { _调试: { 批次索引, 错误: err.message } }
1234
+ ? { 批次索引, _调试: { 错误: err.message } }
1123
1235
  : { 批次索引, 错误: err.message };
1124
1236
  return 格式化输出(错误对象, 索引, opt, 错误附加, 操作类型);
1125
1237
  }
@@ -1133,15 +1245,16 @@ class KingsoftAirscript {
1133
1245
  .map(x => x.json)
1134
1246
  .filter((json) => typeof json === 'object' && json !== null)
1135
1247
  .map(json => {
1136
- var _a;
1248
+ var _a, _b, _c;
1137
1249
  const fromData = (_a = json.data) === null || _a === void 0 ? void 0 : _a.task_id;
1138
1250
  const fromTop = json.task_id;
1139
- return fromData !== null && fromData !== void 0 ? fromData : fromTop;
1251
+ const fromMeta = (_b = json._meta) === null || _b === void 0 ? void 0 : _b.task_id;
1252
+ return (_c = fromData !== null && fromData !== void 0 ? fromData : fromTop) !== null && _c !== void 0 ? _c : fromMeta;
1140
1253
  })
1141
1254
  .filter((id) => typeof id === 'string' && id.length > 0);
1142
1255
  const 批次数 = Math.ceil(目标数组.length / 批次大小);
1143
1256
  const 分批汇总 = {
1144
- 批次数: 批次数,
1257
+ 批次数,
1145
1258
  每批条数: Array.from({ length: 批次数 }, (_, i) => {
1146
1259
  const start = i * 批次大小;
1147
1260
  const end = Math.min(start + 批次大小, 目标数组.length);
@@ -1149,7 +1262,7 @@ class KingsoftAirscript {
1149
1262
  }),
1150
1263
  字段路径: 数组路径,
1151
1264
  总数据条数: 目标数组.length,
1152
- 并发数: 并发数,
1265
+ 并发数,
1153
1266
  };
1154
1267
  const 合并结果 = {
1155
1268
  分批汇总,
@@ -1159,20 +1272,16 @@ class KingsoftAirscript {
1159
1272
  };
1160
1273
  return [{ json: 合并结果, pairedItem: { item: 索引 } }];
1161
1274
  }
1162
- else {
1163
- return 批次结果.flat();
1164
- }
1165
- }
1166
- else {
1167
- const 响应 = await 执行一次(上下文, 调试字段);
1168
- const 附加 = opt.w_debug ? { _调试: 调试字段 } : undefined;
1169
- return 格式化输出(响应, 索引, opt, 附加, 操作类型);
1275
+ return 批次结果.flat();
1170
1276
  }
1277
+ const 响应 = await 执行一次(上下文, 调试字段);
1278
+ const 附加 = opt.w_debug ? { _调试: 调试字段 } : undefined;
1279
+ return 格式化输出(响应, 索引, opt, 附加, 操作类型);
1171
1280
  };
1172
- const 安全执行单个项目 = async (itemIndex) => {
1173
- var _a, _b, _c, _d, _e;
1281
+ const 安全执行单个项目 = async (itemIndex, 并发闸门) => {
1282
+ var _a, _b, _c;
1174
1283
  try {
1175
- return await 处理单个项目(itemIndex);
1284
+ return await 处理单个项目(itemIndex, 并发闸门);
1176
1285
  }
1177
1286
  catch (e) {
1178
1287
  if (!this.continueOnFail())
@@ -1183,30 +1292,34 @@ class KingsoftAirscript {
1183
1292
  json: {
1184
1293
  error: 提取错误消息(err),
1185
1294
  code: (_a = err.code) !== null && _a !== void 0 ? _a : null,
1186
- statusCode: (_c = (_b = err.response) === null || _b === void 0 ? void 0 : _b.status) !== null && _c !== void 0 ? _c : null,
1187
- details: (_e = (_d = err.response) === null || _d === void 0 ? void 0 : _d.data) !== null && _e !== void 0 ? _e : null,
1295
+ statusCode: (_b = getStatusCode(err)) !== null && _b !== void 0 ? _b : null,
1296
+ details: (_c = getBody(err)) !== null && _c !== void 0 ? _c : null,
1188
1297
  },
1189
1298
  pairedItem: { item: itemIndex },
1190
1299
  },
1191
1300
  ];
1192
1301
  }
1193
1302
  };
1194
- const opt = 读取高级选项(0);
1303
+ const operation0 = this.getNodeParameter('operation', 0, 'runScriptSync');
1304
+ const payloadMode0 = this.getNodeParameter('payloadMode', 0, 'argvFromUI');
1305
+ const appendOnce = (operation0 === 'runScriptSync' || operation0 === 'runScriptAsync')
1306
+ && payloadMode0 === 'appendItemsToArrayField';
1307
+ const indicesToRun = appendOnce ? [0] : Array.from({ length: 输入数据项列表.length }, (_, i) => i);
1195
1308
  const 汇总输出 = [];
1196
- if (opt.a_parallelExecution) {
1197
- const 批处理数量 = Math.max(1, opt.e_batchSize);
1198
- for (let i = 0; i < 输入数据项列表.length; i += 批处理数量) {
1199
- const 索引列表 = 输入数据项列表.slice(i, i + 批处理数量).map((_, localIndex) => i + localIndex);
1200
- const 任务函数列表 = 索引列表.map((idx) => () => 安全执行单个项目(idx));
1201
- const 批次结果 = await 并发执行(任务函数列表, 批处理数量);
1309
+ if (opt0.a_parallelExecution) {
1310
+ const 批处理数量 = Math.max(1, opt0.e_batchSize);
1311
+ for (let i = 0; i < indicesToRun.length; i += 批处理数量) {
1312
+ const slice = indicesToRun.slice(i, i + 批处理数量);
1313
+ const 任务函数列表 = slice.map((idx) => () => 安全执行单个项目(idx, 全局并发闸门));
1314
+ const 批次结果 = await 并发执行(任务函数列表, slice.length);
1202
1315
  for (const 单项结果 of 批次结果) {
1203
1316
  汇总输出.push(...单项结果);
1204
1317
  }
1205
1318
  }
1206
1319
  }
1207
1320
  else {
1208
- for (let i = 0; i < 输入数据项列表.length; i++) {
1209
- const 单项结果 = await 安全执行单个项目(i);
1321
+ for (const idx of indicesToRun) {
1322
+ const 单项结果 = await 安全执行单个项目(idx, 全局并发闸门);
1210
1323
  汇总输出.push(...单项结果);
1211
1324
  }
1212
1325
  }