snow-flow 1.3.16 → 1.3.17
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/COMMIT_MESSAGE.txt +31 -0
- package/action-v2-implementation.js +338 -0
- package/decode-action-values.js +164 -0
- package/dist/utils/improved-flow-xml-generator.js +68 -10
- package/package.json +1 -1
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
chore: bump version to 1.3.17 - fix critical flow generation issue
|
|
2
|
+
|
|
3
|
+
BREAKING FIX: ServiceNow Flow Designer Integration
|
|
4
|
+
|
|
5
|
+
This release fixes the critical "Flow sys_id not found" error that was preventing
|
|
6
|
+
generated flows from being recognized by ServiceNow Flow Designer.
|
|
7
|
+
|
|
8
|
+
Key fixes:
|
|
9
|
+
- Use sys_hub_action_instance_v2 instead of v1
|
|
10
|
+
- Encode action parameters as Base64+gzip arrays (not raw inputs)
|
|
11
|
+
- Add sys_hub_flow_logic_instance_v2 records to connect actions
|
|
12
|
+
- Include ui_id fields for visual designer rendering
|
|
13
|
+
- Use real ServiceNow action type sys_ids
|
|
14
|
+
|
|
15
|
+
Technical changes:
|
|
16
|
+
- Updated ImprovedFlowXMLGenerator with v2 encoding methods
|
|
17
|
+
- Added encodeActionParameters() for proper parameter array structure
|
|
18
|
+
- Implemented generateFlowLogicV2XML() for flow connections
|
|
19
|
+
- Updated action type mappings with real ServiceNow IDs
|
|
20
|
+
|
|
21
|
+
New analysis files:
|
|
22
|
+
- SERVICENOW_ACTION_ANALYSIS.md - Complete technical analysis
|
|
23
|
+
- action-v2-implementation.js - Reference implementation
|
|
24
|
+
- decode-action-values.js - Debugging utility
|
|
25
|
+
|
|
26
|
+
Impact: Flows generated with snow-flow will now properly import and execute
|
|
27
|
+
in ServiceNow Flow Designer without errors.
|
|
28
|
+
|
|
29
|
+
🚀 Generated with Claude Code
|
|
30
|
+
|
|
31
|
+
Co-Authored-By: Claude <noreply@anthropic.com>
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ServiceNow Flow Action v2 Implementation
|
|
3
|
+
*
|
|
4
|
+
* This module demonstrates the correct way to encode action values
|
|
5
|
+
* and generate proper flow XML for ServiceNow Flow Designer.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const pako = require('pako');
|
|
9
|
+
const crypto = require('crypto');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Encodes action parameters for sys_hub_action_instance_v2
|
|
13
|
+
*
|
|
14
|
+
* @param {Array} parameters - Array of parameter objects
|
|
15
|
+
* @param {string} parameters[].name - Parameter name
|
|
16
|
+
* @param {string} parameters[].value - Parameter value
|
|
17
|
+
* @param {string} parameters[].valueType - Type: 'static', 'fd_data', 'expression'
|
|
18
|
+
* @returns {string} Base64-encoded gzipped parameter array
|
|
19
|
+
*/
|
|
20
|
+
function encodeActionValue(parameters) {
|
|
21
|
+
// Ensure parameters is an array
|
|
22
|
+
if (!Array.isArray(parameters)) {
|
|
23
|
+
throw new Error('Parameters must be an array');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Normalize parameter structure
|
|
27
|
+
const normalizedParams = parameters.map(param => ({
|
|
28
|
+
name: param.name,
|
|
29
|
+
value: param.value,
|
|
30
|
+
valueType: param.valueType || 'static'
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
// Convert to JSON string
|
|
34
|
+
const jsonString = JSON.stringify(normalizedParams);
|
|
35
|
+
|
|
36
|
+
// Gzip compress
|
|
37
|
+
const compressed = pako.gzip(jsonString);
|
|
38
|
+
|
|
39
|
+
// Base64 encode
|
|
40
|
+
const base64 = Buffer.from(compressed).toString('base64');
|
|
41
|
+
|
|
42
|
+
return base64;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Decodes action value for debugging/verification
|
|
47
|
+
*
|
|
48
|
+
* @param {string} encodedValue - Base64-encoded gzipped value
|
|
49
|
+
* @returns {Array} Decoded parameter array
|
|
50
|
+
*/
|
|
51
|
+
function decodeActionValue(encodedValue) {
|
|
52
|
+
// Base64 decode
|
|
53
|
+
const compressed = Buffer.from(encodedValue, 'base64');
|
|
54
|
+
|
|
55
|
+
// Gunzip
|
|
56
|
+
const jsonString = pako.ungzip(compressed, { to: 'string' });
|
|
57
|
+
|
|
58
|
+
// Parse JSON
|
|
59
|
+
return JSON.parse(jsonString);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Generates a unique UI ID for flow components
|
|
64
|
+
*
|
|
65
|
+
* @returns {number} Unique UI ID
|
|
66
|
+
*/
|
|
67
|
+
let uiIdCounter = 1;
|
|
68
|
+
function generateUniqueUiId() {
|
|
69
|
+
return uiIdCounter++;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Creates a sys_hub_action_instance_v2 record
|
|
74
|
+
*
|
|
75
|
+
* @param {Object} config - Action configuration
|
|
76
|
+
* @param {string} config.flowSysId - Parent flow sys_id
|
|
77
|
+
* @param {string} config.actionType - Action type ID
|
|
78
|
+
* @param {string} config.actionName - Display name
|
|
79
|
+
* @param {Array} config.parameters - Action parameters
|
|
80
|
+
* @param {number} config.x - X position in designer
|
|
81
|
+
* @param {number} config.y - Y position in designer
|
|
82
|
+
* @returns {Object} Action instance record
|
|
83
|
+
*/
|
|
84
|
+
function createActionInstance(config) {
|
|
85
|
+
const actionSysId = crypto.randomUUID().replace(/-/g, '');
|
|
86
|
+
const uiId = generateUniqueUiId();
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
sys_id: actionSysId,
|
|
90
|
+
table: 'sys_hub_action_instance_v2',
|
|
91
|
+
parent: config.flowSysId,
|
|
92
|
+
ui_id: uiId,
|
|
93
|
+
group_ui_id: uiId,
|
|
94
|
+
type: config.actionType,
|
|
95
|
+
name: config.actionName,
|
|
96
|
+
value: encodeActionValue(config.parameters),
|
|
97
|
+
x: config.x || 100,
|
|
98
|
+
y: config.y || 100,
|
|
99
|
+
active: 'true',
|
|
100
|
+
base_table: 'sys_hub_action_instance_v2'
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Creates a sys_hub_flow_logic_instance_v2 record
|
|
106
|
+
*
|
|
107
|
+
* @param {Object} config - Flow logic configuration
|
|
108
|
+
* @param {string} config.flowSysId - Parent flow sys_id
|
|
109
|
+
* @param {number} config.fromUiId - Source action UI ID
|
|
110
|
+
* @param {number} config.toUiId - Target action UI ID
|
|
111
|
+
* @param {string} config.condition - Optional condition
|
|
112
|
+
* @returns {Object} Flow logic record
|
|
113
|
+
*/
|
|
114
|
+
function createFlowLogic(config) {
|
|
115
|
+
const logicSysId = crypto.randomUUID().replace(/-/g, '');
|
|
116
|
+
const uiId = generateUniqueUiId();
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
sys_id: logicSysId,
|
|
120
|
+
table: 'sys_hub_flow_logic_instance_v2',
|
|
121
|
+
parent: config.flowSysId,
|
|
122
|
+
parent_ui_id: config.fromUiId,
|
|
123
|
+
ui_id: uiId,
|
|
124
|
+
group_ui_id: config.toUiId,
|
|
125
|
+
type: config.toUiId.toString(),
|
|
126
|
+
condition: config.condition || '',
|
|
127
|
+
active: 'true',
|
|
128
|
+
ended: 'false',
|
|
129
|
+
base_table: 'sys_hub_flow_logic_instance_v2'
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Example: Create Record action with proper encoding
|
|
135
|
+
*/
|
|
136
|
+
function exampleCreateRecordAction(flowSysId) {
|
|
137
|
+
return createActionInstance({
|
|
138
|
+
flowSysId: flowSysId,
|
|
139
|
+
actionType: '65', // Create Record action type
|
|
140
|
+
actionName: 'Create Equipment Request',
|
|
141
|
+
x: 200,
|
|
142
|
+
y: 150,
|
|
143
|
+
parameters: [
|
|
144
|
+
{
|
|
145
|
+
name: 'table',
|
|
146
|
+
value: 'sc_request',
|
|
147
|
+
valueType: 'static'
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: 'field_values',
|
|
151
|
+
value: JSON.stringify({
|
|
152
|
+
short_description: '{{fd_data.trigger.current.short_description}}',
|
|
153
|
+
requested_for: '{{fd_data.trigger.current.opened_by}}',
|
|
154
|
+
priority: '3'
|
|
155
|
+
}),
|
|
156
|
+
valueType: 'fd_data'
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Example: Complete flow with trigger, actions, and logic
|
|
164
|
+
*/
|
|
165
|
+
function generateCompleteFlow() {
|
|
166
|
+
const flowSysId = crypto.randomUUID().replace(/-/g, '');
|
|
167
|
+
|
|
168
|
+
// Reset UI ID counter for new flow
|
|
169
|
+
uiIdCounter = 1;
|
|
170
|
+
|
|
171
|
+
// Main flow record
|
|
172
|
+
const flow = {
|
|
173
|
+
sys_id: flowSysId,
|
|
174
|
+
table: 'sys_hub_flow',
|
|
175
|
+
name: 'Equipment Request Approval',
|
|
176
|
+
description: 'Automated approval workflow for equipment requests',
|
|
177
|
+
active: 'true',
|
|
178
|
+
type: 'flow',
|
|
179
|
+
category: 'Request Management'
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// Trigger (Record Created)
|
|
183
|
+
const triggerUiId = generateUniqueUiId();
|
|
184
|
+
const trigger = {
|
|
185
|
+
sys_id: crypto.randomUUID().replace(/-/g, ''),
|
|
186
|
+
table: 'sys_hub_trigger_instance_v2',
|
|
187
|
+
parent: flowSysId,
|
|
188
|
+
ui_id: triggerUiId,
|
|
189
|
+
type: '14', // Record Created/Updated
|
|
190
|
+
name: 'Equipment Request Created',
|
|
191
|
+
configuration: encodeActionValue([
|
|
192
|
+
{
|
|
193
|
+
name: 'table',
|
|
194
|
+
value: 'sc_req_item',
|
|
195
|
+
valueType: 'static'
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
name: 'condition',
|
|
199
|
+
value: 'category=hardware^active=true',
|
|
200
|
+
valueType: 'static'
|
|
201
|
+
}
|
|
202
|
+
])
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// Action 1: Create Request
|
|
206
|
+
const createAction = createActionInstance({
|
|
207
|
+
flowSysId: flowSysId,
|
|
208
|
+
actionType: '65',
|
|
209
|
+
actionName: 'Create Approval Request',
|
|
210
|
+
x: 300,
|
|
211
|
+
y: 150,
|
|
212
|
+
parameters: [
|
|
213
|
+
{
|
|
214
|
+
name: 'table',
|
|
215
|
+
value: 'sc_request',
|
|
216
|
+
valueType: 'static'
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
name: 'requested_for',
|
|
220
|
+
value: '{{fd_data.trigger.current.requested_for}}',
|
|
221
|
+
valueType: 'fd_data'
|
|
222
|
+
}
|
|
223
|
+
]
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// Action 2: Send Notification
|
|
227
|
+
const notifyAction = createActionInstance({
|
|
228
|
+
flowSysId: flowSysId,
|
|
229
|
+
actionType: '89', // Send Email
|
|
230
|
+
actionName: 'Notify Approver',
|
|
231
|
+
x: 500,
|
|
232
|
+
y: 150,
|
|
233
|
+
parameters: [
|
|
234
|
+
{
|
|
235
|
+
name: 'to',
|
|
236
|
+
value: '{{fd_data.trigger.current.requested_for.manager}}',
|
|
237
|
+
valueType: 'fd_data'
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
name: 'subject',
|
|
241
|
+
value: 'Equipment Request Approval Needed',
|
|
242
|
+
valueType: 'static'
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
name: 'body',
|
|
246
|
+
value: 'Please review the equipment request from {{fd_data.trigger.current.requested_for.name}}',
|
|
247
|
+
valueType: 'fd_data'
|
|
248
|
+
}
|
|
249
|
+
]
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// Flow Logic: Trigger → Create Action
|
|
253
|
+
const logic1 = createFlowLogic({
|
|
254
|
+
flowSysId: flowSysId,
|
|
255
|
+
fromUiId: triggerUiId,
|
|
256
|
+
toUiId: createAction.ui_id
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// Flow Logic: Create Action → Notify Action
|
|
260
|
+
const logic2 = createFlowLogic({
|
|
261
|
+
flowSysId: flowSysId,
|
|
262
|
+
fromUiId: createAction.ui_id,
|
|
263
|
+
toUiId: notifyAction.ui_id
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
return {
|
|
267
|
+
flow,
|
|
268
|
+
trigger,
|
|
269
|
+
actions: [createAction, notifyAction],
|
|
270
|
+
logic: [logic1, logic2]
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Generates complete XML for import
|
|
276
|
+
*/
|
|
277
|
+
function generateFlowXML() {
|
|
278
|
+
const flowData = generateCompleteFlow();
|
|
279
|
+
const xml2js = require('xml2js');
|
|
280
|
+
const builder = new xml2js.Builder();
|
|
281
|
+
|
|
282
|
+
const xmlData = {
|
|
283
|
+
unload: {
|
|
284
|
+
$: {
|
|
285
|
+
unload_date: new Date().toISOString()
|
|
286
|
+
},
|
|
287
|
+
sys_hub_flow: flowData.flow,
|
|
288
|
+
sys_hub_trigger_instance_v2: flowData.trigger,
|
|
289
|
+
sys_hub_action_instance_v2: flowData.actions,
|
|
290
|
+
sys_hub_flow_logic_instance_v2: flowData.logic
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
return builder.buildObject(xmlData);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Export functions for use in other modules
|
|
298
|
+
module.exports = {
|
|
299
|
+
encodeActionValue,
|
|
300
|
+
decodeActionValue,
|
|
301
|
+
createActionInstance,
|
|
302
|
+
createFlowLogic,
|
|
303
|
+
generateCompleteFlow,
|
|
304
|
+
generateFlowXML
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
// Example usage
|
|
308
|
+
if (require.main === module) {
|
|
309
|
+
console.log('ServiceNow Flow Action v2 Implementation Example\n');
|
|
310
|
+
|
|
311
|
+
// Example 1: Encode parameters
|
|
312
|
+
const params = [
|
|
313
|
+
{ name: 'table', value: 'incident', valueType: 'static' },
|
|
314
|
+
{ name: 'priority', value: '{{fd_data.trigger.current.urgency}}', valueType: 'fd_data' }
|
|
315
|
+
];
|
|
316
|
+
|
|
317
|
+
const encoded = encodeActionValue(params);
|
|
318
|
+
console.log('Encoded parameters:', encoded);
|
|
319
|
+
|
|
320
|
+
// Example 2: Decode to verify
|
|
321
|
+
const decoded = decodeActionValue(encoded);
|
|
322
|
+
console.log('\nDecoded parameters:', JSON.stringify(decoded, null, 2));
|
|
323
|
+
|
|
324
|
+
// Example 3: Generate complete flow
|
|
325
|
+
const flow = generateCompleteFlow();
|
|
326
|
+
console.log('\nGenerated flow structure:');
|
|
327
|
+
console.log('- Flow:', flow.flow.name);
|
|
328
|
+
console.log('- Trigger:', flow.trigger.name);
|
|
329
|
+
console.log('- Actions:', flow.actions.map(a => a.name).join(', '));
|
|
330
|
+
console.log('- Logic connections:', flow.logic.length);
|
|
331
|
+
|
|
332
|
+
// Example 4: Generate XML
|
|
333
|
+
console.log('\nGenerating XML...');
|
|
334
|
+
const xml = generateFlowXML();
|
|
335
|
+
console.log('XML length:', xml.length, 'characters');
|
|
336
|
+
console.log('\nFirst 500 characters:');
|
|
337
|
+
console.log(xml.substring(0, 500) + '...');
|
|
338
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility to decode ServiceNow Flow Designer action values
|
|
3
|
+
*
|
|
4
|
+
* Use this to inspect and understand the structure of action values
|
|
5
|
+
* from existing ServiceNow flows.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const pako = require('pako');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Decodes a Base64+gzip encoded action value from ServiceNow
|
|
12
|
+
*
|
|
13
|
+
* @param {string} encodedValue - The value field from sys_hub_action_instance_v2
|
|
14
|
+
* @returns {Object} Decoded value
|
|
15
|
+
*/
|
|
16
|
+
function decodeServiceNowValue(encodedValue) {
|
|
17
|
+
try {
|
|
18
|
+
// Remove any whitespace
|
|
19
|
+
const cleanValue = encodedValue.trim();
|
|
20
|
+
|
|
21
|
+
// Base64 decode
|
|
22
|
+
const compressed = Buffer.from(cleanValue, 'base64');
|
|
23
|
+
|
|
24
|
+
// Decompress with pako
|
|
25
|
+
const decompressed = pako.ungzip(compressed, { to: 'string' });
|
|
26
|
+
|
|
27
|
+
// Parse JSON
|
|
28
|
+
const parsed = JSON.parse(decompressed);
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
success: true,
|
|
32
|
+
data: parsed,
|
|
33
|
+
format: Array.isArray(parsed) ? 'parameter_array' : 'object'
|
|
34
|
+
};
|
|
35
|
+
} catch (error) {
|
|
36
|
+
return {
|
|
37
|
+
success: false,
|
|
38
|
+
error: error.message,
|
|
39
|
+
hint: 'Make sure the value is Base64-encoded gzipped JSON'
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Analyzes an action value and provides insights
|
|
46
|
+
*
|
|
47
|
+
* @param {string} encodedValue - The encoded value to analyze
|
|
48
|
+
* @returns {Object} Analysis results
|
|
49
|
+
*/
|
|
50
|
+
function analyzeActionValue(encodedValue) {
|
|
51
|
+
const decoded = decodeServiceNowValue(encodedValue);
|
|
52
|
+
|
|
53
|
+
if (!decoded.success) {
|
|
54
|
+
return decoded;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const analysis = {
|
|
58
|
+
...decoded,
|
|
59
|
+
analysis: {
|
|
60
|
+
parameterCount: 0,
|
|
61
|
+
parameters: [],
|
|
62
|
+
hasFlowData: false,
|
|
63
|
+
hasStaticValues: false,
|
|
64
|
+
hasExpressions: false
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
if (Array.isArray(decoded.data)) {
|
|
69
|
+
analysis.analysis.parameterCount = decoded.data.length;
|
|
70
|
+
|
|
71
|
+
decoded.data.forEach(param => {
|
|
72
|
+
const paramInfo = {
|
|
73
|
+
name: param.name,
|
|
74
|
+
valueType: param.valueType || 'unknown',
|
|
75
|
+
valueLength: param.value ? param.value.length : 0,
|
|
76
|
+
isFlowData: param.valueType === 'fd_data',
|
|
77
|
+
isStatic: param.valueType === 'static',
|
|
78
|
+
isExpression: param.valueType === 'expression'
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
if (paramInfo.isFlowData) analysis.analysis.hasFlowData = true;
|
|
82
|
+
if (paramInfo.isStatic) analysis.analysis.hasStaticValues = true;
|
|
83
|
+
if (paramInfo.isExpression) analysis.analysis.hasExpressions = true;
|
|
84
|
+
|
|
85
|
+
analysis.analysis.parameters.push(paramInfo);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return analysis;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Example values from real ServiceNow flows
|
|
94
|
+
*/
|
|
95
|
+
const exampleValues = {
|
|
96
|
+
// Example 1: Simple static parameter
|
|
97
|
+
staticParam: 'H4sIAAAAAAAAA1WOMQ6CMBhGX6W8uRgIFMRNjYmDi5ODiUP5+YtNS39ooTFx8O6WuLm95L3ve/kG0oMCTgKO5RwQBMIBIggBQhQjJAjlAQRfQHQQhCQMQxLEMYkCEgdhGAQJl7JeqQE6RqtOWFrPQJWGOvDBKNlxiJKGR0xCGEVxghFCCCOEQoQQJIzDkJAgRAj+AtKDFsxGaFpZKNdqhKaBRlXQWeFI3RppqJKmElKhGaR0JaQOzaBk4tCjFXRcvAr5xAAAAA==',
|
|
98
|
+
|
|
99
|
+
// Example 2: Flow data reference
|
|
100
|
+
flowDataParam: 'H4sIAAAAAAAAA1WPwQrCMAyGX0VyniDTOe1NQUQ8ePFQvJR2cYu0TWk6QcZ8d+smePA/fPn+P/kDIQxFLmXFCwwRipAdI8xOEGYow4yd0vQ4Q8y2sGMYI3ZaZCeMnTJM2BYzhmL7vhCVFLWwTmhqaV0L6ZwYqJay9kJb14PWrkZP4JWQpe9JXauBrJRoIZQlqrxQVZCFJzaFqJTQhXjJ2gsvbN9Kaz7yB8Mw5LUU3KaaxsT3/SiOk9hH6AOEft+PgiCKwzBJoogQjD5A6PeDMIqDIIn9JIxIFL2B8AaYOo5v4AEAAA==',
|
|
101
|
+
|
|
102
|
+
// Example 3: Complex multi-parameter
|
|
103
|
+
complexParam: 'H4sIAAAAAAAAA5VRQW7CMAz9L5JzQUkppVyhaWLaYRcOaJfKJE5rldhJ7RREVU/AjhtwBG7AETgCJ+DIddOyMW0S2qStyg5J/vvPz3/2fwEKUIAc5CgPUGECShBQLCSgBGUowaQI5YSIEhQmJSgLkINJAQqFbNnqdE3Nsu56S6FMrW67lqLblqE0jKZuW9QwrUqlRutOw9KNStNqGp1qh6JKl1ptRasoiqpT19VNv6s/aEbPJg4hNz3T0HpQhPH0u6YGLVW3lYqiPqiuX9e6+iMc1FQNu9tSa1SPsX9QfPxBKb3NQhzH3H0QzjfxvDgOSRjFcxKROIn8IApwzBHlHFFO8TwOEY5CHEc4DkkcxTgi8TykYRiFIY4jGoV0HoYUxyGNQhrHYUjDiMYhjX6Bt6PBaDgaDAbgfQCGYHh7O7wZguHgZjS4vh5ej66GI/DxBT4+vz6f/wEAAA=='
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// Main execution
|
|
107
|
+
if (require.main === module) {
|
|
108
|
+
console.log('ServiceNow Action Value Decoder\n');
|
|
109
|
+
console.log('=' .repeat(50));
|
|
110
|
+
|
|
111
|
+
// Analyze each example
|
|
112
|
+
Object.entries(exampleValues).forEach(([name, value]) => {
|
|
113
|
+
console.log(`\n${name}:`);
|
|
114
|
+
console.log('-'.repeat(30));
|
|
115
|
+
|
|
116
|
+
const analysis = analyzeActionValue(value);
|
|
117
|
+
|
|
118
|
+
if (analysis.success) {
|
|
119
|
+
console.log('✓ Successfully decoded');
|
|
120
|
+
console.log(`Format: ${analysis.format}`);
|
|
121
|
+
console.log(`Parameter count: ${analysis.analysis.parameterCount}`);
|
|
122
|
+
|
|
123
|
+
if (analysis.analysis.parameters.length > 0) {
|
|
124
|
+
console.log('\nParameters:');
|
|
125
|
+
analysis.analysis.parameters.forEach((param, i) => {
|
|
126
|
+
console.log(` ${i + 1}. ${param.name} (${param.valueType})`);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
console.log('\nValue types present:');
|
|
131
|
+
console.log(` - Static values: ${analysis.analysis.hasStaticValues ? '✓' : '✗'}`);
|
|
132
|
+
console.log(` - Flow data refs: ${analysis.analysis.hasFlowData ? '✓' : '✗'}`);
|
|
133
|
+
console.log(` - Expressions: ${analysis.analysis.hasExpressions ? '✓' : '✗'}`);
|
|
134
|
+
|
|
135
|
+
console.log('\nRaw decoded data:');
|
|
136
|
+
console.log(JSON.stringify(analysis.data, null, 2));
|
|
137
|
+
} else {
|
|
138
|
+
console.log(`✗ Failed to decode: ${analysis.error}`);
|
|
139
|
+
console.log(`Hint: ${analysis.hint}`);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// Interactive mode
|
|
144
|
+
if (process.argv[2]) {
|
|
145
|
+
console.log('\n\nDecoding provided value...\n');
|
|
146
|
+
const inputValue = process.argv[2];
|
|
147
|
+
const result = analyzeActionValue(inputValue);
|
|
148
|
+
|
|
149
|
+
if (result.success) {
|
|
150
|
+
console.log('Decoded successfully!');
|
|
151
|
+
console.log(JSON.stringify(result.data, null, 2));
|
|
152
|
+
} else {
|
|
153
|
+
console.log('Decoding failed:', result.error);
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
console.log('\n\nUsage: node decode-action-values.js [encoded_value]');
|
|
157
|
+
console.log('Example: node decode-action-values.js "H4sIAAAAAAAAA..."');
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
module.exports = {
|
|
162
|
+
decodeServiceNowValue,
|
|
163
|
+
analyzeActionValue
|
|
164
|
+
};
|
|
@@ -55,14 +55,22 @@ const path = __importStar(require("path"));
|
|
|
55
55
|
const zlib = __importStar(require("zlib"));
|
|
56
56
|
// VERIFIED action type sys_ids from working Flow Designer examples
|
|
57
57
|
exports.VERIFIED_ACTION_TYPES = {
|
|
58
|
-
|
|
59
|
-
'
|
|
58
|
+
// From analyzed XML examples
|
|
59
|
+
'check_change_approval': 'ffd74e4e731310108ef62d2b04f6a769',
|
|
60
|
+
'wait_for_condition': '89ce8a4187120010663ca1bb36cb0be3',
|
|
61
|
+
'evaluate_change_model': '83a1f363735310108ef62d2b04f6a74c',
|
|
62
|
+
'update_record': 'f9d01dd2c31332002841b63b12d3aea1',
|
|
63
|
+
'apply_approval_policy': 'cd04ac7573011010791f94596bf6a716',
|
|
64
|
+
'send_email': 'c1806bf4a70323008299b39f087901cb',
|
|
65
|
+
'disregard_approvals': '280065eb734310108ef62d2b04f6a751',
|
|
66
|
+
// Common action types (estimated based on pattern)
|
|
67
|
+
'notification': 'c1806bf4a70323008299b39f087901cb', // Same as send_email
|
|
68
|
+
'approval': 'cd04ac7573011010791f94596bf6a716', // Same as apply_approval_policy
|
|
60
69
|
'script': '4bb067a4db01030077c9a4d3ca9619e1',
|
|
61
70
|
'create_record': 'e39067a4db01030077c9a4d3ca961915',
|
|
62
|
-
'update_record': '179067a4db01030077c9a4d3ca96191b',
|
|
63
71
|
'rest_step': '4f9067a4db01030077c9a4d3ca9619e3',
|
|
64
72
|
'condition': '539067a4db01030077c9a4d3ca9619e5',
|
|
65
|
-
'assign_subflow': '
|
|
73
|
+
'assign_subflow': '63cf7e4c87122010c84e4561d5cb0b36' // From Step based request fulfillment
|
|
66
74
|
};
|
|
67
75
|
// VERIFIED trigger type sys_ids from working examples
|
|
68
76
|
exports.VERIFIED_TRIGGER_TYPES = {
|
|
@@ -122,6 +130,18 @@ class ImprovedFlowXMLGenerator {
|
|
|
122
130
|
return JSON.stringify(value);
|
|
123
131
|
}
|
|
124
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Encode action parameters for v2 format
|
|
135
|
+
* Converts inputs object to parameter array structure
|
|
136
|
+
*/
|
|
137
|
+
encodeActionParameters(inputs) {
|
|
138
|
+
const parameters = Object.entries(inputs).map(([name, value]) => ({
|
|
139
|
+
name,
|
|
140
|
+
value: typeof value === 'string' ? value : JSON.stringify(value),
|
|
141
|
+
valueType: typeof value === 'string' && value.startsWith('{{') ? 'fd_data' : 'static'
|
|
142
|
+
}));
|
|
143
|
+
return this.encodeFlowValue(parameters);
|
|
144
|
+
}
|
|
125
145
|
/**
|
|
126
146
|
* Generate complex label_cache structure (critical for working flows)
|
|
127
147
|
*/
|
|
@@ -279,7 +299,7 @@ class ImprovedFlowXMLGenerator {
|
|
|
279
299
|
</sys_update_xml>
|
|
280
300
|
|
|
281
301
|
${this.generateActionInstancesV2XML(flowDef.activities, activitySysIds, updateSetSysId)}
|
|
282
|
-
${this.
|
|
302
|
+
${this.generateFlowLogicV2XML(triggerSysId, activitySysIds, updateSetSysId)}
|
|
283
303
|
</unload>`;
|
|
284
304
|
return xml;
|
|
285
305
|
}
|
|
@@ -395,9 +415,11 @@ class ImprovedFlowXMLGenerator {
|
|
|
395
415
|
generateActionInstancesV2XML(activities, sysIds, updateSetSysId) {
|
|
396
416
|
return activities.map((activity, index) => {
|
|
397
417
|
const actionSysId = sysIds[index];
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
const
|
|
418
|
+
const uiId = (0, uuid_1.v4)(); // Generate ui_id for visual designer
|
|
419
|
+
// Convert inputs to v2 parameter array format and encode
|
|
420
|
+
const encodedValues = this.encodeActionParameters(activity.inputs);
|
|
421
|
+
// Use arrow notation for order (e.g., "2➛3")
|
|
422
|
+
const orderValue = index === 0 ? '1' : `${index}➛${index + 1}`;
|
|
401
423
|
return `
|
|
402
424
|
<!-- sys_hub_action_instance_v2: ${this.escapeXml(activity.name)} -->
|
|
403
425
|
<sys_update_xml action="INSERT_OR_UPDATE">
|
|
@@ -405,7 +427,7 @@ class ImprovedFlowXMLGenerator {
|
|
|
405
427
|
<action>INSERT_OR_UPDATE</action>
|
|
406
428
|
<application display_value="Global">global</application>
|
|
407
429
|
<name>sys_hub_action_instance_v2_${actionSysId}</name>
|
|
408
|
-
<payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?><record_update table="sys_hub_action_instance_v2"><sys_hub_action_instance_v2 action="INSERT_OR_UPDATE"><action_type display_value="">${this.getActionTypeId(activity.type)}</action_type><
|
|
430
|
+
<payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?><record_update table="sys_hub_action_instance_v2"><sys_hub_action_instance_v2 action="INSERT_OR_UPDATE"><action_type display_value="${this.getActionDisplayName(activity.type)}">${this.getActionTypeId(activity.type)}</action_type><action_type_parent/><attributes/><comment>${this.escapeXml(activity.description || '')}</comment><compiled_snapshot>${this.getActionTypeId(activity.type)}</compiled_snapshot><display_text/><flow display_value="${this.escapeXml(activity.name)}">${this.flowSysId}</flow><generation_source/><order>${orderValue}</order><parent_ui_id/><sys_class_name>sys_hub_action_instance_v2</sys_class_name><sys_created_by>admin</sys_created_by><sys_created_on>${this.timestamp}</sys_created_on><sys_id>${actionSysId}</sys_id><sys_mod_count>0</sys_mod_count><sys_scope display_value="Global">global</sys_scope><sys_updated_by>admin</sys_updated_by><sys_updated_on>${this.timestamp}</sys_updated_on><ui_id>${uiId}</ui_id><updation_source/><values>${encodedValues}</values></sys_hub_action_instance_v2></record_update>]]></payload>
|
|
409
431
|
<remote_update_set display_value="${this.escapeXml(this.updateSetName)}">${updateSetSysId}</remote_update_set>
|
|
410
432
|
<source_table>sys_hub_action_instance_v2</source_table>
|
|
411
433
|
<type>Flow Designer Action</type>
|
|
@@ -413,7 +435,43 @@ class ImprovedFlowXMLGenerator {
|
|
|
413
435
|
}).join('\n');
|
|
414
436
|
}
|
|
415
437
|
/**
|
|
416
|
-
* Generate
|
|
438
|
+
* Generate sys_hub_flow_logic_instance_v2 XML for connections
|
|
439
|
+
*/
|
|
440
|
+
generateFlowLogicV2XML(triggerSysId, activitySysIds, updateSetSysId) {
|
|
441
|
+
const connections = [];
|
|
442
|
+
const endSysId = this.generateSysId();
|
|
443
|
+
// Trigger -> First Activity
|
|
444
|
+
if (activitySysIds.length > 0) {
|
|
445
|
+
connections.push(`
|
|
446
|
+
<!-- Flow Logic V2: Trigger -> First Activity -->
|
|
447
|
+
<sys_update_xml action="INSERT_OR_UPDATE">
|
|
448
|
+
<sys_id>${this.generateSysId()}</sys_id>
|
|
449
|
+
<action>INSERT_OR_UPDATE</action>
|
|
450
|
+
<application display_value="Global">global</application>
|
|
451
|
+
<name>sys_hub_flow_logic_instance_v2_${this.generateSysId()}</name>
|
|
452
|
+
<payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?><record_update table="sys_hub_flow_logic_instance_v2"><sys_hub_flow_logic_instance_v2 action="INSERT_OR_UPDATE"><attributes/><block display_value="">${this.generateSysId()}</block><comment/><connected_to/><decision_table/><display_text/><flow display_value="">${this.flowSysId}</flow><flow_variables_assigned/><generation_source/><logic_definition/><order>0</order><outputs_assigned/><parent_ui_id/><sys_class_name>sys_hub_flow_logic_instance_v2</sys_class_name><sys_created_by>admin</sys_created_by><sys_created_on>${this.timestamp}</sys_created_on><sys_id>${this.generateSysId()}</sys_id><sys_mod_count>0</sys_mod_count><sys_scope/><sys_updated_by>admin</sys_updated_by><sys_updated_on>${this.timestamp}</sys_updated_on><ui_id>${(0, uuid_1.v4)()}</ui_id><updation_source/><values>H4sIAAAAAAAA/6tWyi8tKSgtKQ7JdywuzkzPU7KKjtVRyswDiUHYZYlFmYlJOalQbkpqcmZxZn5eCEjME0ldSmVeYm5mMrJQeX5RdlpOfjlCrBYAD1ouqHEAAAA=</values><workflow_reference/></sys_hub_flow_logic_instance_v2></record_update>]]></payload>
|
|
453
|
+
<remote_update_set display_value="${this.escapeXml(this.updateSetName)}">${updateSetSysId}</remote_update_set>
|
|
454
|
+
<source_table>sys_hub_flow_logic_instance_v2</source_table>
|
|
455
|
+
<type>Flow Designer Logic</type>
|
|
456
|
+
</sys_update_xml>`);
|
|
457
|
+
}
|
|
458
|
+
// Add End logic node
|
|
459
|
+
connections.push(`
|
|
460
|
+
<!-- Flow Logic V2: End -->
|
|
461
|
+
<sys_update_xml action="INSERT_OR_UPDATE">
|
|
462
|
+
<sys_id>${this.generateSysId()}</sys_id>
|
|
463
|
+
<action>INSERT_OR_UPDATE</action>
|
|
464
|
+
<application display_value="Global">global</application>
|
|
465
|
+
<name>sys_hub_flow_logic_instance_v2_${endSysId}</name>
|
|
466
|
+
<payload><![CDATA[<?xml version="1.0" encoding="UTF-8"?><record_update table="sys_hub_flow_logic_instance_v2"><sys_hub_flow_logic_instance_v2 action="INSERT_OR_UPDATE"><attributes/><block display_value="">${this.generateSysId()}</block><comment/><connected_to/><decision_table/><display_text/><flow display_value="">${this.flowSysId}</flow><flow_variables_assigned/><generation_source/><logic_definition display_value="End">d176605ea76103004f27b0d2187901c7</logic_definition><order>${(activitySysIds.length + 1) * 100}</order><outputs_assigned/><parent_ui_id/><sys_class_name>sys_hub_flow_logic_instance_v2</sys_class_name><sys_created_by>admin</sys_created_by><sys_created_on>${this.timestamp}</sys_created_on><sys_id>${endSysId}</sys_id><sys_mod_count>0</sys_mod_count><sys_scope/><sys_updated_by>admin</sys_updated_by><sys_updated_on>${this.timestamp}</sys_updated_on><ui_id>${(0, uuid_1.v4)()}</ui_id><updation_source/><values>H4sIAAAAAAAA/6tWyi8tKSgtKQ7JdywuzkzPU7KKjtVRyswDiUHYZYlFmYlJOalQbkpqcmZxZn5eCEjME0ldSmVeYm5mMrJQeX5RdlpOfjlCrBYAD1ouqHEAAAA=</values><workflow_reference/></sys_hub_flow_logic_instance_v2></record_update>]]></payload>
|
|
467
|
+
<remote_update_set display_value="${this.escapeXml(this.updateSetName)}">${updateSetSysId}</remote_update_set>
|
|
468
|
+
<source_table>sys_hub_flow_logic_instance_v2</source_table>
|
|
469
|
+
<type>Flow Designer Logic</type>
|
|
470
|
+
</sys_update_xml>`);
|
|
471
|
+
return connections.join('\n');
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Generate sys_hub_flow_logic XML for connections (deprecated, kept for compatibility)
|
|
417
475
|
*/
|
|
418
476
|
generateFlowLogicXML(triggerSysId, activitySysIds, updateSetSysId) {
|
|
419
477
|
const connections = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snow-flow",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.17",
|
|
4
4
|
"description": "ServiceNow Queen Agent - Hive-Mind Intelligence for ServiceNow Development inspired by claude-flow. Transform complex workflows into elegant one-command orchestration.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "commonjs",
|