@knowttl/mg-axi 0.1.1 → 0.1.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.
Files changed (48) hide show
  1. package/README.md +251 -77
  2. package/dist/api.js +253 -8
  3. package/dist/bin/mg-axi-hook.js +31 -0
  4. package/dist/catalogue.js +693 -2
  5. package/dist/cli.js +155 -17
  6. package/dist/docs.js +175 -46
  7. package/dist/doctor.js +2 -2
  8. package/dist/entra-access-reviews.js +11 -4
  9. package/dist/entra-apps.js +171 -14
  10. package/dist/entra-audit-logs.js +101 -16
  11. package/dist/entra-auth-methods.js +8 -4
  12. package/dist/entra-certificate-auth.js +12 -8
  13. package/dist/entra-conditional-access.js +425 -15
  14. package/dist/entra-contacts.js +19 -12
  15. package/dist/entra-contracts.js +7 -4
  16. package/dist/entra-custom-security-attributes.js +19 -12
  17. package/dist/entra-data-policy-operations.js +7 -4
  18. package/dist/entra-delegated-admin.js +55 -6
  19. package/dist/entra-deleted-items.js +6 -4
  20. package/dist/entra-directory-objects.js +6 -4
  21. package/dist/entra-directory.js +19 -12
  22. package/dist/entra-domains.js +13 -8
  23. package/dist/entra-entitlement-management.js +12 -4
  24. package/dist/entra-federation-configurations.js +7 -4
  25. package/dist/entra-grants.js +8 -4
  26. package/dist/entra-group-lifecycle.js +13 -8
  27. package/dist/entra-group-pim.js +431 -0
  28. package/dist/entra-groups.js +13 -8
  29. package/dist/entra-identity-providers.js +7 -4
  30. package/dist/entra-lifecycle-workflows.js +152 -13
  31. package/dist/entra-multi-tenant-organization.js +7 -4
  32. package/dist/entra-on-premises-synchronization.js +6 -4
  33. package/dist/entra-organization.js +13 -8
  34. package/dist/entra-risk-prevention.js +442 -0
  35. package/dist/entra-risk.js +224 -9
  36. package/dist/entra-roles.js +204 -12
  37. package/dist/entra-subscriptions.js +6 -4
  38. package/dist/entra-terms-of-use.js +13 -8
  39. package/dist/entra-users.js +7 -4
  40. package/dist/graph-session.js +30 -5
  41. package/dist/hook.js +84 -0
  42. package/dist/list-totals.js +52 -0
  43. package/dist/setup.js +9 -1
  44. package/docs/coverage.md +743 -610
  45. package/inventory/operations.json +2 -2
  46. package/inventory/schema.json +1 -1
  47. package/package.json +4 -3
  48. package/skills/mg-axi/SKILL.md +86 -1
@@ -1,8 +1,10 @@
1
1
  import { AxiError } from "axi-sdk-js";
2
+ import { listTotals } from "./list-totals.js";
2
3
  // EXT-02 lifecycle-workflows reads: the read-only workflow, workflow
3
4
  // template, task definition and tenant-settings first part, the
4
- // second-part top-level run and user/subject processing-result reads and
5
- // the third-part task-report reads. See
5
+ // second-part top-level run and user/subject processing-result reads, the
6
+ // third-part task-report reads and the fourth-part run-nested processing
7
+ // results. See
6
8
  // README.md for the supported commands and usage. Operation construction
7
9
  // stays beside its command; the shared session owns URLs, credentials,
8
10
  // paging, retries and error translation, and the SDK owns TOON rendering.
@@ -14,11 +16,13 @@ import { AxiError } from "axi-sdk-js";
14
16
  // workflowtemplate-get, lifecycleworkflowscontainer-list-taskdefinitions,
15
17
  // taskdefinition-get, lifecyclemanagementsettings-get, workflow-list-runs,
16
18
  // run-get, workflow-list-userprocessingresults, userprocessingresult-get,
17
- // run-list-subjectprocessingresults, subjectprocessingresult-get,
19
+ // run-list-userprocessingresults, run-list-subjectprocessingresults,
20
+ // subjectprocessingresult-get, run-list-taskprocessingresults,
18
21
  // workflow-list-taskreports and task-get operation documentation and the
19
22
  // reviewed resource property sets for workflow, workflowTemplate,
20
23
  // taskDefinition, lifecycleManagementSettings, run, userProcessingResult,
21
- // subjectProcessingResult, taskReport and task, on 2026-10-06.
24
+ // subjectProcessingResult, taskProcessingResult, taskReport and task, on
25
+ // 2026-10-06.
22
26
  // Workflow list/show take D/A
23
27
  // LifecycleWorkflows-Workflow.ReadBasic.All as the least privileged choice
24
28
  // (LifecycleWorkflows-Workflow.Read.All or LifecycleWorkflows.Read.All for
@@ -46,6 +50,15 @@ import { AxiError } from "axi-sdk-js";
46
50
  // taskDefinition navigations return the related objects whole (task
47
51
  // arguments and definition parameters ride along as reviewed fields) while
48
52
  // taskProcessingResults, the subject link and every $expand stay out.
53
+ // The run-nested user, subject and task processing-result singles share
54
+ // their top-level query contracts: the userprocessingresult-get page covers
55
+ // the run-nested user single and documents $select, the
56
+ // subjectprocessingresult-get page covers the run-nested subject single
57
+ // and documents $expand only (whole rows), and the run-nested task single
58
+ // has no operation-level page (like the taskReport-nested singles), so it
59
+ // arrives whole with --select refused. The taskProcessingResult subject,
60
+ // task and workflowSubject navigations stay out with $expand: task results
61
+ // are personal data and carry failure detail, never subject identity.
49
62
  // The taskReports list documents $select/$filter (with $orderby/$expand
50
63
  // unreviewed); the taskReport get and the taskReport-nested task and
51
64
  // taskDefinition singles have no operation-level page (the task-get page
@@ -53,14 +66,18 @@ import { AxiError } from "axi-sdk-js";
53
66
  // there), so those three singles arrive whole and are projected locally
54
67
  // with --fields (--select is refused before credentials). Processing results
55
68
  // are personal data: user and subject defaults carry status and counts
56
- // only, never the subject link. Deeper execution detail (run-nested and
57
- // third-level processing results, reprocessed runs, subjects, workflow and
58
- // template tasks, createdBy, lastModifiedBy, previewScope, executionScope,
59
- // versions, insights, deleted items, custom task extensions) needs its own
69
+ // only, never the subject link. Deeper execution detail (third-level
70
+ // processing results under a user or subject result, reprocessed runs,
71
+ // subjects, workflow and template tasks, createdBy, lastModifiedBy,
72
+ // previewScope, executionScope, versions, insights, deleted items, custom
73
+ // task extensions) needs its own
60
74
  // sub-read and stays out, as do the summary functions (bracketed start/end
61
75
  // arguments outside the session-guard function-binding allowlist).
62
76
  // Lifecycle workflows need Microsoft Entra ID Governance or Microsoft Entra
63
- // Suite (every governed user, not only administrators). No mutation (no
77
+ // Suite (every governed user, not only administrators). Run-nested results
78
+ // scope one run's processing outcomes: user results aggregate one user's
79
+ // execution, subject results mirror them for non-user subjects, and task
80
+ // results carry one task's outcome with failure detail. No mutation (no
64
81
  // workflow create/update/delete/activate/run, no settings update) and no
65
82
  // beta.
66
83
  // Workflows expose the configured joiner/mover/leaver automations. Only
@@ -163,6 +180,19 @@ export const KNOWN_SUBJECT_PROCESSING_FIELDS = [
163
180
  "workflowExecutionType",
164
181
  "workflowVersion",
165
182
  ];
183
+ // Task processing results carry one task's outcome within one run.
184
+ // failureReason and processingInfo are human-readable outcome detail (not
185
+ // identity); the subject, task and workflowSubject navigations carry the
186
+ // targeted identity and need $expand, so they stay out with it.
187
+ export const KNOWN_TASK_PROCESSING_FIELDS = [
188
+ "id",
189
+ "completedDateTime",
190
+ "createdDateTime",
191
+ "failureReason",
192
+ "processingInfo",
193
+ "processingStatus",
194
+ "startedDateTime",
195
+ ];
166
196
  // Task reports aggregate one workflow task's processing results within one
167
197
  // run. runId names the owning run; the task, taskDefinition and
168
198
  // taskProcessingResults relationships need their own sub-reads ($expand
@@ -202,6 +232,7 @@ const RUN_KNOWN = new Set(KNOWN_RUN_FIELDS);
202
232
  const USER_PROCESSING_KNOWN = new Set(KNOWN_USER_PROCESSING_FIELDS);
203
233
  const SUBJECT_PROCESSING_KNOWN = new Set(KNOWN_SUBJECT_PROCESSING_FIELDS);
204
234
  const TASK_REPORT_KNOWN = new Set(KNOWN_TASK_REPORT_FIELDS);
235
+ const TASK_PROCESSING_KNOWN = new Set(KNOWN_TASK_PROCESSING_FIELDS);
205
236
  const TASK_KNOWN = new Set(KNOWN_TASK_FIELDS);
206
237
  // Compact rows: identifiers plus category and enablement state.
207
238
  const DEFAULT_WORKFLOW_LIST_SELECT = ["id", "displayName", "category", "isEnabled", "isSchedulingEnabled"];
@@ -221,6 +252,8 @@ const DEFAULT_USER_PROCESSING_LIST_SELECT = ["id", "processingStatus", "failedTa
221
252
  const DEFAULT_USER_PROCESSING_SHOW_SELECT = [...DEFAULT_USER_PROCESSING_LIST_SELECT];
222
253
  const DEFAULT_SUBJECT_PROCESSING_FIELDS = ["id", "subjectType", "processingStatus", "failedTasksCount", "totalTasksCount", "totalUnprocessedTasksCount"];
223
254
  // Compact task-report rows: identifiers plus the owning run and user counts.
255
+ const DEFAULT_TASK_PROCESSING_LIST_SELECT = ["id", "processingStatus", "failureReason"];
256
+ const DEFAULT_TASK_PROCESSING_SHOW_SELECT = [...KNOWN_TASK_PROCESSING_FIELDS];
224
257
  const DEFAULT_TASK_REPORT_LIST_SELECT = ["id", "runId", "processingStatus", "totalUsersCount", "failedUsersCount", "successfulUsersCount"];
225
258
  const DEFAULT_TASK_REPORT_SHOW_SELECT = [...KNOWN_TASK_REPORT_FIELDS];
226
259
  const DEFAULT_TASK_SHOW_SELECT = [...KNOWN_TASK_FIELDS];
@@ -361,9 +394,17 @@ function reportId(flags, help) {
361
394
  }
362
395
  return report;
363
396
  }
397
+ function runId(flags, help) {
398
+ const run = flags.run === undefined ? "" : String(flags.run);
399
+ if (!run.trim()) {
400
+ throw new AxiError("--run needs the parent lifecycle workflow run ID", "VALIDATION_ERROR", [help]);
401
+ }
402
+ return run;
403
+ }
364
404
  const WORKFLOW_LIST = {
365
405
  command: "entra lifecycle workflow list",
366
406
  key: "workflows",
407
+ totalsNoun: "workflows",
367
408
  known: WORKFLOW_KNOWN,
368
409
  knownList: KNOWN_WORKFLOW_FIELDS,
369
410
  defaultSelect: DEFAULT_WORKFLOW_LIST_SELECT,
@@ -378,6 +419,7 @@ const WORKFLOW_LIST = {
378
419
  const WORKFLOW_TEMPLATE_LIST = {
379
420
  command: "entra lifecycle workflow-template list",
380
421
  key: "workflowTemplates",
422
+ totalsNoun: "workflow templates",
381
423
  known: WORKFLOW_TEMPLATE_KNOWN,
382
424
  knownList: KNOWN_WORKFLOW_TEMPLATE_FIELDS,
383
425
  defaultSelect: DEFAULT_WORKFLOW_TEMPLATE_LIST_SELECT,
@@ -392,6 +434,7 @@ const WORKFLOW_TEMPLATE_LIST = {
392
434
  const TASK_DEFINITION_LIST = {
393
435
  command: "entra lifecycle task-definition list",
394
436
  key: "taskDefinitions",
437
+ totalsNoun: "task definitions",
395
438
  known: TASK_DEFINITION_KNOWN,
396
439
  knownList: KNOWN_TASK_DEFINITION_FIELDS,
397
440
  defaultSelect: DEFAULT_TASK_DEFINITION_LIST_SELECT,
@@ -406,6 +449,7 @@ const TASK_DEFINITION_LIST = {
406
449
  const RUN_LIST = {
407
450
  command: "entra lifecycle run list",
408
451
  key: "runs",
452
+ totalsNoun: "runs",
409
453
  known: RUN_KNOWN,
410
454
  knownList: KNOWN_RUN_FIELDS,
411
455
  defaultSelect: DEFAULT_RUN_LIST_SELECT,
@@ -420,6 +464,7 @@ const RUN_LIST = {
420
464
  const USER_PROCESSING_LIST = {
421
465
  command: "entra lifecycle user-processing-result list",
422
466
  key: "userProcessingResults",
467
+ totalsNoun: "user processing results",
423
468
  known: USER_PROCESSING_KNOWN,
424
469
  knownList: KNOWN_USER_PROCESSING_FIELDS,
425
470
  defaultSelect: DEFAULT_USER_PROCESSING_LIST_SELECT,
@@ -434,6 +479,7 @@ const USER_PROCESSING_LIST = {
434
479
  const SUBJECT_PROCESSING_LIST = {
435
480
  command: "entra lifecycle subject-processing-result list",
436
481
  key: "subjectProcessingResults",
482
+ totalsNoun: "subject processing results",
437
483
  known: SUBJECT_PROCESSING_KNOWN,
438
484
  knownList: KNOWN_SUBJECT_PROCESSING_FIELDS,
439
485
  defaultSelect: DEFAULT_SUBJECT_PROCESSING_FIELDS,
@@ -449,6 +495,7 @@ const SUBJECT_PROCESSING_LIST = {
449
495
  const TASK_REPORT_LIST = {
450
496
  command: "entra lifecycle task-report list",
451
497
  key: "taskReports",
498
+ totalsNoun: "task reports",
452
499
  known: TASK_REPORT_KNOWN,
453
500
  knownList: KNOWN_TASK_REPORT_FIELDS,
454
501
  defaultSelect: DEFAULT_TASK_REPORT_LIST_SELECT,
@@ -460,6 +507,52 @@ const TASK_REPORT_LIST = {
460
507
  `Show one task report: mg-axi entra lifecycle task-report show --workflow <workflow-id> --id <report-id> ${profileHint(profileName)}`,
461
508
  ],
462
509
  };
510
+ const RUN_USER_PROCESSING_LIST = {
511
+ command: "entra lifecycle run user-processing-result list",
512
+ key: "userProcessingResults",
513
+ totalsNoun: "user processing results",
514
+ known: USER_PROCESSING_KNOWN,
515
+ knownList: KNOWN_USER_PROCESSING_FIELDS,
516
+ defaultSelect: DEFAULT_USER_PROCESSING_LIST_SELECT,
517
+ defaultScopes: DEFAULT_REPORTS_SCOPES,
518
+ hints: REPORTS_DENIAL_HINTS,
519
+ emptyNote: "0 run user processing results matched; the absence of results is the answer, not an error",
520
+ standing: profileName => [
521
+ "Run user processing results aggregate one user's execution within one run and carry personal data: defaults stay minimal and the subject link is never requested",
522
+ `Show one run user processing result: mg-axi entra lifecycle run user-processing-result show --workflow <workflow-id> --run <run-id> --id <result-id> ${profileHint(profileName)}`,
523
+ ],
524
+ };
525
+ const RUN_SUBJECT_PROCESSING_LIST = {
526
+ command: "entra lifecycle run subject-processing-result list",
527
+ key: "subjectProcessingResults",
528
+ totalsNoun: "subject processing results",
529
+ known: SUBJECT_PROCESSING_KNOWN,
530
+ knownList: KNOWN_SUBJECT_PROCESSING_FIELDS,
531
+ defaultSelect: DEFAULT_SUBJECT_PROCESSING_FIELDS,
532
+ defaultScopes: DEFAULT_REPORTS_SCOPES,
533
+ hints: REPORTS_DENIAL_HINTS,
534
+ emptyNote: "0 run subject processing results matched; the absence of results is the answer, not an error",
535
+ queryless: true,
536
+ standing: profileName => [
537
+ "Run subject processing results mirror user results for non-user subjects within one run and carry personal data: rows arrive whole (Graph documents no $select on the list and $expand only on the get) and defaults stay minimal",
538
+ `Show one run subject processing result: mg-axi entra lifecycle run subject-processing-result show --workflow <workflow-id> --run <run-id> --id <result-id> ${profileHint(profileName)}`,
539
+ ],
540
+ };
541
+ const RUN_TASK_PROCESSING_LIST = {
542
+ command: "entra lifecycle run task-processing-result list",
543
+ key: "taskProcessingResults",
544
+ totalsNoun: "task processing results",
545
+ known: TASK_PROCESSING_KNOWN,
546
+ knownList: KNOWN_TASK_PROCESSING_FIELDS,
547
+ defaultSelect: DEFAULT_TASK_PROCESSING_LIST_SELECT,
548
+ defaultScopes: DEFAULT_REPORTS_SCOPES,
549
+ hints: REPORTS_DENIAL_HINTS,
550
+ emptyNote: "0 run task processing results matched; the absence of results is the answer, not an error",
551
+ standing: profileName => [
552
+ "Run task processing results carry one task's outcome within one run with failure detail: a task row never carries its subject, task or workflowSubject navigations; those belong to later slices",
553
+ `Show one run task processing result: mg-axi entra lifecycle run task-processing-result show --workflow <workflow-id> --run <run-id> --id <result-id> ${profileHint(profileName)}`,
554
+ ],
555
+ };
463
556
  async function listCollection(shape, session, flags, profile, operation, help, profileName, params = {}, resumeHint) {
464
557
  const cursor = flags.cursor === undefined ? undefined : String(flags.cursor);
465
558
  if (cursor !== undefined && !cursor.trim())
@@ -523,16 +616,17 @@ async function listCollection(shape, session, flags, profile, operation, help, p
523
616
  if (!result.complete) {
524
617
  return {
525
618
  [shape.key]: rows,
526
- count: { returned: rows.length, complete: false, reason: result.reason },
619
+ ...listTotals(rows.length, result.total, shape.totalsNoun, false),
620
+ complete: false,
621
+ reason: result.reason,
527
622
  cursor: result.cursor,
528
623
  help: [...truncationHints, resume, ...standing],
529
624
  };
530
625
  }
531
- const count = { returned: rows.length, complete: true };
532
626
  if (!rows.length) {
533
- return { [shape.key]: rows, count, help: [shape.emptyNote, ...standing] };
627
+ return { [shape.key]: rows, ...listTotals(rows.length, result.total, shape.totalsNoun, true), complete: true, help: [shape.emptyNote, ...standing] };
534
628
  }
535
- return { [shape.key]: rows, count, help: [...truncationHints, ...standing] };
629
+ return { [shape.key]: rows, ...listTotals(rows.length, result.total, shape.totalsNoun, true), complete: true, help: [...truncationHints, ...standing] };
536
630
  }
537
631
  async function showOne(key, command, known, knownList, defaultSelect, defaultScopes, hints, session, flags, profile, operation, help, profileName, params, malformed, queryless = false) {
538
632
  if (queryless && flags.select !== undefined) {
@@ -671,3 +765,48 @@ export async function showTaskReportTaskDefinition(session, flags, profile, oper
671
765
  const report = reportId(flags, help);
672
766
  return showOne("taskDefinition", "entra lifecycle task-report task-definition show", TASK_DEFINITION_KNOWN, KNOWN_TASK_DEFINITION_FIELDS, DEFAULT_TASK_DEFINITION_SHOW_SELECT, DEFAULT_REPORTS_SCOPES, REPORTS_DENIAL_HINTS, session, flags, profile, operation, help, profileName, { "workflow-id": workflow, "taskReport-id": report }, "Graph returned a malformed task definition body", true);
673
767
  }
768
+ export async function listRunUserProcessingResults(session, flags, profile, operation, help, profileName) {
769
+ const workflow = workflowId(flags, help);
770
+ const run = runId(flags, help);
771
+ return listCollection(RUN_USER_PROCESSING_LIST, session, flags, profile, operation, help, profileName, { "workflow-id": workflow, "run-id": run }, `Resume losslessly with the same --workflow --run and flags plus --cursor - ${profileHint(profileName)} and supply the returned cursor on stdin`);
772
+ }
773
+ export async function showRunUserProcessingResult(session, flags, profile, operation, help, profileName) {
774
+ const workflow = workflowId(flags, help);
775
+ const run = runId(flags, help);
776
+ return showOne("userProcessingResult", "entra lifecycle run user-processing-result show", USER_PROCESSING_KNOWN, KNOWN_USER_PROCESSING_FIELDS, DEFAULT_USER_PROCESSING_SHOW_SELECT, DEFAULT_REPORTS_SCOPES, REPORTS_DENIAL_HINTS, session, flags, profile, operation, help, profileName, { "workflow-id": workflow, "run-id": run, "userProcessingResult-id": String(flags.id) }, "Graph returned a malformed user processing result body");
777
+ }
778
+ export async function countRunUserProcessingResults(session, flags, profile, operation, help, profileName) {
779
+ const workflow = workflowId(flags, help);
780
+ const run = runId(flags, help);
781
+ return countCollection("run user processing result", RUN_USER_PROCESSING_LIST.emptyNote, DEFAULT_REPORTS_SCOPES, REPORTS_DENIAL_HINTS, session, flags, profile, operation, help, profileName, { "workflow-id": workflow, "run-id": run });
782
+ }
783
+ export async function listRunSubjectProcessingResults(session, flags, profile, operation, help, profileName) {
784
+ const workflow = workflowId(flags, help);
785
+ const run = runId(flags, help);
786
+ return listCollection(RUN_SUBJECT_PROCESSING_LIST, session, flags, profile, operation, help, profileName, { "workflow-id": workflow, "run-id": run }, `Resume losslessly with the same --workflow --run and flags plus --cursor - ${profileHint(profileName)} and supply the returned cursor on stdin`);
787
+ }
788
+ export async function showRunSubjectProcessingResult(session, flags, profile, operation, help, profileName) {
789
+ const workflow = workflowId(flags, help);
790
+ const run = runId(flags, help);
791
+ return showOne("subjectProcessingResult", "entra lifecycle run subject-processing-result show", SUBJECT_PROCESSING_KNOWN, KNOWN_SUBJECT_PROCESSING_FIELDS, DEFAULT_SUBJECT_PROCESSING_FIELDS, DEFAULT_REPORTS_SCOPES, REPORTS_DENIAL_HINTS, session, flags, profile, operation, help, profileName, { "workflow-id": workflow, "run-id": run, "subjectProcessingResult-id": String(flags.id) }, "Graph returned a malformed subject processing result body", true);
792
+ }
793
+ export async function countRunSubjectProcessingResults(session, flags, profile, operation, help, profileName) {
794
+ const workflow = workflowId(flags, help);
795
+ const run = runId(flags, help);
796
+ return countCollection("run subject processing result", RUN_SUBJECT_PROCESSING_LIST.emptyNote, DEFAULT_REPORTS_SCOPES, REPORTS_DENIAL_HINTS, session, flags, profile, operation, help, profileName, { "workflow-id": workflow, "run-id": run });
797
+ }
798
+ export async function listRunTaskProcessingResults(session, flags, profile, operation, help, profileName) {
799
+ const workflow = workflowId(flags, help);
800
+ const run = runId(flags, help);
801
+ return listCollection(RUN_TASK_PROCESSING_LIST, session, flags, profile, operation, help, profileName, { "workflow-id": workflow, "run-id": run }, `Resume losslessly with the same --workflow --run and flags plus --cursor - ${profileHint(profileName)} and supply the returned cursor on stdin`);
802
+ }
803
+ export async function showRunTaskProcessingResult(session, flags, profile, operation, help, profileName) {
804
+ const workflow = workflowId(flags, help);
805
+ const run = runId(flags, help);
806
+ return showOne("taskProcessingResult", "entra lifecycle run task-processing-result show", TASK_PROCESSING_KNOWN, KNOWN_TASK_PROCESSING_FIELDS, DEFAULT_TASK_PROCESSING_SHOW_SELECT, DEFAULT_REPORTS_SCOPES, REPORTS_DENIAL_HINTS, session, flags, profile, operation, help, profileName, { "workflow-id": workflow, "run-id": run, "taskProcessingResult-id": String(flags.id) }, "Graph returned a malformed task processing result body", true);
807
+ }
808
+ export async function countRunTaskProcessingResults(session, flags, profile, operation, help, profileName) {
809
+ const workflow = workflowId(flags, help);
810
+ const run = runId(flags, help);
811
+ return countCollection("run task processing result", RUN_TASK_PROCESSING_LIST.emptyNote, DEFAULT_REPORTS_SCOPES, REPORTS_DENIAL_HINTS, session, flags, profile, operation, help, profileName, { "workflow-id": workflow, "run-id": run });
812
+ }
@@ -1,4 +1,5 @@
1
1
  import { AxiError } from "axi-sdk-js";
2
+ import { listTotals } from "./list-totals.js";
2
3
  // EXT-04 multi-tenant-organization subfamily: the read mapping behind
3
4
  // `mg-axi entra multi-tenant-organization show`,
4
5
  // `mg-axi entra multi-tenant-organization join-request show`,
@@ -276,20 +277,22 @@ export async function listMultiTenantOrganizationTenants(session, flags, profile
276
277
  if (!result.complete) {
277
278
  return {
278
279
  multiTenantOrganizationTenants: rows,
279
- count: { returned: rows.length, complete: false, reason: result.reason },
280
+ ...listTotals(rows.length, result.total, "tenants", false),
281
+ complete: false,
282
+ reason: result.reason,
280
283
  cursor: result.cursor,
281
284
  help: [...truncationHints, resumeHint(profileName), countHint, MTO_NOTE],
282
285
  };
283
286
  }
284
- const count = { returned: rows.length, complete: true };
285
287
  if (!rows.length) {
286
288
  return {
287
289
  multiTenantOrganizationTenants: rows,
288
- count,
290
+ ...listTotals(rows.length, result.total, "tenants", true),
291
+ complete: true,
289
292
  help: ["0 tenants matched; the absence of results is the answer, not an error", MTO_NOTE],
290
293
  };
291
294
  }
292
- return { multiTenantOrganizationTenants: rows, count, help: [...truncationHints, countHint, MTO_NOTE] };
295
+ return { multiTenantOrganizationTenants: rows, ...listTotals(rows.length, result.total, "tenants", true), complete: true, help: [...truncationHints, countHint, MTO_NOTE] };
293
296
  }
294
297
  // The $count route returns a text/plain integer scalar rather than a JSON
295
298
  // collection, so the leaf reads it through session.execute and accepts only
@@ -1,4 +1,5 @@
1
1
  import { AxiError } from "axi-sdk-js";
2
+ import { listTotals } from "./list-totals.js";
2
3
  // EXT-01 on-premises-synchronization subfamily: the read mapping behind
3
4
  // `mg-axi entra on-premises-synchronization list/show`. Operation
4
5
  // construction stays beside its command; the shared session owns URLs,
@@ -201,16 +202,17 @@ export async function listSynchronizations(session, flags, profile, operation, h
201
202
  if (!result.complete) {
202
203
  return {
203
204
  synchronizations,
204
- count: { returned: synchronizations.length, complete: false, reason: result.reason },
205
+ ...listTotals(synchronizations.length, result.total, "synchronizations", false),
206
+ complete: false,
207
+ reason: result.reason,
205
208
  cursor: result.cursor,
206
209
  help: [...truncationHints, resumeHint(profileName), showHint],
207
210
  };
208
211
  }
209
- const count = { returned: synchronizations.length, complete: true };
210
212
  if (!synchronizations.length) {
211
- return { synchronizations, count, help: [EMPTY_NOTE] };
213
+ return { synchronizations, ...listTotals(synchronizations.length, result.total, "synchronizations", true), complete: true, help: [EMPTY_NOTE] };
212
214
  }
213
- return { synchronizations, count, help: [...truncationHints, showHint] };
215
+ return { synchronizations, ...listTotals(synchronizations.length, result.total, "synchronizations", true), complete: true, help: [...truncationHints, showHint] };
214
216
  }
215
217
  export async function showSynchronization(session, flags, profile, operation, help, profileName) {
216
218
  const { select, fields } = selectedFields(flags, DEFAULT_SHOW_SELECT, help);
@@ -1,4 +1,5 @@
1
1
  import { AxiError } from "axi-sdk-js";
2
+ import { listTotals } from "./list-totals.js";
2
3
  // EXT-01 organization subfamily: the read mapping behind
3
4
  // `mg-axi entra organization list/show`, the default-branding read behind
4
5
  // `mg-axi entra organization branding show`, and the branding-localization
@@ -290,20 +291,22 @@ export async function listOrganizations(session, flags, profile, operation, help
290
291
  if (!result.complete) {
291
292
  return {
292
293
  organizations,
293
- count: { returned: organizations.length, complete: false, reason: result.reason },
294
+ ...listTotals(organizations.length, result.total, "organizations", false),
295
+ complete: false,
296
+ reason: result.reason,
294
297
  cursor: result.cursor,
295
298
  help: [...truncationHints, resumeHint(profileName), showHint, filterNote],
296
299
  };
297
300
  }
298
- const count = { returned: organizations.length, complete: true };
299
301
  if (!organizations.length) {
300
302
  return {
301
303
  organizations,
302
- count,
304
+ ...listTotals(organizations.length, result.total, "organizations", true),
305
+ complete: true,
303
306
  help: [filterNote, "0 organizations matched; the absence of results is the answer, not an error"],
304
307
  };
305
308
  }
306
- return { organizations, count, help: [...truncationHints, showHint, filterNote] };
309
+ return { organizations, ...listTotals(organizations.length, result.total, "organizations", true), complete: true, help: [...truncationHints, showHint, filterNote] };
307
310
  }
308
311
  export async function showOrganization(session, flags, profile, operation, help, profileName) {
309
312
  const { select, fields } = selectedFields(flags, KNOWN_ORGANIZATIONS, KNOWN_ORGANIZATION_FIELDS, DEFAULT_ORGANIZATION_SHOW_SELECT, help);
@@ -361,20 +364,22 @@ export async function listBrandingLocalizations(session, flags, profile, operati
361
364
  if (!result.complete) {
362
365
  return {
363
366
  brandingLocalizations: localizations,
364
- count: { returned: localizations.length, complete: false, reason: result.reason },
367
+ ...listTotals(localizations.length, result.total, "branding localizations", false),
368
+ complete: false,
369
+ reason: result.reason,
365
370
  cursor: result.cursor,
366
371
  help: [...truncationHints, resumeHint(profileName), showHint, filterNote],
367
372
  };
368
373
  }
369
- const count = { returned: localizations.length, complete: true };
370
374
  if (!localizations.length) {
371
375
  return {
372
376
  brandingLocalizations: localizations,
373
- count,
377
+ ...listTotals(localizations.length, result.total, "branding localizations", true),
378
+ complete: true,
374
379
  help: [filterNote, "0 branding localizations matched; the absence of results is the answer, not an error"],
375
380
  };
376
381
  }
377
- return { brandingLocalizations: localizations, count, help: [...truncationHints, showHint, filterNote] };
382
+ return { brandingLocalizations: localizations, ...listTotals(localizations.length, result.total, "branding localizations", true), complete: true, help: [...truncationHints, showHint, filterNote] };
378
383
  }
379
384
  export async function showBrandingLocalization(session, flags, profile, operation, help, profileName) {
380
385
  const { select, fields } = selectedFields(flags, KNOWN_BRANDING, KNOWN_BRANDING_FIELDS, DEFAULT_LOCALIZATION_SHOW_SELECT, help, STREAM_HINT);