@jacebenson/jsn 3.4.2 → 3.4.3

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
  "name": "@jacebenson/jsn",
3
- "version": "3.4.2",
3
+ "version": "3.4.3",
4
4
  "description": "A command-line interface for ServiceNow that follows the Unix philosophy: simple, composable, and scriptable.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -139,7 +139,7 @@ export function flowsCmd(wrap) {
139
139
  };
140
140
  }
141
141
 
142
- async function formatFlowInspection(inspection, ctx) {
142
+ export async function formatFlowInspection(inspection, ctx) {
143
143
  const lines = [];
144
144
  const instanceURL = ctx?.instanceURL || '';
145
145
  const flow = inspection.flow;
@@ -156,6 +156,27 @@ async function formatFlowInspection(inspection, ctx) {
156
156
  lines.push(` Link: ${instanceURL}/sys_hub_flow.do?sys_id=${flow.sysID}`);
157
157
  }
158
158
 
159
+ // Flow variables section
160
+ if (inspection.flowVariables && inspection.flowVariables.length > 0) {
161
+ const vars = [...inspection.flowVariables].sort((a, b) => {
162
+ const ao = parseInt(getStringField(a, 'order'), 10) || 0;
163
+ const bo = parseInt(getStringField(b, 'order'), 10) || 0;
164
+ return ao - bo;
165
+ });
166
+ lines.push('');
167
+ lines.push('▶ FLOW VARIABLES');
168
+ lines.push('─'.repeat(50));
169
+ for (const v of vars) {
170
+ const name = firstNonEmpty(getStringField(v, 'label'), getStringField(v, 'name'), 'Variable');
171
+ const typeName = firstNonEmpty(getStringField(v, 'type_label'), getStringField(v, 'type'), '');
172
+ if (typeName) {
173
+ lines.push(` • ${name}: ${typeName}`);
174
+ } else {
175
+ lines.push(` • ${name}`);
176
+ }
177
+ }
178
+ }
179
+
159
180
  // Subflow I/O section
160
181
  if (flow.type && flow.type.toLowerCase() === 'subflow') {
161
182
  lines.push('');
@@ -480,7 +501,7 @@ async function formatStepLine(stepNum, pad, step, ctx) {
480
501
  }
481
502
  }
482
503
 
483
- function formatActionStep(stepNum, pad, action) {
504
+ export function formatActionStep(stepNum, pad, action) {
484
505
  const lines = [];
485
506
  let actionName = firstNonEmpty(
486
507
  getNestedString(action, 'actionType', 'fName'),
@@ -527,16 +548,22 @@ function formatActionStep(stepNum, pad, action) {
527
548
 
528
549
  let inputValue = firstNonEmpty(getStringField(raw, 'displayValue'), getStringField(raw, 'value'));
529
550
  if (!inputValue) continue;
530
- if (inputValue.length > 50) {
531
- inputValue = inputValue.slice(0, 47) + '...';
532
- }
533
551
 
534
552
  let label = inputName;
535
553
  if (raw.parameter && typeof raw.parameter === 'object') {
536
554
  label = firstNonEmpty(getStringField(raw.parameter, 'label'), label);
537
555
  }
538
556
 
539
- lines.push(`${pad} ${label}: ${inputValue}`);
557
+ // ServiceNow writes multi-field payloads (encoded-query style) as
558
+ // "field=value^field2=value2". Split those onto one line per field;
559
+ // plain long strings stay on a single line, untruncated.
560
+ if (inputValue.includes('^')) {
561
+ for (const field of inputValue.split('^')) {
562
+ if (field) lines.push(`${pad} ${label}: ${field}`);
563
+ }
564
+ } else {
565
+ lines.push(`${pad} ${label}: ${inputValue}`);
566
+ }
540
567
  }
541
568
  }
542
569
 
package/src/sdk.js CHANGED
@@ -245,6 +245,7 @@ export class SDKClient {
245
245
  subFlowInstances: [],
246
246
  flowInputs: [],
247
247
  flowOutputs: [],
248
+ flowVariables: [],
248
249
  };
249
250
 
250
251
  // 2) Prefer the ProcessFlow API — the Flow Designer UI's own source.
@@ -372,6 +373,20 @@ export class SDKClient {
372
373
  if (records) inspection.flowOutputs = records;
373
374
  }
374
375
 
376
+ // Flow variables fallback (payload.flowVariables may be empty on legacy
377
+ // payload shapes, but sys_hub_flow_variable rows exist for every flow).
378
+ // Note: the table only carries name/label/order — type is empty there, so
379
+ // prefer payload.flowVariables when available.
380
+ if (!inspection.flowVariables || inspection.flowVariables.length === 0) {
381
+ const varsQuery = new URLSearchParams();
382
+ varsQuery.set('sysparm_display_value', 'all');
383
+ varsQuery.set('sysparm_query', `model=${flowSysID}^ORDERBYorder`);
384
+ varsQuery.set('sysparm_fields', 'sys_id,name,label,type,order');
385
+ varsQuery.set('sysparm_limit', '200');
386
+ const records = await this.list('sys_hub_flow_variable', varsQuery);
387
+ if (records) inspection.flowVariables = records;
388
+ }
389
+
375
390
  return inspection;
376
391
  }
377
392
 
@@ -635,6 +650,9 @@ function extractPayloadData(inspection, payload) {
635
650
  const outputs = toMapSlice(payload.outputs);
636
651
  if (outputs) inspection.flowOutputs = outputs;
637
652
 
653
+ const flowVariables = toMapSlice(payload.flowVariables);
654
+ if (flowVariables) inspection.flowVariables = flowVariables;
655
+
638
656
  const triggerInstances = payload.triggerInstances;
639
657
  if (!Array.isArray(triggerInstances) || triggerInstances.length === 0) return;
640
658