@pnp/cli-microsoft365 7.2.0 → 7.3.0-beta.01256d2

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 (69) hide show
  1. package/allCommands.json +1 -1
  2. package/allCommandsFull.json +1 -1
  3. package/dist/appInsights.js +2 -1
  4. package/dist/cli/Cli.js +14 -13
  5. package/dist/index.js +1 -9
  6. package/dist/m365/aad/commands/group/group-list.js +69 -1
  7. package/dist/m365/external/commands/connection/connection-doctor.js +424 -0
  8. package/dist/m365/external/commands/item/item-add.js +144 -0
  9. package/dist/m365/external/commands.js +3 -1
  10. package/dist/m365/teams/commands/meeting/meeting-add.js +151 -0
  11. package/dist/m365/teams/commands/user/user-app-remove.js +33 -2
  12. package/dist/m365/teams/commands.js +2 -1
  13. package/dist/telemetry.js +0 -8
  14. package/dist/utils/validation.js +5 -2
  15. package/docs/docs/cmd/aad/group/group-list.mdx +11 -0
  16. package/docs/docs/cmd/external/connection/connection-doctor.mdx +179 -0
  17. package/docs/docs/cmd/external/item/item-add.mdx +145 -0
  18. package/docs/docs/cmd/onedrive/report/report-activityfilecounts.mdx +0 -3
  19. package/docs/docs/cmd/onedrive/report/report-activityusercounts.mdx +0 -3
  20. package/docs/docs/cmd/onedrive/report/report-activityuserdetail.mdx +0 -3
  21. package/docs/docs/cmd/onedrive/report/report-usageaccountcounts.mdx +0 -3
  22. package/docs/docs/cmd/onedrive/report/report-usageaccountdetail.mdx +0 -3
  23. package/docs/docs/cmd/onedrive/report/report-usagefilecounts.mdx +0 -3
  24. package/docs/docs/cmd/onedrive/report/report-usagestorage.mdx +0 -3
  25. package/docs/docs/cmd/outlook/report/report-mailactivitycounts.mdx +0 -3
  26. package/docs/docs/cmd/outlook/report/report-mailactivityusercounts.mdx +0 -3
  27. package/docs/docs/cmd/outlook/report/report-mailactivityuserdetail.mdx +0 -3
  28. package/docs/docs/cmd/outlook/report/report-mailappusageappsusercounts.mdx +0 -3
  29. package/docs/docs/cmd/outlook/report/report-mailappusageusercounts.mdx +0 -3
  30. package/docs/docs/cmd/outlook/report/report-mailappusageuserdetail.mdx +0 -3
  31. package/docs/docs/cmd/outlook/report/report-mailappusageversionsusercounts.mdx +0 -3
  32. package/docs/docs/cmd/outlook/report/report-mailboxusagedetail.mdx +0 -3
  33. package/docs/docs/cmd/outlook/report/report-mailboxusagemailboxcount.mdx +0 -3
  34. package/docs/docs/cmd/outlook/report/report-mailboxusagequotastatusmailboxcounts.mdx +0 -3
  35. package/docs/docs/cmd/outlook/report/report-mailboxusagestorage.mdx +0 -3
  36. package/docs/docs/cmd/skype/report/report-activitycounts.mdx +0 -2
  37. package/docs/docs/cmd/skype/report/report-activityusercounts.mdx +0 -3
  38. package/docs/docs/cmd/skype/report/report-activityuserdetail.mdx +0 -3
  39. package/docs/docs/cmd/spo/report/report-activityfilecounts.mdx +0 -3
  40. package/docs/docs/cmd/spo/report/report-activitypages.mdx +0 -3
  41. package/docs/docs/cmd/spo/report/report-activityusercounts.mdx +0 -3
  42. package/docs/docs/cmd/spo/report/report-activityuserdetail.mdx +0 -3
  43. package/docs/docs/cmd/spo/report/report-siteusagedetail.mdx +0 -3
  44. package/docs/docs/cmd/spo/report/report-siteusagefilecounts.mdx +0 -3
  45. package/docs/docs/cmd/spo/report/report-siteusagepages.mdx +0 -3
  46. package/docs/docs/cmd/spo/report/report-siteusagesitecounts.mdx +0 -3
  47. package/docs/docs/cmd/spo/report/report-siteusagestorage.mdx +0 -3
  48. package/docs/docs/cmd/teams/meeting/meeting-add.mdx +283 -0
  49. package/docs/docs/cmd/teams/report/report-deviceusagedistributionusercounts.mdx +0 -3
  50. package/docs/docs/cmd/teams/report/report-deviceusageusercounts.mdx +0 -3
  51. package/docs/docs/cmd/teams/report/report-deviceusageuserdetail.mdx +0 -3
  52. package/docs/docs/cmd/teams/report/report-useractivitycounts.mdx +0 -3
  53. package/docs/docs/cmd/teams/report/report-useractivityusercounts.mdx +0 -3
  54. package/docs/docs/cmd/teams/report/report-useractivityuserdetail.mdx +0 -3
  55. package/docs/docs/cmd/teams/user/user-app-remove.mdx +13 -4
  56. package/docs/docs/cmd/tenant/report/report-activeusercounts.mdx +0 -3
  57. package/docs/docs/cmd/tenant/report/report-activeuserdetail.mdx +0 -3
  58. package/docs/docs/cmd/tenant/report/report-servicesusercounts.mdx +0 -3
  59. package/docs/docs/cmd/yammer/report/report-activitycounts.mdx +0 -3
  60. package/docs/docs/cmd/yammer/report/report-activityusercounts.mdx +0 -3
  61. package/docs/docs/cmd/yammer/report/report-activityuserdetail.mdx +0 -3
  62. package/docs/docs/cmd/yammer/report/report-deviceusagedistributionusercounts.mdx +0 -3
  63. package/docs/docs/cmd/yammer/report/report-deviceusageusercounts.mdx +0 -3
  64. package/docs/docs/cmd/yammer/report/report-deviceusageuserdetail.mdx +0 -3
  65. package/docs/docs/cmd/yammer/report/report-groupsactivitycounts.mdx +0 -3
  66. package/docs/docs/cmd/yammer/report/report-groupsactivitydetail.mdx +0 -3
  67. package/docs/docs/cmd/yammer/report/report-groupsactivitygroupcounts.mdx +0 -3
  68. package/npm-shrinkwrap.json +6 -6
  69. package/package.json +4 -3
@@ -25,6 +25,7 @@ appInsightsClient.commonProperties = {
25
25
  ci: Boolean(process.env.CI).toString()
26
26
  };
27
27
  appInsightsClient.context.tags['ai.cloud.roleInstance'] = crypto.createHash('sha256').update(appInsightsClient.context.tags['ai.cloud.roleInstance']).digest('hex');
28
- appInsightsClient.context.tags['ai.cloud.role'];
28
+ delete appInsightsClient.context.tags['ai.cloud.role'];
29
+ delete appInsightsClient.context.tags['ai.cloud.roleName'];
29
30
  export default appInsightsClient;
30
31
  //# sourceMappingURL=appInsights.js.map
package/dist/cli/Cli.js CHANGED
@@ -100,43 +100,44 @@ export class Cli {
100
100
  }
101
101
  return Promise.resolve();
102
102
  }
103
- const optionsWithoutShorts = Cli.removeShortOptions(this.optionsFromArgs);
103
+ delete this.optionsFromArgs.options._;
104
+ delete this.optionsFromArgs.options['--'];
104
105
  try {
105
106
  // replace values staring with @ with file contents
106
- Cli.loadOptionValuesFromFiles(optionsWithoutShorts);
107
+ Cli.loadOptionValuesFromFiles(this.optionsFromArgs);
107
108
  }
108
109
  catch (e) {
109
- return this.closeWithError(e, optionsWithoutShorts);
110
+ return this.closeWithError(e, this.optionsFromArgs);
110
111
  }
111
112
  const startProcessing = process.hrtime.bigint();
112
113
  try {
113
114
  // process options before passing them on to validation stage
114
- const contextCommandOptions = await this.loadOptionsFromContext(this.commandToExecute.options, optionsWithoutShorts.options.debug);
115
- optionsWithoutShorts.options = { ...contextCommandOptions, ...optionsWithoutShorts.options };
116
- await this.commandToExecute.command.processOptions(optionsWithoutShorts.options);
115
+ const contextCommandOptions = await this.loadOptionsFromContext(this.commandToExecute.options, this.optionsFromArgs.options.debug);
116
+ this.optionsFromArgs.options = { ...contextCommandOptions, ...this.optionsFromArgs.options };
117
+ await this.commandToExecute.command.processOptions(this.optionsFromArgs.options);
117
118
  const endProcessing = process.hrtime.bigint();
118
119
  timings.options.push(Number(endProcessing - startProcessing));
119
120
  }
120
121
  catch (e) {
121
122
  const endProcessing = process.hrtime.bigint();
122
123
  timings.options.push(Number(endProcessing - startProcessing));
123
- return this.closeWithError(e.message, optionsWithoutShorts, false);
124
+ return this.closeWithError(e.message, this.optionsFromArgs, false);
124
125
  }
125
126
  // if output not specified, set the configured output value (if any)
126
- if (optionsWithoutShorts.options.output === undefined) {
127
- optionsWithoutShorts.options.output = this.getSettingWithDefaultValue(settingsNames.output, 'json');
127
+ if (this.optionsFromArgs.options.output === undefined) {
128
+ this.optionsFromArgs.options.output = this.getSettingWithDefaultValue(settingsNames.output, 'json');
128
129
  }
129
130
  const startValidation = process.hrtime.bigint();
130
- const validationResult = await this.commandToExecute.command.validate(optionsWithoutShorts, this.commandToExecute);
131
+ const validationResult = await this.commandToExecute.command.validate(this.optionsFromArgs, this.commandToExecute);
131
132
  const endValidation = process.hrtime.bigint();
132
133
  timings.validation.push(Number(endValidation - startValidation));
133
134
  if (validationResult !== true) {
134
- return this.closeWithError(validationResult, optionsWithoutShorts, true);
135
+ return this.closeWithError(validationResult, this.optionsFromArgs, true);
135
136
  }
136
137
  const end = process.hrtime.bigint();
137
138
  timings.core.push(Number(end - start));
138
139
  try {
139
- await Cli.executeCommand(this.commandToExecute.command, optionsWithoutShorts);
140
+ await Cli.executeCommand(this.commandToExecute.command, this.optionsFromArgs);
140
141
  const endTotal = process.hrtime.bigint();
141
142
  timings.total.push(Number(endTotal - start));
142
143
  this.printTimings(rawArgs);
@@ -146,7 +147,7 @@ export class Cli {
146
147
  const endTotal = process.hrtime.bigint();
147
148
  timings.total.push(Number(endTotal - start));
148
149
  this.printTimings(rawArgs);
149
- await this.closeWithError(err, optionsWithoutShorts);
150
+ await this.closeWithError(err, this.optionsFromArgs);
150
151
  /* c8 ignore next */
151
152
  }
152
153
  }
package/dist/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  import { Cli } from './cli/Cli.js';
3
- import { telemetry } from './telemetry.js';
4
3
  import { app } from './utils/app.js';
5
4
  // required to make console.log() in combination with piped output synchronous
6
5
  // on Windows/in PowerShell so that the output is not trimmed by calling
@@ -14,12 +13,5 @@ if (!process.env.CLIMICROSOFT365_NOUPDATE) {
14
13
  updateNotifier.default({ pkg: app.packageJson() }).notify({ defer: false });
15
14
  });
16
15
  }
17
- try {
18
- const cli = Cli.getInstance();
19
- cli.execute(process.argv.slice(2));
20
- }
21
- catch (e) {
22
- telemetry.trackException(e);
23
- process.exit(1);
24
- }
16
+ Cli.getInstance().execute(process.argv.slice(2));
25
17
  //# sourceMappingURL=index.js.map
@@ -1,3 +1,9 @@
1
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
+ };
6
+ var _AadGroupListCommand_instances, _a, _AadGroupListCommand_initTelemetry, _AadGroupListCommand_initOptions, _AadGroupListCommand_initValidators;
1
7
  import { Cli } from '../../../../cli/Cli.js';
2
8
  import { odata } from '../../../../utils/odata.js';
3
9
  import GraphCommand from '../../../base/GraphCommand.js';
@@ -12,9 +18,51 @@ class AadGroupListCommand extends GraphCommand {
12
18
  defaultProperties() {
13
19
  return ['id', 'displayName', 'groupType'];
14
20
  }
21
+ constructor() {
22
+ super();
23
+ _AadGroupListCommand_instances.add(this);
24
+ __classPrivateFieldGet(this, _AadGroupListCommand_instances, "m", _AadGroupListCommand_initTelemetry).call(this);
25
+ __classPrivateFieldGet(this, _AadGroupListCommand_instances, "m", _AadGroupListCommand_initOptions).call(this);
26
+ __classPrivateFieldGet(this, _AadGroupListCommand_instances, "m", _AadGroupListCommand_initValidators).call(this);
27
+ }
15
28
  async commandAction(logger, args) {
16
29
  try {
17
- const groups = await odata.getAllItems(`${this.resource}/v1.0/groups`);
30
+ let requestUrl = `${this.resource}/v1.0/groups`;
31
+ let useConsistencyLevelHeader = false;
32
+ if (args.options.type) {
33
+ const groupType = _a.groupTypes.find(g => g.toLowerCase() === args.options.type?.toLowerCase());
34
+ switch (groupType) {
35
+ case 'microsoft365':
36
+ requestUrl += `?$filter=groupTypes/any(c:c+eq+'Unified')`;
37
+ break;
38
+ case 'security':
39
+ requestUrl += '?$filter=securityEnabled eq true and mailEnabled eq false';
40
+ break;
41
+ case 'distribution':
42
+ requestUrl += '?$filter=securityEnabled eq false and mailEnabled eq true';
43
+ break;
44
+ case 'mailEnabledSecurity':
45
+ useConsistencyLevelHeader = true;
46
+ requestUrl += `?$filter=securityEnabled eq true and mailEnabled eq true and not(groupTypes/any(t:t eq 'Unified'))&$count=true`;
47
+ break;
48
+ }
49
+ }
50
+ let groups = [];
51
+ if (useConsistencyLevelHeader) {
52
+ // While using not() function in the filter, we need to specify the ConsistencyLevel header.
53
+ const requestOptions = {
54
+ url: requestUrl,
55
+ headers: {
56
+ accept: 'application/json;odata.metadata=none',
57
+ ConsistencyLevel: 'eventual'
58
+ },
59
+ responseType: 'json'
60
+ };
61
+ groups = await odata.getAllItems(requestOptions);
62
+ }
63
+ else {
64
+ groups = await odata.getAllItems(requestUrl);
65
+ }
18
66
  if (Cli.shouldTrimOutput(args.options.output)) {
19
67
  groups.forEach((group) => {
20
68
  if (group.groupTypes && group.groupTypes.length > 0 && group.groupTypes[0] === 'Unified') {
@@ -38,5 +86,25 @@ class AadGroupListCommand extends GraphCommand {
38
86
  }
39
87
  }
40
88
  }
89
+ _a = AadGroupListCommand, _AadGroupListCommand_instances = new WeakSet(), _AadGroupListCommand_initTelemetry = function _AadGroupListCommand_initTelemetry() {
90
+ this.telemetry.push((args) => {
91
+ Object.assign(this.telemetryProperties, {
92
+ type: typeof args.options.type !== 'undefined'
93
+ });
94
+ });
95
+ }, _AadGroupListCommand_initOptions = function _AadGroupListCommand_initOptions() {
96
+ this.options.unshift({
97
+ option: '--type [type]',
98
+ autocomplete: _a.groupTypes
99
+ });
100
+ }, _AadGroupListCommand_initValidators = function _AadGroupListCommand_initValidators() {
101
+ this.validators.push(async (args) => {
102
+ if (args.options.type && _a.groupTypes.every(g => g.toLowerCase() !== args.options.type?.toLowerCase())) {
103
+ return `${args.options.type} is not a valid type value. Allowed values microsoft365|security|distribution|mailEnabledSecurity.`;
104
+ }
105
+ return true;
106
+ });
107
+ };
108
+ AadGroupListCommand.groupTypes = ['microsoft365', 'security', 'distribution', 'mailEnabledSecurity'];
41
109
  export default new AadGroupListCommand();
42
110
  //# sourceMappingURL=group-list.js.map
@@ -0,0 +1,424 @@
1
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
+ };
6
+ var _ExternalConnectionDoctorCommand_instances, _a, _ExternalConnectionDoctorCommand_initOptions, _ExternalConnectionDoctorCommand_initValidators;
7
+ import os from 'os';
8
+ import { Cli } from '../../../../cli/Cli.js';
9
+ import request from '../../../../request.js';
10
+ import { settingsNames } from '../../../../settingsNames.js';
11
+ import GraphCommand from '../../../base/GraphCommand.js';
12
+ import commands from '../../commands.js';
13
+ class ExternalConnectionDoctorCommand extends GraphCommand {
14
+ get name() {
15
+ return commands.CONNECTION_DOCTOR;
16
+ }
17
+ get description() {
18
+ return 'Checks if the external connection is correctly configured for use with the specified Microsoft 365 experience';
19
+ }
20
+ constructor() {
21
+ super();
22
+ _ExternalConnectionDoctorCommand_instances.add(this);
23
+ this.checksStatus = [];
24
+ __classPrivateFieldGet(this, _ExternalConnectionDoctorCommand_instances, "m", _ExternalConnectionDoctorCommand_initOptions).call(this);
25
+ __classPrivateFieldGet(this, _ExternalConnectionDoctorCommand_instances, "m", _ExternalConnectionDoctorCommand_initValidators).call(this);
26
+ }
27
+ async commandAction(logger, args) {
28
+ const ux = args.options.ux ?? 'all';
29
+ const output = args.options.output;
30
+ this.checksStatus = [];
31
+ const cli = Cli.getInstance();
32
+ const showSpinner = cli.getSettingWithDefaultValue(settingsNames.showSpinner, true) &&
33
+ output === 'text' &&
34
+ typeof global.it === 'undefined';
35
+ let checks = [
36
+ {
37
+ id: 'loadExternalConnection',
38
+ text: 'Load connection',
39
+ fn: this.loadConnection,
40
+ type: 'required'
41
+ },
42
+ {
43
+ id: 'loadSchema',
44
+ text: 'Load schema',
45
+ fn: this.loadSchema,
46
+ type: 'required'
47
+ }
48
+ ];
49
+ if (ux === 'copilot' || ux === 'all') {
50
+ checks.push({
51
+ id: 'copilotRequiredSemanticLabels',
52
+ text: 'Required semantic labels',
53
+ fn: this.checkCopilotRequiredSemanticLabels,
54
+ type: 'required'
55
+ }, {
56
+ id: 'searchableProperties',
57
+ text: 'Searchable properties',
58
+ fn: this.checkSearchableProperties,
59
+ type: 'required'
60
+ }, {
61
+ id: 'contentIngested',
62
+ text: 'Items have content ingested',
63
+ fn: this.checkContentIngested,
64
+ type: 'required'
65
+ }, {
66
+ id: 'enabledForInlineResults',
67
+ text: 'Connection configured for inline results',
68
+ type: 'required'
69
+ }, {
70
+ id: 'itemsHaveActivities',
71
+ text: 'Items have activities recorded',
72
+ type: 'recommended'
73
+ }, {
74
+ id: 'meaningfulNameAndDescription',
75
+ text: 'Meaningful connection name and description',
76
+ type: 'required'
77
+ });
78
+ }
79
+ if (ux === 'search' || ux === 'all') {
80
+ checks.push({
81
+ id: 'semanticLabels',
82
+ text: 'Semantic labels',
83
+ fn: this.checkSemanticLabels,
84
+ type: 'recommended'
85
+ }, {
86
+ id: 'searchableProperties',
87
+ text: 'Searchable properties',
88
+ fn: this.checkSearchableProperties,
89
+ type: 'recommended'
90
+ }, {
91
+ id: 'resultType',
92
+ text: 'Result type',
93
+ fn: this.checkResultType,
94
+ type: 'recommended'
95
+ }, {
96
+ id: 'contentIngested',
97
+ text: 'Items have content ingested',
98
+ fn: this.checkContentIngested,
99
+ type: 'recommended'
100
+ }, {
101
+ id: 'itemsHaveActivities',
102
+ text: 'Items have activities recorded',
103
+ type: 'recommended'
104
+ });
105
+ }
106
+ checks.push({
107
+ id: 'urlToItemResolver',
108
+ text: 'urlToItemResolver configured',
109
+ fn: this.checkUrlToItemResolverConfigured,
110
+ type: 'recommended'
111
+ });
112
+ // filter out duplicate checks based on their IDs
113
+ checks = checks.filter((check, index, self) => self.findIndex(c => c.id === check.id) === index);
114
+ for (const check of checks) {
115
+ if (this.debug) {
116
+ logger.logToStderr(`Running check ${check.id}...`);
117
+ }
118
+ // don't show spinner if running tests
119
+ /* c8 ignore next 3 */
120
+ if (showSpinner) {
121
+ cli.spinner.start(check.text);
122
+ }
123
+ // only automated checks have functions
124
+ if (!check.fn) {
125
+ // don't show spinner if running tests
126
+ /* c8 ignore next 3 */
127
+ if (showSpinner) {
128
+ cli.spinner.info(`${check.text} (manual)`);
129
+ }
130
+ this.checksStatus.push({
131
+ ...check,
132
+ status: 'manual'
133
+ });
134
+ continue;
135
+ }
136
+ const result = await check.fn.bind(this)(check.id, args);
137
+ this.checksStatus.push({ ...check, ...result });
138
+ if (result.status === 'passed') {
139
+ // don't show spinner if running tests
140
+ /* c8 ignore next 3 */
141
+ if (showSpinner) {
142
+ cli.spinner.succeed();
143
+ }
144
+ continue;
145
+ }
146
+ if (result.status === 'failed') {
147
+ // don't show spinner if running tests
148
+ /* c8 ignore next 9 */
149
+ if (showSpinner) {
150
+ const message = `${check.text}: ${result.errorMessage}`;
151
+ if (check.type === 'required') {
152
+ cli.spinner.fail(message);
153
+ }
154
+ else {
155
+ cli.spinner.warn(message);
156
+ }
157
+ }
158
+ if (result.shouldStop) {
159
+ break;
160
+ }
161
+ }
162
+ }
163
+ if (output === 'text' || output === 'none') {
164
+ return;
165
+ }
166
+ this.checksStatus.forEach(s => {
167
+ delete s.data;
168
+ delete s.fn;
169
+ delete s.shouldStop;
170
+ });
171
+ if (output === 'json' || output === 'md') {
172
+ await logger.log(this.checksStatus);
173
+ return;
174
+ }
175
+ if (output === 'csv') {
176
+ this.checksStatus.forEach(r => {
177
+ // we need to set errorMessage to empty string so that it's not
178
+ // removed from the CSV output
179
+ r.errorMessage = r.errorMessage ?? '';
180
+ });
181
+ await logger.log(this.checksStatus);
182
+ }
183
+ }
184
+ getMdOutput(logStatement, command, options) {
185
+ const output = [
186
+ `# ${command.getCommandName()} ${Object.keys(options).filter(o => o !== 'output').map(k => `--${k} "${options[k]}"`).join(' ')}`, os.EOL,
187
+ os.EOL,
188
+ `Date: ${(new Date().toLocaleDateString())}`, os.EOL,
189
+ os.EOL
190
+ ];
191
+ if (logStatement && logStatement.length > 0) {
192
+ const properties = ['text', 'type', 'status', 'errorMessage'];
193
+ output.push('Check|Type|Status|Error message', os.EOL);
194
+ output.push(':----|:--:|:----:|:------------', os.EOL);
195
+ logStatement.forEach(r => {
196
+ output.push(properties.map(p => r[p] ?? '').join('|'), os.EOL);
197
+ });
198
+ logStatement.push(os.EOL);
199
+ }
200
+ return output.join('').trimEnd();
201
+ }
202
+ async loadConnection(id, args) {
203
+ const requestOptions = {
204
+ url: `${this.resource}/v1.0/external/connections/${args.options.id}`,
205
+ headers: {
206
+ accept: 'application/json;odata.metadata=none'
207
+ },
208
+ responseType: 'json'
209
+ };
210
+ try {
211
+ const externalConnection = await request.get(requestOptions);
212
+ return {
213
+ id,
214
+ data: externalConnection,
215
+ status: 'passed'
216
+ };
217
+ }
218
+ catch (ex) {
219
+ return {
220
+ id,
221
+ error: ex?.response?.data?.error?.innerError?.message,
222
+ errorMessage: 'Connection not found',
223
+ shouldStop: true,
224
+ status: 'failed'
225
+ };
226
+ }
227
+ }
228
+ async loadSchema(id, args) {
229
+ const requestOptions = {
230
+ url: `${this.resource}/v1.0/external/connections/${args.options.id}/schema`,
231
+ headers: {
232
+ accept: 'application/json;odata.metadata=none'
233
+ },
234
+ responseType: 'json'
235
+ };
236
+ try {
237
+ const schema = await request.get(requestOptions);
238
+ return {
239
+ id,
240
+ data: schema,
241
+ status: 'passed'
242
+ };
243
+ }
244
+ catch (ex) {
245
+ return {
246
+ id,
247
+ errorMessage: 'Schema not found',
248
+ error: ex?.response?.data?.error?.innerError?.message,
249
+ shouldStop: true,
250
+ status: 'failed'
251
+ };
252
+ }
253
+ }
254
+ async checkCopilotRequiredSemanticLabels(id) {
255
+ const schema = this.checksStatus.find(r => r.id === 'loadSchema').data;
256
+ const requiredLabels = ['title', 'url', 'iconUrl'];
257
+ for (const label of requiredLabels) {
258
+ if (!schema.properties?.find(p => p.labels?.find(l => l.toString() === label))) {
259
+ return {
260
+ id,
261
+ errorMessage: `Missing label ${label}`,
262
+ status: 'failed'
263
+ };
264
+ }
265
+ }
266
+ return {
267
+ id,
268
+ status: 'passed'
269
+ };
270
+ }
271
+ async checkSearchableProperties(id) {
272
+ const schema = this.checksStatus.find(r => r.id === 'loadSchema').data;
273
+ if (!schema.properties?.some(p => p.isSearchable)) {
274
+ return {
275
+ id,
276
+ errorMessage: 'Schema does not have any searchable properties',
277
+ status: 'failed'
278
+ };
279
+ }
280
+ return {
281
+ id,
282
+ status: 'passed'
283
+ };
284
+ }
285
+ async checkContentIngested(id, args) {
286
+ try {
287
+ // find items that belong to the connection
288
+ const searchRequestOptions = {
289
+ url: `${this.resource}/v1.0/search/query`,
290
+ headers: {
291
+ accept: 'application/json;odata.metadata=none'
292
+ },
293
+ responseType: 'json',
294
+ data: {
295
+ requests: [
296
+ {
297
+ entityTypes: [
298
+ 'externalItem'
299
+ ],
300
+ contentSources: [
301
+ `/external/connections/${args.options.id}`
302
+ ],
303
+ query: {
304
+ queryString: '*'
305
+ },
306
+ from: 0,
307
+ size: 1
308
+ }
309
+ ]
310
+ }
311
+ };
312
+ const result = await request.post(searchRequestOptions);
313
+ const hit = result.value?.[0].hitsContainers?.[0]?.hits?.[0];
314
+ if (!hit) {
315
+ return {
316
+ id,
317
+ errorMessage: 'No items found that belong to the connection',
318
+ status: 'failed'
319
+ };
320
+ }
321
+ // something@tenant,itemId
322
+ const itemId = hit.resource?.properties?.substrateContentDomainId?.split(',')?.[1];
323
+ if (!itemId) {
324
+ return {
325
+ id,
326
+ errorMessage: 'Item does not have substrateContentDomainId property or the property is invalid',
327
+ status: 'failed'
328
+ };
329
+ }
330
+ const externalItemRequestOptions = {
331
+ url: `${this.resource}/v1.0/external/connections/${args.options.id}/items/${itemId}`,
332
+ headers: {
333
+ accept: 'application/json;odata.metadata=none'
334
+ },
335
+ responseType: 'json'
336
+ };
337
+ const externalItem = await request.get(externalItemRequestOptions);
338
+ if (!externalItem.content?.value) {
339
+ return {
340
+ id,
341
+ data: externalItem,
342
+ errorMessage: 'Item does not have content or content is empty',
343
+ status: 'failed'
344
+ };
345
+ }
346
+ return {
347
+ id,
348
+ data: externalItem,
349
+ status: 'passed'
350
+ };
351
+ }
352
+ catch (ex) {
353
+ return {
354
+ id,
355
+ error: ex?.response?.data?.error?.innerError?.message,
356
+ errorMessage: 'Error while checking if content is ingested',
357
+ status: 'failed'
358
+ };
359
+ }
360
+ }
361
+ async checkUrlToItemResolverConfigured(id) {
362
+ const externalConnection = this.checksStatus.find(r => r.id === 'loadExternalConnection').data;
363
+ if (!externalConnection.activitySettings?.urlToItemResolvers?.some(r => r)) {
364
+ return {
365
+ id,
366
+ errorMessage: 'urlToItemResolver is not configured',
367
+ status: 'failed'
368
+ };
369
+ }
370
+ return {
371
+ id,
372
+ status: 'passed'
373
+ };
374
+ }
375
+ async checkSemanticLabels(id) {
376
+ const schema = this.checksStatus.find(r => r.id === 'loadSchema').data;
377
+ const hasLabels = schema.properties?.some(p => p.labels?.some(l => l));
378
+ if (!hasLabels) {
379
+ return {
380
+ id,
381
+ errorMessage: `Schema does not have semantic labels`,
382
+ status: 'failed'
383
+ };
384
+ }
385
+ return {
386
+ id,
387
+ status: 'passed'
388
+ };
389
+ }
390
+ async checkResultType(id) {
391
+ const externalConnection = this.checksStatus.find(r => r.id === 'loadExternalConnection').data;
392
+ if (!externalConnection.searchSettings?.searchResultTemplates?.some(t => t)) {
393
+ return {
394
+ id,
395
+ errorMessage: `Connection has no result types`,
396
+ status: 'failed'
397
+ };
398
+ }
399
+ return {
400
+ id,
401
+ status: 'passed'
402
+ };
403
+ }
404
+ }
405
+ _a = ExternalConnectionDoctorCommand, _ExternalConnectionDoctorCommand_instances = new WeakSet(), _ExternalConnectionDoctorCommand_initOptions = function _ExternalConnectionDoctorCommand_initOptions() {
406
+ this.options.unshift({
407
+ option: '-i, --id <id>'
408
+ }, {
409
+ option: '--ux [ux]',
410
+ autocomplete: _a.supportedUx
411
+ });
412
+ }, _ExternalConnectionDoctorCommand_initValidators = function _ExternalConnectionDoctorCommand_initValidators() {
413
+ this.validators.push(async (args) => {
414
+ if (args.options.ux) {
415
+ if (!_a.supportedUx.find(u => u === args.options.ux)) {
416
+ return `${args.options.ux} is not a valid UX. Allowed values are ${_a.supportedUx.join(', ')}`;
417
+ }
418
+ }
419
+ return true;
420
+ });
421
+ };
422
+ ExternalConnectionDoctorCommand.supportedUx = ['copilot', 'search', 'all'];
423
+ export default new ExternalConnectionDoctorCommand();
424
+ //# sourceMappingURL=connection-doctor.js.map