@knowttl/mg-axi 0.1.1 → 0.1.2
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/README.md +149 -38
- package/dist/api.js +134 -8
- package/dist/bin/mg-axi-hook.js +31 -0
- package/dist/catalogue.js +390 -2
- package/dist/cli.js +116 -8
- package/dist/docs.js +45 -5
- package/dist/doctor.js +2 -2
- package/dist/entra-access-reviews.js +11 -4
- package/dist/entra-apps.js +13 -8
- package/dist/entra-audit-logs.js +8 -4
- package/dist/entra-auth-methods.js +8 -4
- package/dist/entra-certificate-auth.js +12 -8
- package/dist/entra-conditional-access.js +9 -4
- package/dist/entra-contacts.js +19 -12
- package/dist/entra-contracts.js +7 -4
- package/dist/entra-custom-security-attributes.js +19 -12
- package/dist/entra-data-policy-operations.js +7 -4
- package/dist/entra-delegated-admin.js +55 -6
- package/dist/entra-deleted-items.js +6 -4
- package/dist/entra-directory-objects.js +6 -4
- package/dist/entra-directory.js +19 -12
- package/dist/entra-domains.js +13 -8
- package/dist/entra-entitlement-management.js +12 -4
- package/dist/entra-group-pim.js +431 -0
- package/dist/entra-groups.js +13 -8
- package/dist/entra-lifecycle-workflows.js +136 -9
- package/dist/entra-organization.js +13 -8
- package/dist/entra-risk-prevention.js +436 -0
- package/dist/entra-risk.js +213 -5
- package/dist/entra-roles.js +10 -4
- package/dist/entra-subscriptions.js +6 -4
- package/dist/entra-users.js +7 -4
- package/dist/graph-session.js +29 -5
- package/dist/hook.js +84 -0
- package/dist/list-totals.js +52 -0
- package/dist/setup.js +5 -0
- package/docs/coverage.md +79 -13
- package/inventory/operations.json +2 -2
- package/package.json +4 -3
- package/skills/mg-axi/SKILL.md +56 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// EXT-01 certificate-auth subfamily: the read mapping behind
|
|
3
4
|
// `mg-axi entra certificate-auth-pki list/show/count` and
|
|
4
5
|
// `mg-axi entra certificate-authority list/show/count`. Operation
|
|
@@ -242,16 +243,17 @@ export async function listCertificateAuthPkis(session, flags, profile, operation
|
|
|
242
243
|
if (!result.complete) {
|
|
243
244
|
return {
|
|
244
245
|
certificateAuthPkis: pkis,
|
|
245
|
-
|
|
246
|
+
...listTotals(pkis.length, result.total, "PKI configurations", false),
|
|
247
|
+
complete: false,
|
|
248
|
+
reason: result.reason,
|
|
246
249
|
cursor: result.cursor,
|
|
247
250
|
help: [...truncationHints, resumeHint(profileName), showHint, EMPTY_PKI_NOTE],
|
|
248
251
|
};
|
|
249
252
|
}
|
|
250
|
-
const count = { returned: pkis.length, complete: true };
|
|
251
253
|
if (!pkis.length) {
|
|
252
|
-
return { certificateAuthPkis: pkis,
|
|
254
|
+
return { certificateAuthPkis: pkis, ...listTotals(pkis.length, result.total, "PKI configurations", true), complete: true, help: [EMPTY_PKI_NOTE] };
|
|
253
255
|
}
|
|
254
|
-
return { certificateAuthPkis: pkis,
|
|
256
|
+
return { certificateAuthPkis: pkis, ...listTotals(pkis.length, result.total, "PKI configurations", true), complete: true, help: [...truncationHints, showHint, EMPTY_PKI_NOTE] };
|
|
255
257
|
}
|
|
256
258
|
export async function showCertificateAuthPki(session, flags, profile, operation, help, profileName) {
|
|
257
259
|
const { select, fields } = selectedFields(flags, KNOWN_PKIS, KNOWN_PKI_FIELDS, DEFAULT_PKI_SHOW_SELECT, help, "PKI");
|
|
@@ -324,20 +326,22 @@ export async function listCertificateAuthorities(session, flags, profile, operat
|
|
|
324
326
|
if (!result.complete) {
|
|
325
327
|
return {
|
|
326
328
|
certificateAuthorities: authorities,
|
|
327
|
-
|
|
329
|
+
...listTotals(authorities.length, result.total, "certificate authorities", false),
|
|
330
|
+
complete: false,
|
|
331
|
+
reason: result.reason,
|
|
328
332
|
cursor: result.cursor,
|
|
329
333
|
help: [...truncationHints, resumeHint(profileName), showHint, CERT_BLOB_NOTE],
|
|
330
334
|
};
|
|
331
335
|
}
|
|
332
|
-
const count = { returned: authorities.length, complete: true };
|
|
333
336
|
if (!authorities.length) {
|
|
334
337
|
return {
|
|
335
338
|
certificateAuthorities: authorities,
|
|
336
|
-
|
|
339
|
+
...listTotals(authorities.length, result.total, "certificate authorities", true),
|
|
340
|
+
complete: true,
|
|
337
341
|
help: ["0 certificate authorities matched; the absence of results is the answer, not an error", CERT_BLOB_NOTE],
|
|
338
342
|
};
|
|
339
343
|
}
|
|
340
|
-
return { certificateAuthorities: authorities,
|
|
344
|
+
return { certificateAuthorities: authorities, ...listTotals(authorities.length, result.total, "certificate authorities", true), complete: true, help: [...truncationHints, showHint, CERT_BLOB_NOTE] };
|
|
341
345
|
}
|
|
342
346
|
export async function showCertificateAuthority(session, flags, profile, operation, help, profileName) {
|
|
343
347
|
const { select, fields } = selectedFields(flags, KNOWN_CAS, KNOWN_CA_FIELDS, DEFAULT_CA_SHOW_SELECT, help, "certificate-authority");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// READ-03: the Conditional Access read mapping behind
|
|
3
4
|
// `mg-axi entra conditional-access policy list/show` and
|
|
4
5
|
// `mg-axi entra conditional-access named-location list/show` as separate
|
|
@@ -183,6 +184,7 @@ const POLICY_LIST = {
|
|
|
183
184
|
command: "entra conditional-access policy list",
|
|
184
185
|
key: "policies",
|
|
185
186
|
noun: "policy",
|
|
187
|
+
plural: "policies",
|
|
186
188
|
known: POLICY_KNOWN,
|
|
187
189
|
knownList: KNOWN_POLICY_FIELDS,
|
|
188
190
|
defaultSelect: DEFAULT_POLICY_LIST_SELECT,
|
|
@@ -195,6 +197,7 @@ const LOCATION_LIST = {
|
|
|
195
197
|
command: "entra conditional-access named-location list",
|
|
196
198
|
key: "namedLocations",
|
|
197
199
|
noun: "named-location",
|
|
200
|
+
plural: "named locations",
|
|
198
201
|
known: LOCATION_KNOWN,
|
|
199
202
|
knownList: KNOWN_LOCATION_FIELDS,
|
|
200
203
|
defaultSelect: DEFAULT_LOCATION_LIST_SELECT,
|
|
@@ -242,23 +245,25 @@ async function listCollection(shape, session, flags, profile, operation, help, p
|
|
|
242
245
|
if (!result.complete) {
|
|
243
246
|
return {
|
|
244
247
|
[shape.key]: rows,
|
|
245
|
-
|
|
248
|
+
...listTotals(rows.length, result.total, shape.plural, false),
|
|
249
|
+
complete: false,
|
|
250
|
+
reason: result.reason,
|
|
246
251
|
cursor: result.cursor,
|
|
247
252
|
help: [...truncationHints, `Resume losslessly with the same flags plus --cursor - ${profileHint(profileName)} and supply the returned cursor on stdin`, showHint],
|
|
248
253
|
};
|
|
249
254
|
}
|
|
250
|
-
const count = { returned: rows.length, complete: true };
|
|
251
255
|
if (!rows.length) {
|
|
252
256
|
return {
|
|
253
257
|
[shape.key]: rows,
|
|
254
|
-
|
|
258
|
+
...listTotals(rows.length, result.total, shape.plural, true),
|
|
259
|
+
complete: true,
|
|
255
260
|
help: [
|
|
256
261
|
`mg-axi ${shape.command} --filter <odata-filter> ${profileHint(profileName)}`,
|
|
257
262
|
shape.emptyHint,
|
|
258
263
|
],
|
|
259
264
|
};
|
|
260
265
|
}
|
|
261
|
-
return { [shape.key]: rows,
|
|
266
|
+
return { [shape.key]: rows, ...listTotals(rows.length, result.total, shape.plural, true), complete: true, help: [...truncationHints, showHint] };
|
|
262
267
|
}
|
|
263
268
|
const POLICY_SHOW = {
|
|
264
269
|
command: "entra conditional-access policy show",
|
package/dist/entra-contacts.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// EXT-01 contacts subfamily plus EXT-01m/EXT-01n navigation: the read mapping
|
|
3
4
|
// behind `mg-axi entra contact list/show/count`, the manager/directReports
|
|
4
5
|
// navigation reads (`show-manager`, `list/show/count-direct-reports`) and the
|
|
@@ -290,23 +291,25 @@ export async function listContacts(session, flags, profile, operation, help, pro
|
|
|
290
291
|
if (!result.complete) {
|
|
291
292
|
return {
|
|
292
293
|
contacts,
|
|
293
|
-
|
|
294
|
+
...listTotals(contacts.length, result.total, "contacts", false),
|
|
295
|
+
complete: false,
|
|
296
|
+
reason: result.reason,
|
|
294
297
|
cursor: result.cursor,
|
|
295
298
|
help: [...truncationHints, resumeHint(profileName), showHint],
|
|
296
299
|
};
|
|
297
300
|
}
|
|
298
|
-
const count = { returned: contacts.length, complete: true };
|
|
299
301
|
if (!contacts.length) {
|
|
300
302
|
return {
|
|
301
303
|
contacts,
|
|
302
|
-
|
|
304
|
+
...listTotals(contacts.length, result.total, "contacts", true),
|
|
305
|
+
complete: true,
|
|
303
306
|
help: [
|
|
304
307
|
`mg-axi entra contact list --filter <odata-filter> ${profileHint(profileName)}`,
|
|
305
308
|
"0 contacts matched; the absence of results is the answer, not an error",
|
|
306
309
|
],
|
|
307
310
|
};
|
|
308
311
|
}
|
|
309
|
-
return { contacts,
|
|
312
|
+
return { contacts, ...listTotals(contacts.length, result.total, "contacts", true), complete: true, help: [...truncationHints, showHint] };
|
|
310
313
|
}
|
|
311
314
|
export async function showContact(session, flags, profile, operation, help, profileName) {
|
|
312
315
|
checkReadOperation(operation, help);
|
|
@@ -512,20 +515,22 @@ export async function listContactDirectReports(session, flags, profile, operatio
|
|
|
512
515
|
if (!result.complete) {
|
|
513
516
|
return {
|
|
514
517
|
directReports,
|
|
515
|
-
|
|
518
|
+
...listTotals(directReports.length, result.total, "direct reports", false),
|
|
519
|
+
complete: false,
|
|
520
|
+
reason: result.reason,
|
|
516
521
|
cursor: result.cursor,
|
|
517
522
|
help: [...truncationHints, ...limitedHints, resumeHint(profileName), showHint],
|
|
518
523
|
};
|
|
519
524
|
}
|
|
520
|
-
const count = { returned: directReports.length, complete: true };
|
|
521
525
|
if (!directReports.length) {
|
|
522
526
|
return {
|
|
523
527
|
directReports,
|
|
524
|
-
|
|
528
|
+
...listTotals(directReports.length, result.total, "direct reports", true),
|
|
529
|
+
complete: true,
|
|
525
530
|
help: [...limitedHints, "0 direct reports matched; the absence of results is the answer, not an error", showHint],
|
|
526
531
|
};
|
|
527
532
|
}
|
|
528
|
-
return { directReports,
|
|
533
|
+
return { directReports, ...listTotals(directReports.length, result.total, "direct reports", true), complete: true, help: [...truncationHints, ...limitedHints, showHint] };
|
|
529
534
|
}
|
|
530
535
|
export async function showContactDirectReport(session, flags, profile, operation, help, profileName) {
|
|
531
536
|
checkReadOperation(operation, help);
|
|
@@ -767,20 +772,22 @@ export async function listContactMemberOf(session, flags, profile, operation, he
|
|
|
767
772
|
if (!result.complete) {
|
|
768
773
|
return {
|
|
769
774
|
memberOf,
|
|
770
|
-
|
|
775
|
+
...listTotals(memberOf.length, result.total, "memberships", false),
|
|
776
|
+
complete: false,
|
|
777
|
+
reason: result.reason,
|
|
771
778
|
cursor: result.cursor,
|
|
772
779
|
help: [...truncationHints, ...limitedHints, resumeHint(profileName), scopeHint, showHint],
|
|
773
780
|
};
|
|
774
781
|
}
|
|
775
|
-
const count = { returned: memberOf.length, complete: true };
|
|
776
782
|
if (!memberOf.length) {
|
|
777
783
|
return {
|
|
778
784
|
memberOf,
|
|
779
|
-
|
|
785
|
+
...listTotals(memberOf.length, result.total, "memberships", true),
|
|
786
|
+
complete: true,
|
|
780
787
|
help: [...limitedHints, `0 ${noun} matched; the absence of results is the answer, not an error`, scopeHint, showHint],
|
|
781
788
|
};
|
|
782
789
|
}
|
|
783
|
-
return { memberOf,
|
|
790
|
+
return { memberOf, ...listTotals(memberOf.length, result.total, "memberships", true), complete: true, help: [...truncationHints, ...limitedHints, scopeHint, showHint] };
|
|
784
791
|
}
|
|
785
792
|
export async function showContactMemberOf(session, flags, profile, operation, help, profileName) {
|
|
786
793
|
checkReadOperation(operation, help);
|
package/dist/entra-contracts.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// EXT-04 partner contracts subfamily: the read mapping behind `mg-axi entra
|
|
3
4
|
// contract list/show/count`. Operation construction stays beside its command;
|
|
4
5
|
// the shared session owns URLs, credentials, paging, retries and error
|
|
@@ -198,20 +199,22 @@ export async function listContracts(session, flags, profile, operation, help, pr
|
|
|
198
199
|
if (!result.complete) {
|
|
199
200
|
return {
|
|
200
201
|
contracts,
|
|
201
|
-
|
|
202
|
+
...listTotals(contracts.length, result.total, "contracts", false),
|
|
203
|
+
complete: false,
|
|
204
|
+
reason: result.reason,
|
|
202
205
|
cursor: result.cursor,
|
|
203
206
|
help: [...truncationHints, resumeHint(profileName), showHint, PARTNER_NOTE],
|
|
204
207
|
};
|
|
205
208
|
}
|
|
206
|
-
const count = { returned: contracts.length, complete: true };
|
|
207
209
|
if (!contracts.length) {
|
|
208
210
|
return {
|
|
209
211
|
contracts,
|
|
210
|
-
|
|
212
|
+
...listTotals(contracts.length, result.total, "contracts", true),
|
|
213
|
+
complete: true,
|
|
211
214
|
help: ["0 contracts matched; the absence of results is the answer, not an error", PARTNER_NOTE],
|
|
212
215
|
};
|
|
213
216
|
}
|
|
214
|
-
return { contracts,
|
|
217
|
+
return { contracts, ...listTotals(contracts.length, result.total, "contracts", true), complete: true, help: [...truncationHints, showHint, PARTNER_NOTE] };
|
|
215
218
|
}
|
|
216
219
|
export async function showContract(session, flags, profile, operation, help, profileName) {
|
|
217
220
|
const { select, fields } = selectedFields(flags, KNOWN_CONTRACTS, KNOWN_CONTRACT_FIELDS, DEFAULT_CONTRACT_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 custom-security-attributes subfamily: the read mapping behind
|
|
3
4
|
// `mg-axi entra attribute-set list/show/count`,
|
|
4
5
|
// `mg-axi entra custom-security-attribute-definition list/show/count` and
|
|
@@ -265,20 +266,22 @@ export async function listAttributeSets(session, flags, profile, operation, help
|
|
|
265
266
|
if (!result.complete) {
|
|
266
267
|
return {
|
|
267
268
|
attributeSets: sets,
|
|
268
|
-
|
|
269
|
+
...listTotals(sets.length, result.total, "attribute sets", false),
|
|
270
|
+
complete: false,
|
|
271
|
+
reason: result.reason,
|
|
269
272
|
cursor: result.cursor,
|
|
270
273
|
help: [...truncationHints, resumeHint(profileName), showHint, filterNote],
|
|
271
274
|
};
|
|
272
275
|
}
|
|
273
|
-
const count = { returned: sets.length, complete: true };
|
|
274
276
|
if (!sets.length) {
|
|
275
277
|
return {
|
|
276
278
|
attributeSets: sets,
|
|
277
|
-
|
|
279
|
+
...listTotals(sets.length, result.total, "attribute sets", true),
|
|
280
|
+
complete: true,
|
|
278
281
|
help: [filterNote, "0 attribute sets matched; the absence of results is the answer, not an error"],
|
|
279
282
|
};
|
|
280
283
|
}
|
|
281
|
-
return { attributeSets: sets,
|
|
284
|
+
return { attributeSets: sets, ...listTotals(sets.length, result.total, "attribute sets", true), complete: true, help: [...truncationHints, showHint, filterNote] };
|
|
282
285
|
}
|
|
283
286
|
export async function showAttributeSet(session, flags, profile, operation, help, profileName) {
|
|
284
287
|
const { select, fields } = selectedFields(flags, KNOWN_ATTRIBUTE_SETS, KNOWN_ATTRIBUTE_SET_FIELDS, DEFAULT_ATTRIBUTE_SET_SHOW_SELECT, help, "attribute-set");
|
|
@@ -331,20 +334,22 @@ export async function listCustomSecurityAttributeDefinitions(session, flags, pro
|
|
|
331
334
|
if (!result.complete) {
|
|
332
335
|
return {
|
|
333
336
|
customSecurityAttributeDefinitions: definitions,
|
|
334
|
-
|
|
337
|
+
...listTotals(definitions.length, result.total, "custom security attribute definitions", false),
|
|
338
|
+
complete: false,
|
|
339
|
+
reason: result.reason,
|
|
335
340
|
cursor: result.cursor,
|
|
336
341
|
help: [...truncationHints, resumeHint(profileName), showHint],
|
|
337
342
|
};
|
|
338
343
|
}
|
|
339
|
-
const count = { returned: definitions.length, complete: true };
|
|
340
344
|
if (!definitions.length) {
|
|
341
345
|
return {
|
|
342
346
|
customSecurityAttributeDefinitions: definitions,
|
|
343
|
-
|
|
347
|
+
...listTotals(definitions.length, result.total, "custom security attribute definitions", true),
|
|
348
|
+
complete: true,
|
|
344
349
|
help: ["0 custom security attribute definitions matched; the absence of results is the answer, not an error"],
|
|
345
350
|
};
|
|
346
351
|
}
|
|
347
|
-
return { customSecurityAttributeDefinitions: definitions,
|
|
352
|
+
return { customSecurityAttributeDefinitions: definitions, ...listTotals(definitions.length, result.total, "custom security attribute definitions", true), complete: true, help: [...truncationHints, showHint] };
|
|
348
353
|
}
|
|
349
354
|
export async function showCustomSecurityAttributeDefinition(session, flags, profile, operation, help, profileName) {
|
|
350
355
|
const { select, fields } = selectedFields(flags, KNOWN_DEFINITIONS, KNOWN_CUSTOM_SECURITY_DEFINITION_FIELDS, DEFAULT_DEFINITION_SHOW_SELECT, help, "definition");
|
|
@@ -407,20 +412,22 @@ export async function listAllowedValues(session, flags, profile, operation, help
|
|
|
407
412
|
if (!result.complete) {
|
|
408
413
|
return {
|
|
409
414
|
allowedValues: values,
|
|
410
|
-
|
|
415
|
+
...listTotals(values.length, result.total, "allowed values", false),
|
|
416
|
+
complete: false,
|
|
417
|
+
reason: result.reason,
|
|
411
418
|
cursor: result.cursor,
|
|
412
419
|
help: [...truncationHints, resumeHint(profileName), showHint, filterNote],
|
|
413
420
|
};
|
|
414
421
|
}
|
|
415
|
-
const count = { returned: values.length, complete: true };
|
|
416
422
|
if (!values.length) {
|
|
417
423
|
return {
|
|
418
424
|
allowedValues: values,
|
|
419
|
-
|
|
425
|
+
...listTotals(values.length, result.total, "allowed values", true),
|
|
426
|
+
complete: true,
|
|
420
427
|
help: [filterNote, "0 allowed values matched; the definition may allow free-form values instead of predefined ones"],
|
|
421
428
|
};
|
|
422
429
|
}
|
|
423
|
-
return { allowedValues: values,
|
|
430
|
+
return { allowedValues: values, ...listTotals(values.length, result.total, "allowed values", true), complete: true, help: [...truncationHints, showHint, filterNote] };
|
|
424
431
|
}
|
|
425
432
|
export async function showAllowedValue(session, flags, profile, operation, help, profileName) {
|
|
426
433
|
const { select, fields } = selectedFields(flags, KNOWN_ALLOWED_VALUES, KNOWN_ALLOWED_VALUE_FIELDS, DEFAULT_ALLOWED_VALUE_SHOW_SELECT, help, "allowed-value");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
import { REDACTED } from "./graph-session.js";
|
|
3
4
|
// EXT-03 data-policy-operations subfamily: the read mapping behind
|
|
4
5
|
// `mg-axi entra data-policy-operation list/show/count`. Operation
|
|
@@ -224,20 +225,22 @@ export async function listDataPolicyOperations(session, flags, profile, operatio
|
|
|
224
225
|
if (!result.complete) {
|
|
225
226
|
return {
|
|
226
227
|
dataPolicyOperations: operations,
|
|
227
|
-
|
|
228
|
+
...listTotals(operations.length, result.total, "data-policy operations", false),
|
|
229
|
+
complete: false,
|
|
230
|
+
reason: result.reason,
|
|
228
231
|
cursor: result.cursor,
|
|
229
232
|
help: [...truncationHints, resumeHint(profileName), showHint, WORKFORCE_NOTE],
|
|
230
233
|
};
|
|
231
234
|
}
|
|
232
|
-
const count = { returned: operations.length, complete: true };
|
|
233
235
|
if (!operations.length) {
|
|
234
236
|
return {
|
|
235
237
|
dataPolicyOperations: operations,
|
|
236
|
-
|
|
238
|
+
...listTotals(operations.length, result.total, "data-policy operations", true),
|
|
239
|
+
complete: true,
|
|
237
240
|
help: ["0 data-policy operations matched; the absence of results is the answer, not an error", WORKFORCE_NOTE],
|
|
238
241
|
};
|
|
239
242
|
}
|
|
240
|
-
return { dataPolicyOperations: operations,
|
|
243
|
+
return { dataPolicyOperations: operations, ...listTotals(operations.length, result.total, "data-policy operations", true), complete: true, help: [...truncationHints, showHint, WORKFORCE_NOTE] };
|
|
241
244
|
}
|
|
242
245
|
export async function showDataPolicyOperation(session, flags, profile, operation, help, profileName) {
|
|
243
246
|
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-04 delegated-admin subfamily: the read mapping behind
|
|
3
4
|
// `mg-axi entra delegated-admin-customer list/show`,
|
|
4
5
|
// `mg-axi entra delegated-admin-relationship list/show` and the navigation
|
|
@@ -35,8 +36,8 @@ import { AxiError } from "axi-sdk-js";
|
|
|
35
36
|
// --filter passes through as plain $filter with no $count or ConsistencyLevel
|
|
36
37
|
// contract. serviceManagementDetails documents no query parameters, so both
|
|
37
38
|
// service-management-detail reads run queryless and project locally. The
|
|
38
|
-
// $count scalars
|
|
39
|
-
// for later EXT-04
|
|
39
|
+
// six $count scalars ship in this module; the tenantRelationship container
|
|
40
|
+
// root stays scheduled for a later EXT-04 subfamily, as do the multi-tenant-organization reads
|
|
40
41
|
// (shipped separately) and the tenant-lookup functions (shipped as
|
|
41
42
|
// tenant-information show under mg-ext-04e). Beta stays out. No delegated-admin mutation exists in this slice:
|
|
42
43
|
// relationship creation, approval and termination are writes.
|
|
@@ -389,20 +390,22 @@ async function listResource(session, flags, profile, operation, help, profileNam
|
|
|
389
390
|
if (!result.complete) {
|
|
390
391
|
return {
|
|
391
392
|
[collectionKey]: rows,
|
|
392
|
-
|
|
393
|
+
...listTotals(rows.length, result.total, `${resource.noun}s`, false),
|
|
394
|
+
complete: false,
|
|
395
|
+
reason: result.reason,
|
|
393
396
|
cursor: result.cursor,
|
|
394
397
|
help: [...truncationHints, resumeHint(profileName), showHint, partnerNote(resource)],
|
|
395
398
|
};
|
|
396
399
|
}
|
|
397
|
-
const count = { returned: rows.length, complete: true };
|
|
398
400
|
if (!rows.length) {
|
|
399
401
|
return {
|
|
400
402
|
[collectionKey]: rows,
|
|
401
|
-
|
|
403
|
+
...listTotals(rows.length, result.total, `${resource.noun}s`, true),
|
|
404
|
+
complete: true,
|
|
402
405
|
help: [`0 ${resource.noun}s matched; the absence of results is the answer, not an error`, partnerNote(resource)],
|
|
403
406
|
};
|
|
404
407
|
}
|
|
405
|
-
return { [collectionKey]: rows,
|
|
408
|
+
return { [collectionKey]: rows, ...listTotals(rows.length, result.total, `${resource.noun}s`, true), complete: true, help: [...truncationHints, showHint, partnerNote(resource)] };
|
|
406
409
|
}
|
|
407
410
|
async function showResource(session, flags, profile, operation, help, profileName, resource, rowKey, showCommand) {
|
|
408
411
|
const queryless = resource.queryless === true;
|
|
@@ -466,3 +469,49 @@ export async function listDelegatedAdminServiceManagementDetails(session, flags,
|
|
|
466
469
|
export async function showDelegatedAdminServiceManagementDetail(session, flags, profile, operation, help, profileName) {
|
|
467
470
|
return showResource(session, flags, profile, operation, help, profileName, SERVICE_MANAGEMENT_DETAIL, "delegatedAdminServiceManagementDetail", "entra delegated-admin-customer show-service-management-detail");
|
|
468
471
|
}
|
|
472
|
+
// The $count routes return a text/plain integer scalar rather than a JSON
|
|
473
|
+
// collection, so each leaf reads it through session.execute and accepts only
|
|
474
|
+
// a non-negative integer. There is no --filter/--select/--limit contract on
|
|
475
|
+
// the counts: the catalogue declares no such flags and strict input
|
|
476
|
+
// validation refuses them before credentials. All six share the parent
|
|
477
|
+
// list/show read scope DelegatedAdminRelationship.Read.All, so no new
|
|
478
|
+
// consent is needed.
|
|
479
|
+
function countParentId(flags, label, help) {
|
|
480
|
+
const id = String(flags.id);
|
|
481
|
+
if (!id.trim())
|
|
482
|
+
throw new AxiError(`--id needs the delegated-admin ${label} identifier`, "VALIDATION_ERROR", [help]);
|
|
483
|
+
return id;
|
|
484
|
+
}
|
|
485
|
+
async function countScalar(session, flags, profile, operation, help, profileName, params, rowKey, noun) {
|
|
486
|
+
void profileName;
|
|
487
|
+
const scopes = scopesFor(flags, DEFAULT_DELEGATED_ADMIN_SCOPES, profile, help);
|
|
488
|
+
const raw = await withGuidance(DELEGATED_ADMIN_DENIAL_HINTS, () => session.execute({ profile, operation, params, scopes }));
|
|
489
|
+
if (typeof raw !== "number" || !Number.isInteger(raw) || raw < 0) {
|
|
490
|
+
throw new AxiError(`Graph returned a malformed delegated-admin ${noun} count body`, "GRAPH_ERROR", [
|
|
491
|
+
"Delegated-admin counts carry one non-negative integer scalar; treat anything else as unknown, not empty",
|
|
492
|
+
]);
|
|
493
|
+
}
|
|
494
|
+
return { [rowKey]: raw };
|
|
495
|
+
}
|
|
496
|
+
export async function countDelegatedAdminCustomers(session, flags, profile, operation, help, profileName) {
|
|
497
|
+
return countScalar(session, flags, profile, operation, help, profileName, {}, "delegatedAdminCustomerCount", "customer");
|
|
498
|
+
}
|
|
499
|
+
export async function countDelegatedAdminServiceManagementDetails(session, flags, profile, operation, help, profileName) {
|
|
500
|
+
const customer = countParentId(flags, "customer", help);
|
|
501
|
+
return countScalar(session, flags, profile, operation, help, profileName, { "delegatedAdminCustomer-id": customer }, "delegatedAdminServiceManagementDetailCount", "service-management detail");
|
|
502
|
+
}
|
|
503
|
+
export async function countDelegatedAdminRelationships(session, flags, profile, operation, help, profileName) {
|
|
504
|
+
return countScalar(session, flags, profile, operation, help, profileName, {}, "delegatedAdminRelationshipCount", "relationship");
|
|
505
|
+
}
|
|
506
|
+
export async function countDelegatedAdminAccessAssignments(session, flags, profile, operation, help, profileName) {
|
|
507
|
+
const relationship = countParentId(flags, "relationship", help);
|
|
508
|
+
return countScalar(session, flags, profile, operation, help, profileName, { "delegatedAdminRelationship-id": relationship }, "delegatedAdminAccessAssignmentCount", "access assignment");
|
|
509
|
+
}
|
|
510
|
+
export async function countDelegatedAdminOperations(session, flags, profile, operation, help, profileName) {
|
|
511
|
+
const relationship = countParentId(flags, "relationship", help);
|
|
512
|
+
return countScalar(session, flags, profile, operation, help, profileName, { "delegatedAdminRelationship-id": relationship }, "delegatedAdminRelationshipOperationCount", "relationship operation");
|
|
513
|
+
}
|
|
514
|
+
export async function countDelegatedAdminRequests(session, flags, profile, operation, help, profileName) {
|
|
515
|
+
const relationship = countParentId(flags, "relationship", help);
|
|
516
|
+
return countScalar(session, flags, profile, operation, help, profileName, { "delegatedAdminRelationship-id": relationship }, "delegatedAdminRelationshipRequestCount", "relationship request");
|
|
517
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// EXT-01 deleted-items subfamily: the read mapping behind
|
|
3
4
|
// `mg-axi entra deleted-user|deleted-group|deleted-application|
|
|
4
5
|
// deleted-service-principal|deleted-administrative-unit list/count` and
|
|
@@ -402,16 +403,17 @@ export async function listDeletedItems(session, flags, profile, operation, help,
|
|
|
402
403
|
if (!result.complete) {
|
|
403
404
|
return {
|
|
404
405
|
deletedItems: rows,
|
|
405
|
-
|
|
406
|
+
...listTotals(rows.length, result.total, "deleted items", false),
|
|
407
|
+
complete: false,
|
|
408
|
+
reason: result.reason,
|
|
406
409
|
cursor: result.cursor,
|
|
407
410
|
help: [...truncationHints, resumeHint(profileName), showHint, ...groupNote, ...appNote],
|
|
408
411
|
};
|
|
409
412
|
}
|
|
410
|
-
const count = { returned: rows.length, complete: true };
|
|
411
413
|
if (!rows.length) {
|
|
412
|
-
return { deletedItems: rows,
|
|
414
|
+
return { deletedItems: rows, ...listTotals(rows.length, result.total, "deleted items", true), complete: true, help: [emptyNote, ...groupNote, ...appNote] };
|
|
413
415
|
}
|
|
414
|
-
return { deletedItems: rows,
|
|
416
|
+
return { deletedItems: rows, ...listTotals(rows.length, result.total, "deleted items", true), complete: true, help: [...truncationHints, showHint, ...groupNote, ...appNote] };
|
|
415
417
|
}
|
|
416
418
|
export async function showDeletedItem(session, flags, profile, operation, help, profileName) {
|
|
417
419
|
checkShowOperation(operation, help);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// EXT-01 directory-objects subfamily: the read mapping behind
|
|
3
4
|
// `mg-axi entra directory-object list/show/count`. Operation construction
|
|
4
5
|
// stays beside its command; the shared session owns URLs, credentials,
|
|
@@ -225,16 +226,17 @@ export async function listDirectoryObjects(session, flags, profile, operation, h
|
|
|
225
226
|
if (!result.complete) {
|
|
226
227
|
return {
|
|
227
228
|
directoryObjects,
|
|
228
|
-
|
|
229
|
+
...listTotals(directoryObjects.length, result.total, "directory objects", false),
|
|
230
|
+
complete: false,
|
|
231
|
+
reason: result.reason,
|
|
229
232
|
cursor: result.cursor,
|
|
230
233
|
help: [...truncationHints, resumeHint(profileName), showHint],
|
|
231
234
|
};
|
|
232
235
|
}
|
|
233
|
-
const count = { returned: directoryObjects.length, complete: true };
|
|
234
236
|
if (!directoryObjects.length) {
|
|
235
|
-
return { directoryObjects,
|
|
237
|
+
return { directoryObjects, ...listTotals(directoryObjects.length, result.total, "directory objects", true), complete: true, help: [EMPTY_NOTE] };
|
|
236
238
|
}
|
|
237
|
-
return { directoryObjects,
|
|
239
|
+
return { directoryObjects, ...listTotals(directoryObjects.length, result.total, "directory objects", true), complete: true, help: [...truncationHints, showHint] };
|
|
238
240
|
}
|
|
239
241
|
export async function showDirectoryObject(session, flags, profile, operation, help, profileName) {
|
|
240
242
|
checkReadOperation(operation, help);
|
package/dist/entra-directory.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { listTotals } from "./list-totals.js";
|
|
2
3
|
// READ-10: the directory-device and administrative-unit read mapping behind
|
|
3
4
|
// `mg-axi entra device list/show`, `mg-axi entra administrative-unit
|
|
4
5
|
// list/show` and `mg-axi entra administrative-unit member list`. Operation
|
|
@@ -260,16 +261,18 @@ export async function listDevices(session, flags, profile, operation, help, prof
|
|
|
260
261
|
if (!result.complete) {
|
|
261
262
|
return {
|
|
262
263
|
devices,
|
|
263
|
-
|
|
264
|
+
...listTotals(devices.length, result.total, "devices", false),
|
|
265
|
+
complete: false,
|
|
266
|
+
reason: result.reason,
|
|
264
267
|
cursor: result.cursor,
|
|
265
268
|
help: [...truncationHints, resumeHint(profileName), showHint, scopeHint],
|
|
266
269
|
};
|
|
267
270
|
}
|
|
268
|
-
const count = { returned: devices.length, complete: true };
|
|
269
271
|
if (!devices.length) {
|
|
270
272
|
return {
|
|
271
273
|
devices,
|
|
272
|
-
|
|
274
|
+
...listTotals(devices.length, result.total, "devices", true),
|
|
275
|
+
complete: true,
|
|
273
276
|
help: [
|
|
274
277
|
`mg-axi entra device list --filter <odata-filter> ${profileHint(profileName)}`,
|
|
275
278
|
"0 devices matched; the absence of results is the answer, not an error",
|
|
@@ -277,7 +280,7 @@ export async function listDevices(session, flags, profile, operation, help, prof
|
|
|
277
280
|
],
|
|
278
281
|
};
|
|
279
282
|
}
|
|
280
|
-
return { devices,
|
|
283
|
+
return { devices, ...listTotals(devices.length, result.total, "devices", true), complete: true, help: [...truncationHints, showHint, scopeHint] };
|
|
281
284
|
}
|
|
282
285
|
export async function showDevice(session, flags, profile, operation, help, profileName) {
|
|
283
286
|
const { select, fields } = selectedFields(flags, KNOWN_DEVICES, KNOWN_DEVICE_FIELDS, DEFAULT_DEVICE_SHOW_SELECT, help);
|
|
@@ -318,23 +321,25 @@ export async function listAdministrativeUnits(session, flags, profile, operation
|
|
|
318
321
|
if (!result.complete) {
|
|
319
322
|
return {
|
|
320
323
|
administrativeUnits: units,
|
|
321
|
-
|
|
324
|
+
...listTotals(units.length, result.total, "administrative units", false),
|
|
325
|
+
complete: false,
|
|
326
|
+
reason: result.reason,
|
|
322
327
|
cursor: result.cursor,
|
|
323
328
|
help: [...truncationHints, resumeHint(profileName), showHint],
|
|
324
329
|
};
|
|
325
330
|
}
|
|
326
|
-
const count = { returned: units.length, complete: true };
|
|
327
331
|
if (!units.length) {
|
|
328
332
|
return {
|
|
329
333
|
administrativeUnits: units,
|
|
330
|
-
|
|
334
|
+
...listTotals(units.length, result.total, "administrative units", true),
|
|
335
|
+
complete: true,
|
|
331
336
|
help: [
|
|
332
337
|
`mg-axi entra administrative-unit list --filter <odata-filter> ${profileHint(profileName)}`,
|
|
333
338
|
"0 administrative units matched; the absence of results is the answer, not an error",
|
|
334
339
|
],
|
|
335
340
|
};
|
|
336
341
|
}
|
|
337
|
-
return { administrativeUnits: units,
|
|
342
|
+
return { administrativeUnits: units, ...listTotals(units.length, result.total, "administrative units", true), complete: true, help: [...truncationHints, showHint] };
|
|
338
343
|
}
|
|
339
344
|
export async function showAdministrativeUnit(session, flags, profile, operation, help, profileName) {
|
|
340
345
|
const { select, fields } = selectedFields(flags, KNOWN_AUS, KNOWN_AU_FIELDS, DEFAULT_AU_SHOW_SELECT, help);
|
|
@@ -390,16 +395,18 @@ export async function listAdministrativeUnitMembers(session, flags, profile, ope
|
|
|
390
395
|
if (!result.complete) {
|
|
391
396
|
return {
|
|
392
397
|
members: rows,
|
|
393
|
-
|
|
398
|
+
...listTotals(rows.length, result.total, "members", false),
|
|
399
|
+
complete: false,
|
|
400
|
+
reason: result.reason,
|
|
394
401
|
cursor: result.cursor,
|
|
395
402
|
help: [...truncationHints, ...limitedHints, hiddenHint, resumeHint(profileName)],
|
|
396
403
|
};
|
|
397
404
|
}
|
|
398
|
-
const count = { returned: rows.length, complete: true };
|
|
399
405
|
if (!rows.length) {
|
|
400
406
|
return {
|
|
401
407
|
members: rows,
|
|
402
|
-
|
|
408
|
+
...listTotals(rows.length, result.total, "members", true),
|
|
409
|
+
complete: true,
|
|
403
410
|
help: [
|
|
404
411
|
...limitedHints,
|
|
405
412
|
hiddenHint,
|
|
@@ -407,5 +414,5 @@ export async function listAdministrativeUnitMembers(session, flags, profile, ope
|
|
|
407
414
|
],
|
|
408
415
|
};
|
|
409
416
|
}
|
|
410
|
-
return { members: rows,
|
|
417
|
+
return { members: rows, ...listTotals(rows.length, result.total, "members", true), complete: true, help: [...truncationHints, ...limitedHints, hiddenHint] };
|
|
411
418
|
}
|