@uipath/audit-commands 1.202.1-preview.217 → 1.202.1-preview.238

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.
Files changed (2) hide show
  1. package/dist/index.js +224 -7
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -9189,7 +9189,165 @@ class FilterImplicitLimitError extends Error {
9189
9189
  this.instructions = "Pass --limit <n> to choose how many records the filter applies to. " + "To filter over all records, pass the command's maximum accepted --limit (see the option's description in --help).";
9190
9190
  }
9191
9191
  }
9192
- function applyFilter(data, filter) {
9192
+ function countRecords(data) {
9193
+ if (Array.isArray(data))
9194
+ return data.length;
9195
+ return data == null ? 0 : 1;
9196
+ }
9197
+ function availableFields(data) {
9198
+ const records = Array.isArray(data) ? data : [data];
9199
+ const keys = new Set;
9200
+ for (const record of records) {
9201
+ if (record && typeof record === "object" && !Array.isArray(record)) {
9202
+ for (const key of Object.keys(record))
9203
+ keys.add(key);
9204
+ }
9205
+ }
9206
+ return [...keys];
9207
+ }
9208
+ function decodeQuotedIdentifier(whole, inner) {
9209
+ const [error, decoded] = catchError2(() => JSON.parse(whole));
9210
+ if (!error && typeof decoded === "string")
9211
+ return decoded;
9212
+ return inner.replace(/\\(.)/g, "$1");
9213
+ }
9214
+ function referencedFields(filter) {
9215
+ const top = new Set;
9216
+ const nested = new Set;
9217
+ const withoutValueLiterals = filter.replace(/'(?:\\.|[^'\\])*'/g, " ").replace(/`(?:\\.|[^`\\])*`/g, " ");
9218
+ const isPathTail = (text, index) => text[index - 1] === "." && /[A-Za-z0-9_"]/.test(text[index - 2] ?? "");
9219
+ const quoted = [];
9220
+ const withoutLiterals = withoutValueLiterals.replace(/"((?:\\.|[^"\\])*)"/g, (whole, name, index) => {
9221
+ const isAlias = /^\s*:/.test(withoutValueLiterals.slice(index + whole.length));
9222
+ if (!isAlias) {
9223
+ quoted.push({
9224
+ name: decodeQuotedIdentifier(whole, name),
9225
+ index,
9226
+ tail: isPathTail(withoutValueLiterals, index)
9227
+ });
9228
+ }
9229
+ return `"${" ".repeat(whole.length - 2)}"`;
9230
+ });
9231
+ const descent = /[A-Za-z0-9_"]\s*[.[]/.exec(withoutLiterals);
9232
+ const rootEnd = descent ? descent.index + 1 : Number.POSITIVE_INFINITY;
9233
+ const place = (name, index, tail) => {
9234
+ if (tail || index >= rootEnd)
9235
+ nested.add(name);
9236
+ else
9237
+ top.add(name);
9238
+ };
9239
+ for (const entry of quoted)
9240
+ place(entry.name, entry.index, entry.tail);
9241
+ const identifiers = withoutLiterals.matchAll(/([A-Za-z_][A-Za-z0-9_]*)(\s*[:(])?/g);
9242
+ const reserved = new Set(["true", "false", "null", "and", "or", "not"]);
9243
+ for (const match of identifiers) {
9244
+ const [, name, trailing] = match;
9245
+ if (trailing || reserved.has(name))
9246
+ continue;
9247
+ place(name, match.index, isPathTail(withoutLiterals, match.index));
9248
+ }
9249
+ return {
9250
+ top: [...top],
9251
+ nested: [...nested].filter((name) => !top.has(name)),
9252
+ hasPredicate: /\[\s*\?/.test(withoutValueLiterals)
9253
+ };
9254
+ }
9255
+ function appearsBelowTopLevel(data, name) {
9256
+ let budget = 2000;
9257
+ const visit = (value, depth) => {
9258
+ if (budget-- <= 0 || depth > 4)
9259
+ return false;
9260
+ if (value === null || typeof value !== "object")
9261
+ return false;
9262
+ if (Array.isArray(value))
9263
+ return value.some((entry) => visit(entry, depth));
9264
+ const record = value;
9265
+ if (depth > 0 && Object.hasOwn(record, name))
9266
+ return true;
9267
+ return Object.values(record).some((entry) => visit(entry, depth + 1));
9268
+ };
9269
+ return visit(data, 0);
9270
+ }
9271
+ function alwaysNullKeys(records) {
9272
+ const objects = records.filter((r) => r != null && typeof r === "object" && !Array.isArray(r));
9273
+ if (objects.length === 0 || objects.length !== records.length)
9274
+ return [];
9275
+ const keys = [...new Set(objects.flatMap((o) => Object.keys(o)))];
9276
+ if (keys.length === 0)
9277
+ return [];
9278
+ const nullKeys = keys.filter((key) => objects.every((record) => record[key] === null));
9279
+ return nullKeys.length === keys.length ? nullKeys : [];
9280
+ }
9281
+ function carriesOnlyNulls(value) {
9282
+ if (value === null)
9283
+ return true;
9284
+ if (Array.isArray(value)) {
9285
+ return value.length > 0 && value.every(carriesOnlyNulls);
9286
+ }
9287
+ if (typeof value === "object" && value !== undefined) {
9288
+ const values = Object.values(value);
9289
+ return values.length > 0 && values.every(carriesOnlyNulls);
9290
+ }
9291
+ return false;
9292
+ }
9293
+ function nameList(names, cap2 = 12) {
9294
+ const shown = names.slice(0, cap2).map((n) => `\`${n}\``);
9295
+ const rest = names.length - shown.length;
9296
+ return shown.join(", ") + (rest > 0 ? `, and ${rest} more` : "");
9297
+ }
9298
+ function buildFilterWarning(filter, data, outcome) {
9299
+ const present = availableFields(data);
9300
+ const refs = referencedFields(filter);
9301
+ const unknown = refs.top.filter((name) => !present.includes(name) && !appearsBelowTopLevel(data, name));
9302
+ const unchecked = refs.nested.filter((name) => !present.includes(name));
9303
+ const count = countRecords(data);
9304
+ const scope = `${count} record(s)`;
9305
+ const isNotAField = (names) => `${nameList(names)} ${names.length === 1 ? "is not a field" : "are not fields"} on the ${scope} it read`;
9306
+ const soundness = unchecked.length > 0 ? `${nameList(unchecked)} ${unchecked.length === 1 ? "reads" : "read"} below the top level, so ${unchecked.length === 1 ? "it was" : "they were"} not checked against the record keys` : refs.top.length > 0 ? "every field it names exists" : "";
9307
+ const withSoundness = (base) => soundness ? `${base}, and ${soundness}` : base;
9308
+ let detail;
9309
+ let lede;
9310
+ if (outcome.kind === "null-elements") {
9311
+ lede = "returned only null values";
9312
+ const projected = `all ${outcome.count} of the elements it projected are null`;
9313
+ if (unknown.length > 0) {
9314
+ detail = `${projected}, because ${isNotAField(unknown)}`;
9315
+ } else if (unchecked.length > 0) {
9316
+ detail = withSoundness(projected);
9317
+ } else {
9318
+ detail = `${projected}, and every field it names exists — a multi-select list ` + `(\`[A, B]\`) reads each entry against \`Data\` itself, so on a list ` + `result use \`[].[A, B]\` or \`[].{a: A, b: B}\` to read the records`;
9319
+ }
9320
+ } else if (outcome.kind === "null-rows") {
9321
+ lede = "returned only null values";
9322
+ const projected = `every value it projected is null on all ${outcome.count} row(s)`;
9323
+ detail = unknown.length > 0 ? `${projected}, because ${isNotAField(unknown)}` : withSoundness(projected);
9324
+ } else if (outcome.kind === "null-values") {
9325
+ lede = "returned only null values";
9326
+ const projected = `every key it projected (${nameList(outcome.keys)}) is null`;
9327
+ const sameSet = unknown.length === outcome.keys.length && outcome.keys.every((k) => unknown.includes(k));
9328
+ if (sameSet) {
9329
+ detail = `${isNotAField(outcome.keys)}, so every key it projected is null`;
9330
+ } else if (unknown.length > 0) {
9331
+ detail = `${projected}, because ${isNotAField(unknown)}`;
9332
+ } else {
9333
+ detail = withSoundness(`${projected} on all ${scope}`);
9334
+ }
9335
+ } else {
9336
+ lede = "returned nothing";
9337
+ if (unknown.length > 0) {
9338
+ detail = isNotAField(unknown);
9339
+ } else {
9340
+ const selection = refs.hasPredicate ? "no record matched" : "the expression resolved to no value";
9341
+ detail = withSoundness(`${selection} — it read ${scope}`);
9342
+ }
9343
+ }
9344
+ const fields = present.length > 0 ? ` Available fields: ${nameList(present)}.` : "";
9345
+ return `--output-filter ${JSON.stringify(filter)} ${lede}: ${detail}.${fields}`;
9346
+ }
9347
+ function appendWarning(existing, note) {
9348
+ return existing ? `${existing} ${note}` : note;
9349
+ }
9350
+ function applyFilter(data, filter, onWarning) {
9193
9351
  const codec = requireJmespath();
9194
9352
  let result;
9195
9353
  try {
@@ -9197,9 +9355,34 @@ function applyFilter(data, filter) {
9197
9355
  } catch (err) {
9198
9356
  throw new FilterEvaluationError(filter, err);
9199
9357
  }
9200
- if (result == null)
9358
+ const inputCount = countRecords(data);
9359
+ const warn = (outcome) => {
9360
+ if (inputCount === 0)
9361
+ return;
9362
+ const note = buildFilterWarning(filter, data, outcome);
9363
+ getOutputSink().writeErr(`[WARN] ${note}
9364
+ `);
9365
+ onWarning?.(note);
9366
+ };
9367
+ const warnIfAllNull = (records) => {
9368
+ const keys = alwaysNullKeys(records);
9369
+ if (keys.length > 0)
9370
+ warn({ kind: "null-values", keys });
9371
+ };
9372
+ if (result == null) {
9373
+ warn({ kind: "empty" });
9201
9374
  return [];
9375
+ }
9202
9376
  if (Array.isArray(result)) {
9377
+ if (result.length === 0) {
9378
+ warn({ kind: "empty" });
9379
+ } else if (result.every((entry) => entry === null)) {
9380
+ warn({ kind: "null-elements", count: result.length });
9381
+ } else if (result.every((entry) => Array.isArray(entry)) && carriesOnlyNulls(result)) {
9382
+ warn({ kind: "null-rows", count: result.length });
9383
+ } else {
9384
+ warnIfAllNull(result);
9385
+ }
9203
9386
  if (result.length > 0 && typeof result[0] !== "object") {
9204
9387
  const fieldMatch = filter.match(/\.(\w+)$/);
9205
9388
  const key = fieldMatch ? fieldMatch[1] : "Value";
@@ -9207,10 +9390,30 @@ function applyFilter(data, filter) {
9207
9390
  }
9208
9391
  return result;
9209
9392
  }
9210
- if (typeof result === "object")
9393
+ if (typeof result === "object") {
9394
+ warnIfAllNull([result]);
9211
9395
  return result;
9396
+ }
9212
9397
  return { Value: result };
9213
9398
  }
9399
+ function filterFailureData(envelope) {
9400
+ const filter = getOutputFilter();
9401
+ const data = envelope.Data;
9402
+ if (!filter || data == null)
9403
+ return;
9404
+ let note;
9405
+ const [filterError, filtered] = catchError2(() => applyFilter(data, filter, (n) => {
9406
+ note = n;
9407
+ }));
9408
+ if (filterError) {
9409
+ envelope.Warning = appendWarning(envelope.Warning, `--output-filter was not applied, so Data is shown in full: ${filterError.message}`);
9410
+ return;
9411
+ }
9412
+ envelope.Data = filtered;
9413
+ if (note) {
9414
+ envelope.Warning = appendWarning(envelope.Warning, note);
9415
+ }
9416
+ }
9214
9417
  function defaultErrorCodeForResult(result) {
9215
9418
  switch (result) {
9216
9419
  case RESULTS.AuthenticationError:
@@ -9293,8 +9496,14 @@ var OutputFormatter;
9293
9496
  }
9294
9497
  const filter = getOutputFilter();
9295
9498
  if (filter) {
9296
- const filtered = applyFilter(data.Data, filter);
9499
+ let note;
9500
+ const filtered = applyFilter(data.Data, filter, (n) => {
9501
+ note = n;
9502
+ });
9297
9503
  data.Data = normalize ? normalizeDataKeys(filtered, verbatim, subtrees && { refs: subtrees.refs, mode: "skip" }) : filtered;
9504
+ if (note) {
9505
+ data.Warning = appendWarning(data.Warning, note);
9506
+ }
9298
9507
  }
9299
9508
  logOutput(normalizeOutputKeys(data), getOutputFormat(), options?.tableRowStyle);
9300
9509
  }
@@ -9322,6 +9531,7 @@ var OutputFormatter;
9322
9531
  delete envelope.TelemetryErrorClass;
9323
9532
  delete envelope.TelemetryTerminalOutcome;
9324
9533
  delete envelope.TelemetryTerminalSignal;
9534
+ filterFailureData(envelope);
9325
9535
  if (!suppressTelemetry) {
9326
9536
  telemetry.trackEvent(CommonTelemetryEvents.Error, {
9327
9537
  result: data.Result,
@@ -9370,13 +9580,20 @@ var OutputFormatter;
9370
9580
  OutputFormatter.log = log;
9371
9581
  function formatToString(data) {
9372
9582
  const filter = getOutputFilter();
9583
+ const envelope = data;
9373
9584
  if ("Data" in data && data.Data != null) {
9374
9585
  data.Data = normalizeDataKeys(data.Data);
9375
9586
  if (filter) {
9376
- data.Data = normalizeDataKeys(applyFilter(data.Data, filter));
9587
+ let note;
9588
+ data.Data = normalizeDataKeys(applyFilter(data.Data, filter, (n) => {
9589
+ note = n;
9590
+ }));
9591
+ if (note) {
9592
+ envelope.Warning = appendWarning(envelope.Warning, note);
9593
+ }
9377
9594
  }
9378
9595
  }
9379
- const output = normalizeOutputKeys(data);
9596
+ const output = normalizeOutputKeys(envelope);
9380
9597
  const lines = [];
9381
9598
  const sink = getOutputSink();
9382
9599
  printOutput(output, getOutputFormat(), (msg) => {
@@ -10743,4 +10960,4 @@ export {
10743
10960
  registerCommands
10744
10961
  };
10745
10962
 
10746
- //# debugId=EE5AB7024CA8ACC364756E2164756E21
10963
+ //# debugId=F5707193B3462A7864756E2164756E21
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@uipath/audit-commands",
3
3
  "license": "SEE LICENSE IN LICENSE.txt",
4
- "version": "1.202.1-preview.217",
4
+ "version": "1.202.1-preview.238",
5
5
  "description": "Admin CLI commands for the UiPath Audit Service — query event sources, paginate events, and export ZIPs from the long-term store. Library composed by admin-tool, not a standalone CLI tool.",
6
6
  "private": false,
7
7
  "repository": {
@@ -25,5 +25,5 @@
25
25
  "files": [
26
26
  "dist"
27
27
  ],
28
- "gitHead": "bd513110d03342230901ece289a303e5a0009404"
28
+ "gitHead": "537e43df1d3583633cfd3a0b88634f9ce3ba9d6b"
29
29
  }