snow-flow 1.3.28 → 1.3.30

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.
@@ -0,0 +1,339 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Update Set XML Packager
5
+ *
6
+ * Properly packages Flow Designer XML into ServiceNow Update Sets
7
+ * with all required metadata and escaping
8
+ */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.UpdateSetXMLPackager = void 0;
44
+ exports.packageFlowForUpdateSet = packageFlowForUpdateSet;
45
+ const crypto = __importStar(require("crypto"));
46
+ const fs = __importStar(require("fs"));
47
+ const path = __importStar(require("path"));
48
+ class UpdateSetXMLPackager {
49
+ constructor() {
50
+ this.records = [];
51
+ this.updateSetId = this.generateSysId();
52
+ this.timestamp = new Date().toISOString();
53
+ }
54
+ /**
55
+ * Generate ServiceNow-compatible sys_id
56
+ */
57
+ generateSysId() {
58
+ return crypto.randomBytes(16).toString('hex');
59
+ }
60
+ /**
61
+ * Escape XML special characters
62
+ */
63
+ escapeXml(value) {
64
+ if (!value)
65
+ return '';
66
+ return value
67
+ .replace(/&/g, '&amp;')
68
+ .replace(/</g, '&lt;')
69
+ .replace(/>/g, '&gt;')
70
+ .replace(/"/g, '&quot;')
71
+ .replace(/'/g, '&apos;');
72
+ }
73
+ /**
74
+ * Add a record to the update set
75
+ */
76
+ addRecord(record) {
77
+ this.records.push(record);
78
+ }
79
+ /**
80
+ * Add flow components to update set
81
+ */
82
+ addFlowComponents(components) {
83
+ // Add flow record
84
+ if (components.flow) {
85
+ this.addRecord({
86
+ table: 'sys_hub_flow',
87
+ sys_id: components.flow.sys_id,
88
+ action: 'INSERT_OR_UPDATE',
89
+ payload: this.createRecordPayload('sys_hub_flow', components.flow),
90
+ type: 'Flow Designer Flow',
91
+ name: `sys_hub_flow_${components.flow.sys_id}`
92
+ });
93
+ }
94
+ // Add snapshot
95
+ if (components.snapshot) {
96
+ this.addRecord({
97
+ table: 'sys_hub_flow_snapshot',
98
+ sys_id: components.snapshot.sys_id,
99
+ action: 'INSERT_OR_UPDATE',
100
+ payload: this.createRecordPayload('sys_hub_flow_snapshot', components.snapshot),
101
+ type: 'Flow Designer Snapshot',
102
+ name: `sys_hub_flow_snapshot_${components.snapshot.sys_id}`
103
+ });
104
+ }
105
+ // Add trigger
106
+ if (components.trigger) {
107
+ this.addRecord({
108
+ table: 'sys_hub_trigger_instance_v2',
109
+ sys_id: components.trigger.sys_id,
110
+ action: 'INSERT_OR_UPDATE',
111
+ payload: this.createRecordPayload('sys_hub_trigger_instance_v2', components.trigger),
112
+ type: 'Flow Designer Trigger',
113
+ name: `sys_hub_trigger_instance_v2_${components.trigger.sys_id}`
114
+ });
115
+ }
116
+ // Add actions
117
+ components.actions?.forEach(action => {
118
+ this.addRecord({
119
+ table: 'sys_hub_action_instance_v2',
120
+ sys_id: action.sys_id,
121
+ action: 'INSERT_OR_UPDATE',
122
+ payload: this.createRecordPayload('sys_hub_action_instance_v2', action),
123
+ type: 'Flow Designer Action',
124
+ name: `sys_hub_action_instance_v2_${action.sys_id}`
125
+ });
126
+ });
127
+ // Add logic
128
+ components.logic?.forEach(logic => {
129
+ this.addRecord({
130
+ table: 'sys_hub_flow_logic_instance_v2',
131
+ sys_id: logic.sys_id,
132
+ action: 'INSERT_OR_UPDATE',
133
+ payload: this.createRecordPayload('sys_hub_flow_logic_instance_v2', logic),
134
+ type: 'Flow Designer Logic',
135
+ name: `sys_hub_flow_logic_instance_v2_${logic.sys_id}`
136
+ });
137
+ });
138
+ // Add variables
139
+ components.variables?.forEach(variable => {
140
+ this.addRecord({
141
+ table: 'sys_hub_flow_variable',
142
+ sys_id: variable.sys_id,
143
+ action: 'INSERT_OR_UPDATE',
144
+ payload: this.createRecordPayload('sys_hub_flow_variable', variable),
145
+ type: 'Flow Designer Variable',
146
+ name: `sys_hub_flow_variable_${variable.sys_id}`
147
+ });
148
+ });
149
+ }
150
+ /**
151
+ * Create record payload XML
152
+ */
153
+ createRecordPayload(table, record) {
154
+ const fields = Object.entries(record)
155
+ .filter(([key]) => !key.startsWith('_') && key !== 'sys_id')
156
+ .map(([key, value]) => {
157
+ if (value === null || value === undefined) {
158
+ return `<${key}/>`;
159
+ }
160
+ // Handle display values
161
+ const displayValue = record[`${key}_display_value`];
162
+ const displayAttr = displayValue ? ` display_value="${this.escapeXml(displayValue)}"` : '';
163
+ // Handle different value types
164
+ if (typeof value === 'boolean') {
165
+ return `<${key}${displayAttr}>${value}</${key}>`;
166
+ }
167
+ else if (typeof value === 'object') {
168
+ return `<${key}${displayAttr}>${this.escapeXml(JSON.stringify(value))}</${key}>`;
169
+ }
170
+ else {
171
+ return `<${key}${displayAttr}>${this.escapeXml(String(value))}</${key}>`;
172
+ }
173
+ })
174
+ .join('');
175
+ return `<?xml version="1.0" encoding="UTF-8"?><record_update table="${table}"><${table} action="INSERT_OR_UPDATE">${fields}<sys_id>${record.sys_id}</sys_id></${table}></record_update>`;
176
+ }
177
+ /**
178
+ * Generate complete Update Set XML
179
+ */
180
+ generateXML(metadata) {
181
+ const updateSetSysId = this.generateSysId();
182
+ // Build update records
183
+ const updateRecords = this.records.map(record => {
184
+ const updateXmlSysId = this.generateSysId();
185
+ return `
186
+ <sys_update_xml action="INSERT_OR_UPDATE">
187
+ <sys_id>${updateXmlSysId}</sys_id>
188
+ <action>${record.action}</action>
189
+ <application display_value="${metadata.application || 'Global'}">global</application>
190
+ <category>${record.category || 'customer'}</category>
191
+ <comments/>
192
+ <name>${record.name || record.table + '_' + record.sys_id}</name>
193
+ <payload><![CDATA[${record.payload}]]></payload>
194
+ <remote_update_set display_value="${this.escapeXml(metadata.name)}">${updateSetSysId}</remote_update_set>
195
+ <replace_on_upgrade>false</replace_on_upgrade>
196
+ <source_table>${record.table}</source_table>
197
+ <sys_class_name>sys_update_xml</sys_class_name>
198
+ <sys_created_by>admin</sys_created_by>
199
+ <sys_created_on>${this.timestamp}</sys_created_on>
200
+ <sys_id>${updateXmlSysId}</sys_id>
201
+ <sys_mod_count>0</sys_mod_count>
202
+ <sys_recorded_at>${this.timestamp}</sys_recorded_at>
203
+ <sys_updated_by>admin</sys_updated_by>
204
+ <sys_updated_on>${this.timestamp}</sys_updated_on>
205
+ <type>${record.type}</type>
206
+ <update_domain>global</update_domain>
207
+ <update_guid>${this.generateSysId()}${this.generateSysId()}</update_guid>
208
+ <update_set display_value=""/>
209
+ <view display_value="Default view">Default view</view>
210
+ </sys_update_xml>`;
211
+ }).join('\n');
212
+ // Build complete XML
213
+ return `<?xml version="1.0" encoding="UTF-8"?>
214
+ <unload unload_date="${this.timestamp}">
215
+ <!-- Remote Update Set -->
216
+ <sys_remote_update_set action="INSERT_OR_UPDATE">
217
+ <sys_id>${updateSetSysId}</sys_id>
218
+ <name>${this.escapeXml(metadata.name)}</name>
219
+ <description>${this.escapeXml(metadata.description || '')}</description>
220
+ <origin_sys_id>${updateSetSysId}</origin_sys_id>
221
+ <parent/>
222
+ <release_date>${metadata.release_date || ''}</release_date>
223
+ <remote_parent_id/>
224
+ <remote_sys_id>${updateSetSysId}</remote_sys_id>
225
+ <state>${metadata.state || 'loaded'}</state>
226
+ <summary/>
227
+ <sys_class_name>sys_remote_update_set</sys_class_name>
228
+ <sys_created_by>admin</sys_created_by>
229
+ <sys_created_on>${this.timestamp}</sys_created_on>
230
+ <sys_domain>global</sys_domain>
231
+ <sys_domain_path>/</sys_domain_path>
232
+ <sys_id>${updateSetSysId}</sys_id>
233
+ <sys_mod_count>0</sys_mod_count>
234
+ <sys_updated_by>admin</sys_updated_by>
235
+ <sys_updated_on>${this.timestamp}</sys_updated_on>
236
+ <update_set/>
237
+ <update_source/>
238
+ <version/>
239
+ </sys_remote_update_set>
240
+
241
+ ${updateRecords}
242
+ </unload>`;
243
+ }
244
+ /**
245
+ * Save XML to file
246
+ */
247
+ saveToFile(xml, filename) {
248
+ const outputDir = path.join(process.cwd(), 'flow-update-sets');
249
+ if (!fs.existsSync(outputDir)) {
250
+ fs.mkdirSync(outputDir, { recursive: true });
251
+ }
252
+ const outputFile = path.join(outputDir, filename || `update_set_${this.updateSetId}.xml`);
253
+ fs.writeFileSync(outputFile, xml, 'utf8');
254
+ return outputFile;
255
+ }
256
+ /**
257
+ * Create Update Set from existing flow XML
258
+ */
259
+ static packageFlowXML(flowXML, metadata) {
260
+ const packager = new UpdateSetXMLPackager();
261
+ // Parse existing XML to extract components
262
+ // This is a simplified version - real implementation would parse properly
263
+ const flowMatch = flowXML.match(/<sys_hub_flow[^>]*>[\s\S]*?<\/sys_hub_flow>/);
264
+ const snapshotMatch = flowXML.match(/<sys_hub_flow_snapshot[^>]*>[\s\S]*?<\/sys_hub_flow_snapshot>/);
265
+ if (flowMatch) {
266
+ packager.addRecord({
267
+ table: 'sys_hub_flow',
268
+ sys_id: packager.generateSysId(),
269
+ action: 'INSERT_OR_UPDATE',
270
+ payload: flowMatch[0],
271
+ type: 'Flow Designer Flow'
272
+ });
273
+ }
274
+ if (snapshotMatch) {
275
+ packager.addRecord({
276
+ table: 'sys_hub_flow_snapshot',
277
+ sys_id: packager.generateSysId(),
278
+ action: 'INSERT_OR_UPDATE',
279
+ payload: snapshotMatch[0],
280
+ type: 'Flow Designer Snapshot'
281
+ });
282
+ }
283
+ const xml = packager.generateXML(metadata);
284
+ const filePath = packager.saveToFile(xml);
285
+ return { xml, filePath };
286
+ }
287
+ /**
288
+ * Validate Update Set XML structure
289
+ */
290
+ static validateXML(xml) {
291
+ const errors = [];
292
+ // Check for required elements
293
+ if (!xml.includes('<sys_remote_update_set')) {
294
+ errors.push('Missing sys_remote_update_set element');
295
+ }
296
+ if (!xml.includes('<sys_update_xml')) {
297
+ errors.push('Missing sys_update_xml records');
298
+ }
299
+ // Check for proper CDATA wrapping
300
+ const payloadMatches = xml.match(/<payload>/g);
301
+ const cdataMatches = xml.match(/<!\[CDATA\[/g);
302
+ if (payloadMatches && cdataMatches && payloadMatches.length !== cdataMatches.length) {
303
+ errors.push('Payload elements not properly wrapped in CDATA');
304
+ }
305
+ // Check XML declaration
306
+ if (!xml.startsWith('<?xml version="1.0" encoding="UTF-8"?>')) {
307
+ errors.push('Missing or incorrect XML declaration');
308
+ }
309
+ return {
310
+ valid: errors.length === 0,
311
+ errors
312
+ };
313
+ }
314
+ }
315
+ exports.UpdateSetXMLPackager = UpdateSetXMLPackager;
316
+ // Export helper function
317
+ function packageFlowForUpdateSet(flowDefinition, updateSetName, description) {
318
+ const packager = new UpdateSetXMLPackager();
319
+ // Add all flow components
320
+ packager.addFlowComponents({
321
+ flow: flowDefinition.flow,
322
+ snapshot: flowDefinition.snapshot,
323
+ trigger: flowDefinition.trigger,
324
+ actions: flowDefinition.actions || [],
325
+ logic: flowDefinition.logic || [],
326
+ variables: flowDefinition.variables || []
327
+ });
328
+ // Generate XML
329
+ const xml = packager.generateXML({
330
+ name: updateSetName,
331
+ description: description || `Flow deployment: ${flowDefinition.flow?.name || 'Unknown'}`
332
+ });
333
+ // Save to file
334
+ const filePath = packager.saveToFile(xml);
335
+ // Validate
336
+ const validation = UpdateSetXMLPackager.validateXML(xml);
337
+ return { xml, filePath, validation };
338
+ }
339
+ exports.default = UpdateSetXMLPackager;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snow-flow",
3
- "version": "1.3.28",
3
+ "version": "1.3.30",
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",