snow-flow 3.6.14 β†’ 3.6.16

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.
@@ -720,7 +720,7 @@ ${args.recurring_price && args.recurring_price !== '0' ? `πŸ”„ Recurring: $${arg
720
720
  }
721
721
  /**
722
722
  * Create Catalog Variable
723
- * Uses item_option_new table
723
+ * Uses sc_cat_item_option table (CORRECTED TABLE NAME)
724
724
  */
725
725
  async createCatalogVariable(args) {
726
726
  try {
@@ -752,7 +752,8 @@ ${args.recurring_price && args.recurring_price !== '0' ? `πŸ”„ Recurring: $${arg
752
752
  tooltip: args.tooltip || ''
753
753
  };
754
754
  this.logger.info('🎯 Creating variable with payload:', variableData);
755
- const response = await this.client.createRecord('item_option_new', variableData);
755
+ // βœ… CORRECT TABLE NAME: Use sc_cat_item_option instead of item_option_new
756
+ const response = await this.client.createRecord('sc_cat_item_option', variableData);
756
757
  if (!response.success) {
757
758
  this.logger.error('❌ Variable creation failed:', {
758
759
  error: response.error,
@@ -765,7 +766,7 @@ ${args.recurring_price && args.recurring_price !== '0' ? `πŸ”„ Recurring: $${arg
765
766
  this.logger.info(`βœ… Variable created with sys_id: ${createdSysId}`);
766
767
  // πŸ” VERIFICATION: Check if variable was actually created
767
768
  this.logger.info('πŸ” Verifying variable creation...');
768
- const verification = await this.client.searchRecords('item_option_new', `sys_id=${createdSysId}`, 1);
769
+ const verification = await this.client.searchRecords('sc_cat_item_option', `sys_id=${createdSysId}`, 1);
769
770
  if (!verification.success || verification.data.result.length === 0) {
770
771
  this.logger.error('❌ VERIFICATION FAILED: Variable not found after creation!');
771
772
  throw new Error(`Variable creation verification failed - not found in database`);
@@ -806,19 +807,127 @@ ${args.help_text ? `❓ Help: ${args.help_text}` : ''}
806
807
  async createCatalogUIPolicy(args) {
807
808
  try {
808
809
  this.logger.info('Creating comprehensive catalog UI policy...');
809
- // Helper function to resolve variable names to sys_ids
810
+ // First, let's fetch ALL variables for this catalog item for debugging
811
+ this.logger.info(`πŸ“‹ Fetching all variables for catalog item ${args.cat_item} for debugging...`);
812
+ try {
813
+ const allVarsResponse = await this.client.searchRecords('sc_cat_item_option', `cat_item=${args.cat_item}`, 100);
814
+ if (allVarsResponse.success && allVarsResponse.data.result.length > 0) {
815
+ this.logger.info(`πŸ“Š Found ${allVarsResponse.data.result.length} variables for this catalog item:`);
816
+ allVarsResponse.data.result.forEach((v) => {
817
+ this.logger.info(` - Variable: name='${v.name}', sys_id='${v.sys_id}', question='${v.question_text}'`);
818
+ });
819
+ }
820
+ else {
821
+ this.logger.warn(`⚠️ No variables found for catalog item ${args.cat_item} - this might be a problem!`);
822
+ }
823
+ }
824
+ catch (error) {
825
+ this.logger.error(`❌ Failed to fetch variables for debugging:`, error);
826
+ }
827
+ // Helper function to resolve variable names to sys_ids with MULTIPLE FALLBACKS
810
828
  const resolveVariableId = async (variableName, catalogItem) => {
811
829
  // If already a sys_id, return as-is
812
830
  if (variableName && variableName.match(/^[a-f0-9]{32}$/)) {
831
+ this.logger.info(`βœ… Using sys_id directly: ${variableName}`);
813
832
  return variableName;
814
833
  }
815
- // Search for variable by name in this catalog item
816
- const varResponse = await this.client.searchRecords('item_option_new', `cat_item=${catalogItem}^name=${variableName}`, 1);
817
- if (varResponse.success && varResponse.data.result.length > 0) {
818
- return varResponse.data.result[0].sys_id;
834
+ this.logger.info(`πŸ” Resolving variable name '${variableName}' to sys_id for catalog item ${catalogItem}...`);
835
+ // Try multiple search strategies for maximum compatibility
836
+ const searchStrategies = [
837
+ // Strategy 1: Search by name field
838
+ {
839
+ query: `cat_item=${catalogItem}^name=${variableName}`,
840
+ description: 'by name field'
841
+ },
842
+ // Strategy 2: Search by name with LIKE operator
843
+ {
844
+ query: `cat_item=${catalogItem}^nameLIKE${variableName}`,
845
+ description: 'by name with LIKE'
846
+ },
847
+ // Strategy 3: Search by question_text
848
+ {
849
+ query: `cat_item=${catalogItem}^question_text=${variableName}`,
850
+ description: 'by question_text field'
851
+ },
852
+ // Strategy 4: Search all variables for this item and match manually
853
+ {
854
+ query: `cat_item=${catalogItem}`,
855
+ description: 'all variables for manual matching'
856
+ }
857
+ ];
858
+ for (const strategy of searchStrategies) {
859
+ this.logger.info(`πŸ” Trying strategy: ${strategy.description}`);
860
+ try {
861
+ const varResponse = await this.client.searchRecords('sc_cat_item_option', strategy.query, 50 // Get more results for manual matching
862
+ );
863
+ if (varResponse.success && varResponse.data.result.length > 0) {
864
+ // For the "all variables" strategy, try to match manually
865
+ if (strategy.description === 'all variables for manual matching') {
866
+ const match = varResponse.data.result.find((v) => v.name === variableName ||
867
+ v.question_text === variableName ||
868
+ v.name?.toLowerCase() === variableName.toLowerCase());
869
+ if (match) {
870
+ this.logger.info(`βœ… Found variable through manual matching: ${match.sys_id}`);
871
+ return match.sys_id;
872
+ }
873
+ }
874
+ else {
875
+ // Direct match found
876
+ const sysId = varResponse.data.result[0].sys_id;
877
+ this.logger.info(`βœ… Resolved '${variableName}' to sys_id: ${sysId} (${strategy.description})`);
878
+ return sysId;
879
+ }
880
+ }
881
+ }
882
+ catch (error) {
883
+ this.logger.warn(`⚠️ Strategy failed: ${strategy.description}`, error);
884
+ }
885
+ }
886
+ // If all strategies fail, try alternate table names (just in case)
887
+ const alternateTables = ['item_option_new', 'io_set_item_option'];
888
+ for (const table of alternateTables) {
889
+ this.logger.info(`πŸ” Trying alternate table: ${table}`);
890
+ try {
891
+ const varResponse = await this.client.searchRecords(table, `cat_item=${catalogItem}^name=${variableName}`, 1);
892
+ if (varResponse.success && varResponse.data.result.length > 0) {
893
+ const sysId = varResponse.data.result[0].sys_id;
894
+ this.logger.info(`βœ… Found in alternate table ${table}: ${sysId}`);
895
+ return sysId;
896
+ }
897
+ }
898
+ catch (error) {
899
+ this.logger.warn(`⚠️ Alternate table ${table} failed:`, error);
900
+ }
819
901
  }
820
- this.logger.warn(`Variable '${variableName}' not found for catalog item ${catalogItem}`);
821
- return variableName; // Return original if not found
902
+ this.logger.error(`❌ CRITICAL: Variable '${variableName}' not found in any table for catalog item ${catalogItem}`);
903
+ this.logger.error(`❌ This will cause the action to fail! Please use the sys_id directly instead of the name.`);
904
+ // Return the name but log a warning that this will fail
905
+ return variableName;
906
+ };
907
+ // Helper function to map operations to correct ServiceNow format
908
+ const mapOperatorToServiceNow = (operator) => {
909
+ const opMap = {
910
+ 'is': '=',
911
+ 'equals': '=',
912
+ 'is_not': '!=',
913
+ 'is not': '!=',
914
+ 'not equals': '!=',
915
+ 'contains': 'LIKE',
916
+ 'does_not_contain': 'NOT LIKE',
917
+ 'does not contain': 'NOT LIKE',
918
+ 'greater_than': '>',
919
+ 'greater than': '>',
920
+ 'less_than': '<',
921
+ 'less than': '<',
922
+ 'is_empty': 'ISEMPTY',
923
+ 'is empty': 'ISEMPTY',
924
+ 'is_not_empty': 'ISNOTEMPTY', // βœ… CRITICAL FIX: was missing!
925
+ 'is not empty': 'ISNOTEMPTY'
926
+ };
927
+ const normalizedOp = operator.toLowerCase().trim();
928
+ const mapped = opMap[normalizedOp] || operator;
929
+ this.logger.info(`🎯 Mapped operator '${operator}' -> '${mapped}'`);
930
+ return mapped;
822
931
  };
823
932
  // Build condition string from conditions array
824
933
  let conditionString = '';
@@ -834,47 +943,26 @@ ${args.help_text ? `❓ Help: ${args.help_text}` : ''}
834
943
  for (const condition of args.conditions) {
835
944
  // Resolve variable name to sys_id
836
945
  const variableId = await resolveVariableId(condition.catalog_variable, args.cat_item);
837
- // Build condition string in ServiceNow format
838
- // Format: variable_name=value^ORvariable_name2=value2
839
- const operator = condition.operation || '=';
840
- const connector = condition.and_or === 'OR' ? '^OR' : '^';
841
- // Map common operations to ServiceNow syntax
842
- let operatorSymbol = '=';
843
- switch (operator.toLowerCase()) {
844
- case 'is':
845
- case 'equals':
846
- operatorSymbol = '=';
847
- break;
848
- case 'is not':
849
- case 'not equals':
850
- operatorSymbol = '!=';
851
- break;
852
- case 'contains':
853
- operatorSymbol = 'CONTAINS';
854
- break;
855
- case 'greater than':
856
- operatorSymbol = '>';
857
- break;
858
- case 'less than':
859
- operatorSymbol = '<';
860
- break;
861
- case 'is empty':
862
- operatorSymbol = 'ISEMPTY';
863
- break;
864
- default:
865
- operatorSymbol = operator;
866
- }
867
- // Build the condition part
946
+ // Get the correct ServiceNow operator
947
+ const originalOperator = condition.operation || 'is';
948
+ const serviceNowOperator = mapOperatorToServiceNow(originalOperator);
949
+ // Safely get condition value (avoid undefined concatenation)
950
+ const conditionValue = condition.value || '';
951
+ // Build the condition part based on operator type
868
952
  let conditionPart = '';
869
- if (operatorSymbol === 'ISEMPTY') {
870
- conditionPart = `${variableId}ISEMPTY`;
953
+ if (serviceNowOperator === 'ISEMPTY' || serviceNowOperator === 'ISNOTEMPTY') {
954
+ // For empty/not empty checks, no value needed
955
+ conditionPart = `${variableId}${serviceNowOperator}`;
871
956
  }
872
- else if (operatorSymbol === 'CONTAINS') {
873
- conditionPart = `${variableId}LIKE${condition.value}`;
957
+ else if (serviceNowOperator === 'LIKE' || serviceNowOperator === 'NOT LIKE') {
958
+ // For LIKE operations, ensure value is wrapped properly
959
+ conditionPart = `${variableId}${serviceNowOperator}${conditionValue}`;
874
960
  }
875
961
  else {
876
- conditionPart = `${variableId}${operatorSymbol}${condition.value}`;
962
+ // Standard operations (=, !=, >, <, etc.)
963
+ conditionPart = `${variableId}${serviceNowOperator}${conditionValue}`;
877
964
  }
965
+ this.logger.info(`πŸ—οΈ Built condition part: ${conditionPart} (from ${originalOperator}: '${conditionValue}')`);
878
966
  conditionParts.push(conditionPart);
879
967
  }
880
968
  // Join all conditions with ^ separator (ServiceNow query format)
@@ -917,16 +1005,26 @@ ${args.help_text ? `❓ Help: ${args.help_text}` : ''}
917
1005
  // Resolve variable name to sys_id
918
1006
  this.logger.info(`πŸ” Resolving variable: ${action.catalog_variable} for catalog item: ${args.cat_item}`);
919
1007
  const variableId = await resolveVariableId(action.catalog_variable, args.cat_item);
920
- this.logger.info(`βœ… Resolved to variable ID: ${variableId}`);
921
- // Actions structuur in ServiceNow:
922
- // - catalog_ui_policy_action.catalog_variable -> item_option_new (variable)
923
- // - item_option_new.cat_item -> sc_cat_item (catalog item)
924
- // - catalog_ui_policy.catalog_item -> sc_cat_item (catalog item)
925
- // Mogelijk is er toch een ui_policy veld, maar het lijkt niet verplicht
926
- // MINIMAAL: Probeer eerst alleen de essentiΓ«le velden
1008
+ // Check if resolution actually worked (should be a sys_id now)
1009
+ const isValidSysId = variableId && variableId.match(/^[a-f0-9]{32}$/);
1010
+ if (!isValidSysId) {
1011
+ this.logger.error(`❌ CRITICAL: Failed to resolve variable '${action.catalog_variable}' to sys_id!`);
1012
+ this.logger.error(`❌ Got: ${variableId} (this is not a valid sys_id)`);
1013
+ // Continue anyway but it will likely fail
1014
+ }
1015
+ else {
1016
+ this.logger.info(`βœ… Resolved to variable sys_id: ${variableId}`);
1017
+ }
1018
+ // βœ… CRITICAL FIX: Add "IO:" prefix as required by ServiceNow
1019
+ // BUT ONLY if we have a valid sys_id!
1020
+ const catalogVariableWithPrefix = isValidSysId ? `IO:${variableId}` : variableId;
1021
+ this.logger.info(`🎯 Using catalog_variable value: ${catalogVariableWithPrefix}`);
1022
+ // Actions structure in ServiceNow:
1023
+ // - catalog_ui_policy_action.catalog_variable -> "IO:" + variable_sys_id (required format)
1024
+ // - catalog_ui_policy_action.ui_policy -> catalog_ui_policy.sys_id
927
1025
  const actionData = {
928
- // Hoofdkoppeling: naar de variable (dit MOET kloppen)
929
- catalog_variable: variableId
1026
+ // βœ… Main connection: to the variable with required IO: prefix (if valid sys_id)
1027
+ catalog_variable: catalogVariableWithPrefix
930
1028
  };
931
1029
  // NIET: catalog_ui_policy - deze veld bestaat NIET (volgens error log)
932
1030
  // Probeer alleen ui_policy en policy als alternatief
@@ -1255,7 +1353,7 @@ ${item.recurring_price && item.recurring_price !== '0' ? `πŸ”„ Recurring: $${ite
1255
1353
  πŸ”„ Active: ${item.active ? 'Yes' : 'No'}`;
1256
1354
  // Get variables if requested
1257
1355
  if (args.include_variables) {
1258
- const varResponse = await this.client.searchRecords('item_option_new', `cat_item=${args.sys_id}`, 50);
1356
+ const varResponse = await this.client.searchRecords('sc_cat_item_option', `cat_item=${args.sys_id}`, 50);
1259
1357
  if (varResponse.success && varResponse.data.result.length) {
1260
1358
  const variables = varResponse.data.result.map((v) => ` - ${v.question_text} (${v.type})${v.mandatory ? ' *Required' : ''}`).join('\n');
1261
1359
  details += `\n\nπŸ“‹ **Variables:**\n${variables}`;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "snow-flow",
3
- "version": "3.6.14",
4
- "description": "COMPREHENSIVE CATALOG FIXES - v3.6.14 fixes ALL catalog tools based on user feedback. snow_create_catalog_variable: added missing essential fields (active, display_type, security). snow_get_catalog_item_details: 3-method fallback system. snow_create_catalog_ui_policy: verification after creation. All tools now have extensive debugging and verification.",
3
+ "version": "3.6.16",
4
+ "description": "ENHANCED VARIABLE RESOLUTION - v3.6.16 adds comprehensive multi-strategy variable resolution with 4 different search methods, automatic debugging that shows all available variables, better error handling when resolution fails, and support for alternate table names. Now properly handles cases where variable names can't be resolved to sys_ids and provides clear warnings.",
5
5
  "main": "dist/index.js",
6
6
  "type": "commonjs",
7
7
  "bin": {