snow-flow 10.0.1-dev.462 → 10.0.1-dev.463

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "10.0.1-dev.462",
3
+ "version": "10.0.1-dev.463",
4
4
  "name": "snow-flow",
5
5
  "description": "Snow-Flow - ServiceNow Multi-Agent Development Framework powered by AI",
6
6
  "license": "Elastic-2.0",
@@ -384,15 +384,238 @@ function flattenAttributes(attrs: any): string {
384
384
  * Fallback: if the triggerpicker API fails, queries sys_hub_trigger_input / sys_hub_trigger_output
385
385
  * via the Table API (same approach as buildActionInputsForInsert / buildFlowLogicInputsForInsert).
386
386
  */
387
+ /**
388
+ * Parse XML string from triggerpicker API to extract input/output elements.
389
+ * The triggerpicker endpoint may return XML instead of JSON on some instances.
390
+ */
391
+ function parseTriggerpickerXml(xmlStr: string): { inputs: any[]; outputs: any[] } {
392
+ var inputs: any[] = [];
393
+ var outputs: any[] = [];
394
+
395
+ // Helper: extract text content of an XML element by tag name
396
+ var getTag = function (xml: string, tag: string): string {
397
+ var m = xml.match(new RegExp('<' + tag + '>([\\s\\S]*?)</' + tag + '>'));
398
+ return m ? m[1].trim() : '';
399
+ };
400
+
401
+ // Helper: extract all occurrences of a repeated element
402
+ var getAll = function (xml: string, tag: string): string[] {
403
+ var re = new RegExp('<' + tag + '>([\\s\\S]*?)</' + tag + '>', 'g');
404
+ var results: string[] = [];
405
+ var m;
406
+ while ((m = re.exec(xml)) !== null) results.push(m[1]);
407
+ return results;
408
+ };
409
+
410
+ // Try to find input elements — XML may wrap them in <inputs><element>...</element></inputs>
411
+ // or <trigger_inputs><input>...</input></trigger_inputs> etc.
412
+ var inputsSection = getTag(xmlStr, 'inputs') || getTag(xmlStr, 'trigger_inputs') || xmlStr;
413
+ var inputElements = getAll(inputsSection, 'element');
414
+ if (inputElements.length === 0) inputElements = getAll(inputsSection, 'input');
415
+ if (inputElements.length === 0) inputElements = getAll(inputsSection, 'trigger_input');
416
+
417
+ for (var ii = 0; ii < inputElements.length; ii++) {
418
+ var el = inputElements[ii];
419
+ var name = getTag(el, 'name') || getTag(el, 'element');
420
+ if (!name) continue;
421
+ inputs.push({
422
+ id: getTag(el, 'sys_id') || getTag(el, 'id'),
423
+ name: name,
424
+ label: getTag(el, 'label') || name,
425
+ type: getTag(el, 'type') || getTag(el, 'internal_type') || 'string',
426
+ type_label: getTag(el, 'type_label') || '',
427
+ mandatory: getTag(el, 'mandatory') === 'true',
428
+ order: parseInt(getTag(el, 'order') || '0', 10),
429
+ maxsize: parseInt(getTag(el, 'maxsize') || getTag(el, 'max_length') || '4000', 10),
430
+ hint: getTag(el, 'hint'),
431
+ defaultValue: getTag(el, 'defaultValue') || getTag(el, 'default_value'),
432
+ defaultDisplayValue: getTag(el, 'defaultDisplayValue') || getTag(el, 'default_display_value'),
433
+ choiceOption: getTag(el, 'choiceOption') || getTag(el, 'choice_option'),
434
+ reference: getTag(el, 'reference'),
435
+ reference_display: getTag(el, 'reference_display'),
436
+ use_dependent: getTag(el, 'use_dependent') === 'true',
437
+ dependent_on: getTag(el, 'dependent_on'),
438
+ internal_link: getTag(el, 'internal_link'),
439
+ attributes: getTag(el, 'attributes')
440
+ });
441
+ }
442
+
443
+ var outputsSection = getTag(xmlStr, 'outputs') || getTag(xmlStr, 'trigger_outputs') || '';
444
+ var outputElements = getAll(outputsSection, 'element');
445
+ if (outputElements.length === 0) outputElements = getAll(outputsSection, 'output');
446
+ if (outputElements.length === 0) outputElements = getAll(outputsSection, 'trigger_output');
447
+
448
+ for (var oi = 0; oi < outputElements.length; oi++) {
449
+ var oel = outputElements[oi];
450
+ var oname = getTag(oel, 'name') || getTag(oel, 'element');
451
+ if (!oname) continue;
452
+ outputs.push({
453
+ id: getTag(oel, 'sys_id') || getTag(oel, 'id'),
454
+ name: oname,
455
+ label: getTag(oel, 'label') || oname,
456
+ type: getTag(oel, 'type') || getTag(oel, 'internal_type') || 'string',
457
+ type_label: getTag(oel, 'type_label') || '',
458
+ mandatory: getTag(oel, 'mandatory') === 'true',
459
+ order: parseInt(getTag(oel, 'order') || '0', 10),
460
+ maxsize: parseInt(getTag(oel, 'maxsize') || getTag(oel, 'max_length') || '200', 10),
461
+ hint: getTag(oel, 'hint'),
462
+ reference: getTag(oel, 'reference'),
463
+ reference_display: getTag(oel, 'reference_display'),
464
+ use_dependent: getTag(oel, 'use_dependent') === 'true',
465
+ dependent_on: getTag(oel, 'dependent_on'),
466
+ internal_link: getTag(oel, 'internal_link'),
467
+ attributes: getTag(oel, 'attributes')
468
+ });
469
+ }
470
+
471
+ return { inputs, outputs };
472
+ }
473
+
474
+ /**
475
+ * Build a single trigger input object in GraphQL mutation format.
476
+ * Used by buildTriggerInputsForInsert and the hardcoded fallback.
477
+ */
478
+ function buildTriggerInputObj(inp: any, userTable?: string, userCondition?: string): any {
479
+ var paramType = inp.type || 'string';
480
+ var name = inp.name || '';
481
+ var label = inp.label || name;
482
+ var attrs = typeof inp.attributes === 'object' ? flattenAttributes(inp.attributes) : (inp.attributes || '');
483
+
484
+ // Determine value: user-provided > default
485
+ var value = '';
486
+ if (name === 'table' && userTable) value = userTable;
487
+ else if (name === 'condition') value = userCondition || '^EQ';
488
+ else if (inp.defaultValue) value = inp.defaultValue;
489
+
490
+ var parameter: any = {
491
+ id: inp.id || '', label: label, name: name, type: paramType,
492
+ type_label: inp.type_label || TYPE_LABELS[paramType] || paramType,
493
+ order: inp.order || 0, extended: inp.extended || false,
494
+ mandatory: inp.mandatory || false, readonly: inp.readonly || false,
495
+ maxsize: inp.maxsize || 4000, data_structure: '',
496
+ reference: inp.reference || '', reference_display: inp.reference_display || '',
497
+ ref_qual: inp.ref_qual || '', choiceOption: inp.choiceOption || '',
498
+ table: '', columnName: '', defaultValue: inp.defaultValue || '',
499
+ use_dependent: inp.use_dependent || false, dependent_on: inp.dependent_on || '',
500
+ internal_link: inp.internal_link || '', show_ref_finder: inp.show_ref_finder || false,
501
+ local: inp.local || false, attributes: attrs, sys_class_name: '', children: []
502
+ };
503
+ if (inp.hint) parameter.hint = inp.hint;
504
+ if (inp.defaultDisplayValue) parameter.defaultDisplayValue = inp.defaultDisplayValue;
505
+ if (inp.choices) parameter.choices = inp.choices;
506
+ if (inp.defaultChoices) parameter.defaultChoices = inp.defaultChoices;
507
+
508
+ var inputObj: any = {
509
+ name: name, label: label, internalType: paramType,
510
+ mandatory: inp.mandatory || false, order: inp.order || 0,
511
+ valueSysId: '', field_name: name, type: paramType, children: [],
512
+ displayValue: { value: '' },
513
+ value: value ? { schemaless: false, schemalessValue: '', value: value } : { value: '' },
514
+ parameter: parameter
515
+ };
516
+
517
+ if (inp.choices && Array.isArray(inp.choices)) {
518
+ inputObj.choiceList = inp.choices.map(function (c: any) {
519
+ return { label: c.label, value: c.value };
520
+ });
521
+ }
522
+
523
+ return inputObj;
524
+ }
525
+
526
+ /**
527
+ * Build a single trigger output object in GraphQL mutation format.
528
+ */
529
+ function buildTriggerOutputObj(out: any): any {
530
+ var paramType = out.type || 'string';
531
+ var name = out.name || '';
532
+ var label = out.label || name;
533
+ var attrs = typeof out.attributes === 'object' ? flattenAttributes(out.attributes) : (out.attributes || '');
534
+
535
+ var parameter: any = {
536
+ id: out.id || '', label: label, name: name, type: paramType,
537
+ type_label: out.type_label || TYPE_LABELS[paramType] || paramType,
538
+ hint: out.hint || '', order: out.order || 0, extended: out.extended || false,
539
+ mandatory: out.mandatory || false, readonly: out.readonly || false,
540
+ maxsize: out.maxsize || 200, data_structure: '',
541
+ reference: out.reference || '', reference_display: out.reference_display || '',
542
+ ref_qual: '', choiceOption: '', table: '', columnName: '', defaultValue: '',
543
+ use_dependent: out.use_dependent || false, dependent_on: out.dependent_on || '',
544
+ internal_link: out.internal_link || '', show_ref_finder: false, local: false,
545
+ attributes: attrs, sys_class_name: ''
546
+ };
547
+
548
+ var children: any[] = [];
549
+ var paramChildren: any[] = [];
550
+ if (out.children && Array.isArray(out.children)) {
551
+ children = out.children.map(function (child: any) {
552
+ return { id: '', name: child.name || '', scriptActive: false, children: [], value: { value: '' }, script: null };
553
+ });
554
+ paramChildren = out.children.map(function (child: any) {
555
+ return {
556
+ id: '', label: child.label || child.name || '', name: child.name || '',
557
+ type: child.type || 'string', type_label: child.type_label || TYPE_LABELS[child.type || 'string'] || 'String',
558
+ hint: '', order: child.order || 0, extended: false, mandatory: false, readonly: false, maxsize: 0,
559
+ data_structure: '', reference: '', reference_display: '', ref_qual: '', choiceOption: '',
560
+ table: '', columnName: '', defaultValue: '', defaultDisplayValue: '',
561
+ use_dependent: false, dependent_on: false, show_ref_finder: false, local: false,
562
+ attributes: '', sys_class_name: '',
563
+ uiDisplayType: child.uiDisplayType || child.type || 'string',
564
+ uiDisplayTypeLabel: child.type_label || 'String',
565
+ internal_link: '', value: '', display_value: '', scriptActive: false,
566
+ parent: out.id || '',
567
+ fieldFacetMap: 'uiTypeLabel=' + (child.type_label || 'String') + ',',
568
+ children: [], script: null
569
+ };
570
+ });
571
+ }
572
+ parameter.children = paramChildren;
573
+
574
+ return {
575
+ name: name, value: '', displayValue: '', type: paramType,
576
+ order: out.order || 0, label: label, children: children, parameter: parameter
577
+ };
578
+ }
579
+
580
+ /**
581
+ * Hardcoded record trigger inputs — used as ultimate fallback when API and Table lookups fail.
582
+ * These definitions match the exact format captured from the Flow Designer UI for record-based triggers
583
+ * (record_create, record_update, record_create_or_update). Field names and types are consistent across instances.
584
+ */
585
+ function getRecordTriggerFallbackInputs(): any[] {
586
+ return [
587
+ { name: 'table', label: 'Table', type: 'table_name', type_label: 'Table Name', mandatory: true, order: 1, maxsize: 80, attributes: 'filter_table_source=RECORD_WATCHER_RESTRICTED,' },
588
+ { name: 'condition', label: 'Condition', type: 'conditions', type_label: 'Conditions', mandatory: false, order: 100, maxsize: 4000, use_dependent: true, dependent_on: 'table', attributes: 'extended_operators=VALCHANGES;CHANGESFROM;CHANGESTO,wants_to_add_conditions=true,modelDependent=trigger_inputs,' },
589
+ { name: 'run_on_extended', label: 'run_on_extended', type: 'choice', type_label: 'Choice', mandatory: false, order: 100, maxsize: 40, defaultValue: 'false', defaultDisplayValue: 'Run only on current table', choiceOption: '3', attributes: 'advanced=true,', choices: [{ label: 'Run only on current table', value: 'false', order: 0 }, { label: 'Run on current and extended tables', value: 'true', order: 1 }], defaultChoices: [{ label: 'Run only on current table', value: 'false', order: 1 }, { label: 'Run on current and extended tables', value: 'true', order: 2 }] },
590
+ { name: 'run_flow_in', label: 'run_flow_in', type: 'choice', type_label: 'Choice', mandatory: false, order: 100, maxsize: 40, defaultValue: 'any', defaultDisplayValue: 'any', choiceOption: '3', attributes: 'advanced=true,', choices: [{ label: 'Run flow in background (default)', value: 'background', order: 0 }, { label: 'Run flow in foreground', value: 'foreground', order: 1 }], defaultChoices: [{ label: 'Run flow in background (default)', value: 'background', order: 1 }, { label: 'Run flow in foreground', value: 'foreground', order: 2 }] },
591
+ { name: 'run_when_user_list', label: 'run_when_user_list', type: 'glide_list', type_label: 'List', mandatory: false, order: 100, maxsize: 4000, reference: 'sys_user', reference_display: 'User', attributes: 'advanced=true,' },
592
+ { name: 'run_when_setting', label: 'run_when_setting', type: 'choice', type_label: 'Choice', mandatory: false, order: 100, maxsize: 40, defaultValue: 'both', defaultDisplayValue: 'Run for Both Interactive and Non-Interactive Sessions', choiceOption: '3', attributes: 'advanced=true,', choices: [{ label: 'Only Run for Non-Interactive Session', value: 'non_interactive', order: 0 }, { label: 'Only Run for User Interactive Session', value: 'interactive', order: 1 }, { label: 'Run for Both Interactive and Non-Interactive Sessions', value: 'both', order: 2 }], defaultChoices: [{ label: 'Only Run for Non-Interactive Session', value: 'non_interactive', order: 1 }, { label: 'Only Run for User Interactive Session', value: 'interactive', order: 2 }, { label: 'Run for Both Interactive and Non-Interactive Sessions', value: 'both', order: 3 }] },
593
+ { name: 'run_when_user_setting', label: 'run_when_user_setting', type: 'choice', type_label: 'Choice', mandatory: false, order: 100, maxsize: 40, defaultValue: 'any', defaultDisplayValue: 'Run for any user', choiceOption: '3', attributes: 'advanced=true,', choices: [{ label: 'Do not run if triggered by the following users', value: 'not_one_of', order: 0 }, { label: 'Only Run if triggered by the following users', value: 'one_of', order: 1 }, { label: 'Run for any user', value: 'any', order: 2 }], defaultChoices: [{ label: 'Do not run if triggered by the following users', value: 'not_one_of', order: 1 }, { label: 'Only Run if triggered by the following users', value: 'one_of', order: 2 }, { label: 'Run for any user', value: 'any', order: 3 }] },
594
+ { name: 'trigger_strategy', label: 'Run Trigger', type: 'choice', type_label: 'Choice', mandatory: false, order: 200, maxsize: 40, defaultValue: 'once', defaultDisplayValue: 'Once', choiceOption: '3', hint: 'Run Trigger every time the condition matches, or only the first time.', choices: [{ label: 'Once', value: 'once', order: 0 }, { label: 'For each unique change', value: 'unique_changes', order: 1 }, { label: 'Only if not currently running', value: 'always', order: 2 }, { label: 'For every update', value: 'every', order: 3 }], defaultChoices: [{ label: 'Once', value: 'once', order: 1 }, { label: 'For each unique change', value: 'unique_changes', order: 2 }, { label: 'Only if not currently running', value: 'always', order: 3 }, { label: 'For every update', value: 'every', order: 4 }] }
595
+ ];
596
+ }
597
+
598
+ function getRecordTriggerFallbackOutputs(): any[] {
599
+ return [
600
+ { name: 'current', label: 'Record', type: 'document_id', type_label: 'Document ID', mandatory: true, order: 100, maxsize: 200, use_dependent: true, dependent_on: 'table_name', internal_link: 'table' },
601
+ { name: 'changed_fields', label: 'Changed Fields', type: 'array.object', type_label: 'Array.Object', mandatory: false, order: 100, maxsize: 4000, attributes: 'uiTypeLabel=Array.Object,co_type_name=FDCollection,child_label=FDChangeDetails,child_type_label=Object,element_mapping_provider=com.glide.flow_design.action.data.FlowDesignVariableMapper,pwd2droppable=true,uiType=array.object,child_type=object,child_name=FDChangeDetails,', children: [{ name: 'field_name', label: 'Field Name', type: 'string', type_label: 'String', order: 1 }, { name: 'previous_value', label: 'Previous Value', type: 'string', type_label: 'String', order: 2 }, { name: 'current_value', label: 'Current Value', type: 'string', type_label: 'String', order: 3 }, { name: 'previous_display_value', label: 'Previous Display Value', type: 'string', type_label: 'String', order: 4 }, { name: 'current_display_value', label: 'Current Display Value', type: 'string', type_label: 'String', order: 5 }] },
602
+ { name: 'table_name', label: 'Table Name', type: 'table_name', type_label: 'Table Name', mandatory: false, order: 101, maxsize: 200, internal_link: 'table', attributes: 'test_input_hidden=true,' },
603
+ { name: 'run_start_time', label: 'Run Start Time UTC', type: 'glide_date_time', type_label: 'Date/Time', mandatory: false, order: 110, maxsize: 200, attributes: 'test_input_hidden=true,' },
604
+ { name: 'run_start_date_time', label: 'Run Start Date/Time', type: 'glide_date_time', type_label: 'Date/Time', mandatory: false, order: 110, maxsize: 200, attributes: 'test_input_hidden=true,' }
605
+ ];
606
+ }
607
+
387
608
  async function buildTriggerInputsForInsert(
388
609
  client: any,
389
610
  trigDefId: string,
611
+ trigType: string,
390
612
  userTable?: string,
391
613
  userCondition?: string
392
- ): Promise<{ inputs: any[]; outputs: any[]; error?: string }> {
614
+ ): Promise<{ inputs: any[]; outputs: any[]; source: string; error?: string }> {
393
615
  var apiInputs: any[] = [];
394
616
  var apiOutputs: any[] = [];
395
617
  var fetchError = '';
618
+ var source = '';
396
619
 
397
620
  // Strategy 1: triggerpicker API (primary — same as Flow Designer UI)
398
621
  try {
@@ -400,10 +623,50 @@ async function buildTriggerInputsForInsert(
400
623
  params: { sysparm_transaction_scope: 'global' },
401
624
  headers: { Accept: 'application/json' }
402
625
  });
403
- var tpData = tpResp.data?.result || tpResp.data;
404
- if (tpData && typeof tpData === 'object') {
405
- apiInputs = tpData.inputs || tpData.trigger_inputs || [];
406
- apiOutputs = tpData.outputs || tpData.trigger_outputs || [];
626
+ var tpRaw = tpResp.data;
627
+ var tpData = tpRaw?.result || tpRaw;
628
+
629
+ // Handle JSON object response
630
+ if (tpData && typeof tpData === 'object' && !Array.isArray(tpData)) {
631
+ // Try common field name variations
632
+ var foundInputs = Array.isArray(tpData.inputs) ? tpData.inputs
633
+ : Array.isArray(tpData.trigger_inputs) ? tpData.trigger_inputs
634
+ : Array.isArray(tpData.input) ? tpData.input : null;
635
+ var foundOutputs = Array.isArray(tpData.outputs) ? tpData.outputs
636
+ : Array.isArray(tpData.trigger_outputs) ? tpData.trigger_outputs
637
+ : Array.isArray(tpData.output) ? tpData.output : null;
638
+ if (foundInputs) { apiInputs = foundInputs; source = 'triggerpicker_json'; }
639
+ if (foundOutputs) apiOutputs = foundOutputs;
640
+
641
+ // If no arrays found, try to explore nested structure
642
+ if (!foundInputs && !foundOutputs) {
643
+ for (var key of Object.keys(tpData)) {
644
+ var val = tpData[key];
645
+ if (val && typeof val === 'object' && !Array.isArray(val)) {
646
+ if (Array.isArray(val.inputs)) { apiInputs = val.inputs; source = 'triggerpicker_json.' + key; }
647
+ if (Array.isArray(val.outputs)) apiOutputs = val.outputs;
648
+ }
649
+ }
650
+ }
651
+ }
652
+
653
+ // Handle XML string response
654
+ if (apiInputs.length === 0 && typeof tpData === 'string' && tpData.includes('<')) {
655
+ var xmlResult = parseTriggerpickerXml(tpData);
656
+ if (xmlResult.inputs.length > 0) {
657
+ apiInputs = xmlResult.inputs;
658
+ apiOutputs = xmlResult.outputs;
659
+ source = 'triggerpicker_xml';
660
+ }
661
+ }
662
+ // Also check if the raw response itself is XML (not wrapped in result)
663
+ if (apiInputs.length === 0 && typeof tpRaw === 'string' && tpRaw.includes('<')) {
664
+ var xmlResult2 = parseTriggerpickerXml(tpRaw);
665
+ if (xmlResult2.inputs.length > 0) {
666
+ apiInputs = xmlResult2.inputs;
667
+ apiOutputs = xmlResult2.outputs;
668
+ source = 'triggerpicker_xml_raw';
669
+ }
407
670
  }
408
671
  } catch (tpErr: any) {
409
672
  fetchError = 'triggerpicker: ' + (tpErr.message || 'unknown');
@@ -421,22 +684,25 @@ async function buildTriggerInputsForInsert(
421
684
  }
422
685
  });
423
686
  var tableInputs = tiResp.data.result || [];
424
- apiInputs = tableInputs.map(function (rec: any) {
425
- return {
426
- id: str(rec.sys_id), name: str(rec.element), label: str(rec.label) || str(rec.element),
427
- type: str(rec.internal_type) || 'string',
428
- type_label: TYPE_LABELS[str(rec.internal_type) || 'string'] || str(rec.internal_type),
429
- mandatory: str(rec.mandatory) === 'true',
430
- order: parseInt(str(rec.order) || '0', 10),
431
- maxsize: parseInt(str(rec.max_length) || '4000', 10),
432
- hint: str(rec.hint), defaultValue: str(rec.default_value),
433
- reference: str(rec.reference), reference_display: str(rec.reference_display),
434
- use_dependent: str(rec.use_dependent_field) === 'true',
435
- dependent_on: str(rec.dependent_on_field),
436
- attributes: str(rec.attributes)
437
- };
438
- });
439
- fetchError = '';
687
+ if (tableInputs.length > 0) {
688
+ apiInputs = tableInputs.map(function (rec: any) {
689
+ return {
690
+ id: str(rec.sys_id), name: str(rec.element), label: str(rec.label) || str(rec.element),
691
+ type: str(rec.internal_type) || 'string',
692
+ type_label: TYPE_LABELS[str(rec.internal_type) || 'string'] || str(rec.internal_type),
693
+ mandatory: str(rec.mandatory) === 'true',
694
+ order: parseInt(str(rec.order) || '0', 10),
695
+ maxsize: parseInt(str(rec.max_length) || '4000', 10),
696
+ hint: str(rec.hint), defaultValue: str(rec.default_value),
697
+ reference: str(rec.reference), reference_display: str(rec.reference_display),
698
+ use_dependent: str(rec.use_dependent_field) === 'true',
699
+ dependent_on: str(rec.dependent_on_field),
700
+ attributes: str(rec.attributes)
701
+ };
702
+ });
703
+ source = 'table_api';
704
+ fetchError = '';
705
+ }
440
706
  } catch (tiErr: any) {
441
707
  fetchError += '; table_api_inputs: ' + (tiErr.message || 'unknown');
442
708
  }
@@ -452,127 +718,62 @@ async function buildTriggerInputsForInsert(
452
718
  }
453
719
  });
454
720
  var tableOutputs = toResp.data.result || [];
455
- apiOutputs = tableOutputs.map(function (rec: any) {
456
- return {
457
- id: str(rec.sys_id), name: str(rec.element), label: str(rec.label) || str(rec.element),
458
- type: str(rec.internal_type) || 'string',
459
- type_label: TYPE_LABELS[str(rec.internal_type) || 'string'] || str(rec.internal_type),
460
- mandatory: str(rec.mandatory) === 'true',
461
- order: parseInt(str(rec.order) || '0', 10),
462
- maxsize: parseInt(str(rec.max_length) || '200', 10),
463
- hint: str(rec.hint), reference: str(rec.reference), reference_display: str(rec.reference_display),
464
- use_dependent: str(rec.use_dependent_field) === 'true',
465
- dependent_on: str(rec.dependent_on_field),
466
- attributes: str(rec.attributes)
467
- };
468
- });
721
+ if (tableOutputs.length > 0) {
722
+ apiOutputs = tableOutputs.map(function (rec: any) {
723
+ return {
724
+ id: str(rec.sys_id), name: str(rec.element), label: str(rec.label) || str(rec.element),
725
+ type: str(rec.internal_type) || 'string',
726
+ type_label: TYPE_LABELS[str(rec.internal_type) || 'string'] || str(rec.internal_type),
727
+ mandatory: str(rec.mandatory) === 'true',
728
+ order: parseInt(str(rec.order) || '0', 10),
729
+ maxsize: parseInt(str(rec.max_length) || '200', 10),
730
+ hint: str(rec.hint), reference: str(rec.reference), reference_display: str(rec.reference_display),
731
+ use_dependent: str(rec.use_dependent_field) === 'true',
732
+ dependent_on: str(rec.dependent_on_field),
733
+ attributes: str(rec.attributes)
734
+ };
735
+ });
736
+ }
469
737
  } catch (_) {}
470
738
  }
471
739
 
472
- // Transform inputs into GraphQL mutation format (matching exact UI structure)
473
- var inputs = apiInputs.map(function (inp: any) {
474
- var paramType = inp.type || 'string';
475
- var name = inp.name || '';
476
- var label = inp.label || name;
477
- var attrs = typeof inp.attributes === 'object' ? flattenAttributes(inp.attributes) : (inp.attributes || '');
478
-
479
- // Determine value: user-provided > default
480
- var value = '';
481
- if (name === 'table' && userTable) value = userTable;
482
- else if (name === 'condition') value = userCondition || '^EQ';
483
- else if (inp.defaultValue) value = inp.defaultValue;
484
-
485
- var parameter: any = {
486
- id: inp.id || '', label: label, name: name, type: paramType,
487
- type_label: inp.type_label || TYPE_LABELS[paramType] || paramType,
488
- order: inp.order || 0, extended: inp.extended || false,
489
- mandatory: inp.mandatory || false, readonly: inp.readonly || false,
490
- maxsize: inp.maxsize || 4000, data_structure: '',
491
- reference: inp.reference || '', reference_display: inp.reference_display || '',
492
- ref_qual: inp.ref_qual || '', choiceOption: inp.choiceOption || '',
493
- table: '', columnName: '', defaultValue: inp.defaultValue || '',
494
- use_dependent: inp.use_dependent || false, dependent_on: inp.dependent_on || '',
495
- internal_link: inp.internal_link || '', show_ref_finder: inp.show_ref_finder || false,
496
- local: inp.local || false, attributes: attrs, sys_class_name: '', children: []
497
- };
498
- if (inp.hint) parameter.hint = inp.hint;
499
- if (inp.defaultDisplayValue) parameter.defaultDisplayValue = inp.defaultDisplayValue;
500
- if (inp.choices) parameter.choices = inp.choices;
501
- if (inp.defaultChoices) parameter.defaultChoices = inp.defaultChoices;
502
-
503
- var inputObj: any = {
504
- name: name, label: label, internalType: paramType,
505
- mandatory: inp.mandatory || false, order: inp.order || 0,
506
- valueSysId: '', field_name: name, type: paramType, children: [],
507
- displayValue: { value: '' },
508
- value: value ? { schemaless: false, schemalessValue: '', value: value } : { value: '' },
509
- parameter: parameter
510
- };
740
+ // Strategy 3: Hardcoded fallback for record-based triggers (ultimate safety net)
741
+ // Uses exact definitions captured from the Flow Designer UI
742
+ var isRecordTrigger = /record/.test(trigType.toLowerCase());
743
+ if (apiInputs.length === 0 && isRecordTrigger) {
744
+ apiInputs = getRecordTriggerFallbackInputs();
745
+ source = 'hardcoded_fallback';
746
+ }
747
+ if (apiOutputs.length === 0 && isRecordTrigger) {
748
+ apiOutputs = getRecordTriggerFallbackOutputs();
749
+ }
511
750
 
512
- // Add choiceList for choice-type inputs (top-level, matching UI format)
513
- if (inp.choices && Array.isArray(inp.choices)) {
514
- inputObj.choiceList = inp.choices.map(function (c: any) {
515
- return { label: c.label, value: c.value };
516
- });
751
+ // Transform to GraphQL mutation format
752
+ var inputs = apiInputs.map(function (inp: any) { return buildTriggerInputObj(inp, userTable, userCondition); });
753
+ var outputs = apiOutputs.map(function (out: any) { return buildTriggerOutputObj(out); });
754
+
755
+ // Final safety net: ensure table and condition inputs are ALWAYS present for record triggers
756
+ if (isRecordTrigger) {
757
+ var hasTable = inputs.some(function (i: any) { return i.name === 'table'; });
758
+ var hasCondition = inputs.some(function (i: any) { return i.name === 'condition'; });
759
+ if (!hasTable) {
760
+ inputs.unshift(buildTriggerInputObj(
761
+ { name: 'table', label: 'Table', type: 'table_name', type_label: 'Table Name', mandatory: true, order: 1, maxsize: 80, attributes: 'filter_table_source=RECORD_WATCHER_RESTRICTED,' },
762
+ userTable, userCondition
763
+ ));
764
+ source += '+table_injected';
517
765
  }
518
-
519
- return inputObj;
520
- });
521
-
522
- // Transform outputs into GraphQL mutation format
523
- var outputs = apiOutputs.map(function (out: any) {
524
- var paramType = out.type || 'string';
525
- var name = out.name || '';
526
- var label = out.label || name;
527
- var attrs = typeof out.attributes === 'object' ? flattenAttributes(out.attributes) : (out.attributes || '');
528
-
529
- var parameter: any = {
530
- id: out.id || '', label: label, name: name, type: paramType,
531
- type_label: out.type_label || TYPE_LABELS[paramType] || paramType,
532
- hint: out.hint || '', order: out.order || 0, extended: out.extended || false,
533
- mandatory: out.mandatory || false, readonly: out.readonly || false,
534
- maxsize: out.maxsize || 200, data_structure: '',
535
- reference: out.reference || '', reference_display: out.reference_display || '',
536
- ref_qual: '', choiceOption: '', table: '', columnName: '', defaultValue: '',
537
- use_dependent: out.use_dependent || false, dependent_on: out.dependent_on || '',
538
- internal_link: out.internal_link || '', show_ref_finder: false, local: false,
539
- attributes: attrs, sys_class_name: ''
540
- };
541
-
542
- // Build children for complex types (like array.object)
543
- var children: any[] = [];
544
- var paramChildren: any[] = [];
545
- if (out.children && Array.isArray(out.children)) {
546
- children = out.children.map(function (child: any) {
547
- return { id: '', name: child.name || '', scriptActive: false, children: [], value: { value: '' }, script: null };
548
- });
549
- paramChildren = out.children.map(function (child: any) {
550
- return {
551
- id: '', label: child.label || child.name || '', name: child.name || '',
552
- type: child.type || 'string', type_label: child.type_label || TYPE_LABELS[child.type || 'string'] || 'String',
553
- hint: '', order: child.order || 0, extended: false, mandatory: false, readonly: false, maxsize: 0,
554
- data_structure: '', reference: '', reference_display: '', ref_qual: '', choiceOption: '',
555
- table: '', columnName: '', defaultValue: '', defaultDisplayValue: '',
556
- use_dependent: false, dependent_on: false, show_ref_finder: false, local: false,
557
- attributes: '', sys_class_name: '',
558
- uiDisplayType: child.uiDisplayType || child.type || 'string',
559
- uiDisplayTypeLabel: child.type_label || 'String',
560
- internal_link: '', value: '', display_value: '', scriptActive: false,
561
- parent: out.id || '',
562
- fieldFacetMap: 'uiTypeLabel=' + (child.type_label || 'String') + ',',
563
- children: [], script: null
564
- };
565
- });
766
+ if (!hasCondition) {
767
+ var condIdx = inputs.findIndex(function (i: any) { return i.name === 'table'; });
768
+ inputs.splice(condIdx + 1, 0, buildTriggerInputObj(
769
+ { name: 'condition', label: 'Condition', type: 'conditions', type_label: 'Conditions', mandatory: false, order: 100, maxsize: 4000, use_dependent: true, dependent_on: 'table', attributes: 'extended_operators=VALCHANGES;CHANGESFROM;CHANGESTO,wants_to_add_conditions=true,modelDependent=trigger_inputs,' },
770
+ userTable, userCondition
771
+ ));
772
+ source += '+condition_injected';
566
773
  }
567
- parameter.children = paramChildren;
568
-
569
- return {
570
- name: name, value: '', displayValue: '', type: paramType,
571
- order: out.order || 0, label: label, children: children, parameter: parameter
572
- };
573
- });
774
+ }
574
775
 
575
- return { inputs, outputs, error: fetchError || undefined };
776
+ return { inputs, outputs, source: source || 'none', error: fetchError || undefined };
576
777
  }
577
778
 
578
779
  async function addTriggerViaGraphQL(
@@ -643,8 +844,8 @@ async function addTriggerViaGraphQL(
643
844
  if (!trigDefId) return { success: false, error: 'Trigger definition not found for: ' + triggerType, steps };
644
845
 
645
846
  // Build full trigger inputs and outputs from triggerpicker API (matching UI format)
646
- var triggerData = await buildTriggerInputsForInsert(client, trigDefId!, table, condition);
647
- steps.trigger_data = { inputCount: triggerData.inputs.length, outputCount: triggerData.outputs.length, error: triggerData.error };
847
+ var triggerData = await buildTriggerInputsForInsert(client, trigDefId!, trigType, table, condition);
848
+ steps.trigger_data = { inputCount: triggerData.inputs.length, outputCount: triggerData.outputs.length, source: triggerData.source, error: triggerData.error };
648
849
 
649
850
  const triggerResponseFields = 'triggerInstances { inserts { sysId uiUniqueIdentifier __typename } updates deletes __typename }';
650
851
  try {