@pnp/cli-microsoft365 9.0.0 → 9.1.0-beta.2d61838

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 (122) hide show
  1. package/allCommands.json +1 -1
  2. package/allCommandsFull.json +1 -1
  3. package/dist/Auth.js +6 -4
  4. package/dist/AuthServer.js +7 -7
  5. package/dist/Command.js +4 -1
  6. package/dist/api.js +1 -1
  7. package/dist/config.js +1 -0
  8. package/dist/m365/base/PowerAutomateCommand.js +1 -1
  9. package/dist/m365/commands/login.js +1 -1
  10. package/dist/m365/external/commands/item/item-add.js +2 -5
  11. package/dist/m365/file/commands/file-move.js +135 -0
  12. package/dist/m365/file/commands.js +2 -1
  13. package/dist/m365/flow/commands/environment/environment-get.js +1 -1
  14. package/dist/m365/flow/commands/environment/environment-list.js +1 -1
  15. package/dist/m365/flow/commands/flow-disable.js +1 -1
  16. package/dist/m365/flow/commands/flow-enable.js +1 -1
  17. package/dist/m365/flow/commands/flow-export.js +17 -16
  18. package/dist/m365/flow/commands/flow-get.js +1 -1
  19. package/dist/m365/flow/commands/flow-list.js +1 -1
  20. package/dist/m365/flow/commands/flow-remove.js +1 -1
  21. package/dist/m365/flow/commands/owner/owner-ensure.js +1 -1
  22. package/dist/m365/flow/commands/owner/owner-list.js +1 -1
  23. package/dist/m365/flow/commands/owner/owner-remove.js +1 -1
  24. package/dist/m365/flow/commands/recyclebinitem/recyclebinitem-list.js +47 -0
  25. package/dist/m365/flow/commands/recyclebinitem/recyclebinitem-restore.js +48 -0
  26. package/dist/m365/flow/commands/run/run-cancel.js +1 -1
  27. package/dist/m365/flow/commands/run/run-get.js +1 -1
  28. package/dist/m365/flow/commands/run/run-list.js +1 -1
  29. package/dist/m365/flow/commands/run/run-resubmit.js +2 -2
  30. package/dist/m365/flow/commands.js +2 -0
  31. package/dist/m365/spfx/commands/project/project-doctor/doctor-1.20.0-rc.1.js +25 -0
  32. package/dist/m365/spfx/commands/project/project-doctor.js +2 -1
  33. package/dist/m365/spfx/commands/project/project-upgrade/upgrade-1.20.0-rc.1.js +57 -0
  34. package/dist/m365/spfx/commands/project/project-upgrade.js +16 -13
  35. package/dist/m365/spfx/commands/spfx-doctor.js +15 -0
  36. package/dist/m365/spo/commands/file/file-roleassignment-add.js +17 -54
  37. package/dist/m365/spo/commands/file/file-roleassignment-remove.js +13 -40
  38. package/dist/m365/spo/commands/file/file-roleinheritance-break.js +5 -13
  39. package/dist/m365/spo/commands/file/file-roleinheritance-reset.js +5 -13
  40. package/dist/m365/spo/commands/folder/folder-sharinglink-add.js +143 -0
  41. package/dist/m365/spo/commands/folder/folder-sharinglink-clear.js +111 -0
  42. package/dist/m365/spo/commands/folder/folder-sharinglink-remove.js +95 -0
  43. package/dist/m365/spo/commands/list/list-get.js +17 -4
  44. package/dist/m365/spo/commands/page/page-remove.js +37 -16
  45. package/dist/m365/spo/commands/page/page-section-add.js +185 -34
  46. package/dist/m365/spo/commands/site/SiteAdmin.js +2 -0
  47. package/dist/m365/spo/commands/site/site-admin-add.js +252 -0
  48. package/dist/m365/spo/commands/site/site-admin-list.js +10 -36
  49. package/dist/m365/spo/commands/site/site-admin-remove.js +194 -0
  50. package/dist/m365/spo/commands/site/site-sharingpermission-set.js +68 -0
  51. package/dist/m365/spo/commands/user/user-get.js +67 -9
  52. package/dist/m365/spo/commands.js +6 -0
  53. package/dist/m365/spp/commands/contentcenter/contentcenter-list.js +56 -0
  54. package/dist/m365/spp/commands.js +5 -0
  55. package/dist/m365/teams/MeetingTranscript.js +2 -0
  56. package/dist/m365/teams/commands/meeting/meeting-transcript-get.js +152 -0
  57. package/dist/m365/teams/commands.js +1 -0
  58. package/dist/m365/viva/commands/engage/Community.js +2 -0
  59. package/dist/m365/viva/commands/engage/engage-community-list.js +28 -0
  60. package/dist/m365/viva/commands.js +1 -0
  61. package/dist/request.js +46 -61
  62. package/dist/utils/driveUtil.js +51 -0
  63. package/dist/utils/spo.js +73 -7
  64. package/dist/utils/timersUtil.js +12 -0
  65. package/dist/utils/urlUtil.js +8 -0
  66. package/dist/utils/zod.js +1 -1
  67. package/docs/docs/cmd/entra/m365group/m365group-report-activitystorage.mdx +2 -2
  68. package/docs/docs/cmd/external/item/item-add.mdx +3 -3
  69. package/docs/docs/cmd/file/file-move.mdx +79 -0
  70. package/docs/docs/cmd/flow/recyclebinitem/recyclebinitem-list.mdx +132 -0
  71. package/docs/docs/cmd/flow/recyclebinitem/recyclebinitem-restore.mdx +55 -0
  72. package/docs/docs/cmd/spo/cdn/cdn-get.mdx +1 -1
  73. package/docs/docs/cmd/spo/cdn/cdn-origin-add.mdx +1 -1
  74. package/docs/docs/cmd/spo/cdn/cdn-origin-list.mdx +1 -1
  75. package/docs/docs/cmd/spo/cdn/cdn-origin-remove.mdx +1 -1
  76. package/docs/docs/cmd/spo/cdn/cdn-policy-list.mdx +1 -1
  77. package/docs/docs/cmd/spo/cdn/cdn-policy-set.mdx +1 -1
  78. package/docs/docs/cmd/spo/externaluser/externaluser-list.mdx +1 -1
  79. package/docs/docs/cmd/spo/folder/folder-sharinglink-add.mdx +125 -0
  80. package/docs/docs/cmd/spo/folder/folder-sharinglink-clear.mdx +50 -0
  81. package/docs/docs/cmd/spo/folder/folder-sharinglink-remove.mdx +50 -0
  82. package/docs/docs/cmd/spo/hidedefaultthemes/hidedefaultthemes-get.mdx +1 -1
  83. package/docs/docs/cmd/spo/hidedefaultthemes/hidedefaultthemes-set.mdx +1 -1
  84. package/docs/docs/cmd/spo/homesite/homesite-remove.mdx +1 -1
  85. package/docs/docs/cmd/spo/knowledgehub/knowledgehub-get.mdx +1 -1
  86. package/docs/docs/cmd/spo/knowledgehub/knowledgehub-remove.mdx +1 -1
  87. package/docs/docs/cmd/spo/knowledgehub/knowledgehub-set.mdx +1 -1
  88. package/docs/docs/cmd/spo/orgassetslibrary/orgassetslibrary-add.mdx +1 -1
  89. package/docs/docs/cmd/spo/orgassetslibrary/orgassetslibrary-list.mdx +1 -1
  90. package/docs/docs/cmd/spo/orgassetslibrary/orgassetslibrary-remove.mdx +1 -1
  91. package/docs/docs/cmd/spo/orgnewssite/orgnewssite-list.mdx +1 -1
  92. package/docs/docs/cmd/spo/orgnewssite/orgnewssite-remove.mdx +1 -1
  93. package/docs/docs/cmd/spo/orgnewssite/orgnewssite-set.mdx +1 -1
  94. package/docs/docs/cmd/spo/page/page-remove.mdx +30 -12
  95. package/docs/docs/cmd/spo/page/page-section-add.mdx +57 -2
  96. package/docs/docs/cmd/spo/site/site-admin-add.mdx +67 -0
  97. package/docs/docs/cmd/spo/site/site-admin-list.mdx +64 -12
  98. package/docs/docs/cmd/spo/site/site-admin-remove.mdx +67 -0
  99. package/docs/docs/cmd/spo/site/site-appcatalog-add.mdx +1 -1
  100. package/docs/docs/cmd/spo/site/site-appcatalog-remove.mdx +1 -1
  101. package/docs/docs/cmd/spo/site/site-commsite-enable.mdx +1 -1
  102. package/docs/docs/cmd/spo/site/site-list.mdx +6 -4
  103. package/docs/docs/cmd/spo/site/site-set.mdx +1 -1
  104. package/docs/docs/cmd/spo/site/site-sharingpermission-set.mdx +58 -0
  105. package/docs/docs/cmd/spo/storageentity/storageentity-remove.mdx +1 -1
  106. package/docs/docs/cmd/spo/storageentity/storageentity-set.mdx +1 -1
  107. package/docs/docs/cmd/spo/tenant/tenant-appcatalog-add.mdx +1 -1
  108. package/docs/docs/cmd/spo/tenant/tenant-appcatalogurl-get.mdx +1 -1
  109. package/docs/docs/cmd/spo/tenant/tenant-recyclebinitem-list.mdx +1 -1
  110. package/docs/docs/cmd/spo/tenant/tenant-recyclebinitem-remove.mdx +1 -1
  111. package/docs/docs/cmd/spo/tenant/tenant-settings-list.mdx +1 -1
  112. package/docs/docs/cmd/spo/theme/theme-apply.mdx +1 -1
  113. package/docs/docs/cmd/spo/theme/theme-get.mdx +1 -1
  114. package/docs/docs/cmd/spo/theme/theme-list.mdx +1 -1
  115. package/docs/docs/cmd/spo/theme/theme-remove.mdx +1 -1
  116. package/docs/docs/cmd/spo/theme/theme-set.mdx +1 -1
  117. package/docs/docs/cmd/spo/user/user-get.mdx +35 -9
  118. package/docs/docs/cmd/spp/contentcenter/contentcenter-list.mdx +287 -0
  119. package/docs/docs/cmd/teams/meeting/meeting-transcript-get.mdx +132 -0
  120. package/docs/docs/cmd/viva/engage/engage-community-list.mdx +81 -0
  121. package/npm-shrinkwrap.json +205 -377
  122. package/package.json +17 -18
@@ -0,0 +1,152 @@
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 _TeamsMeetingTranscriptGetCommand_instances, _TeamsMeetingTranscriptGetCommand_initTelemetry, _TeamsMeetingTranscriptGetCommand_initOptions, _TeamsMeetingTranscriptGetCommand_initValidators, _TeamsMeetingTranscriptGetCommand_initOptionSets;
7
+ import auth from '../../../../Auth.js';
8
+ import request from '../../../../request.js';
9
+ import { entraUser } from '../../../../utils/entraUser.js';
10
+ import { accessToken } from '../../../../utils/accessToken.js';
11
+ import { validation } from '../../../../utils/validation.js';
12
+ import GraphCommand from '../../../base/GraphCommand.js';
13
+ import commands from '../../commands.js';
14
+ import fs from 'fs';
15
+ import path from 'path';
16
+ class TeamsMeetingTranscriptGetCommand extends GraphCommand {
17
+ get name() {
18
+ return commands.MEETING_TRANSCRIPT_GET;
19
+ }
20
+ get description() {
21
+ return 'Downloads a transcript for a given meeting';
22
+ }
23
+ constructor() {
24
+ super();
25
+ _TeamsMeetingTranscriptGetCommand_instances.add(this);
26
+ __classPrivateFieldGet(this, _TeamsMeetingTranscriptGetCommand_instances, "m", _TeamsMeetingTranscriptGetCommand_initTelemetry).call(this);
27
+ __classPrivateFieldGet(this, _TeamsMeetingTranscriptGetCommand_instances, "m", _TeamsMeetingTranscriptGetCommand_initOptions).call(this);
28
+ __classPrivateFieldGet(this, _TeamsMeetingTranscriptGetCommand_instances, "m", _TeamsMeetingTranscriptGetCommand_initValidators).call(this);
29
+ __classPrivateFieldGet(this, _TeamsMeetingTranscriptGetCommand_instances, "m", _TeamsMeetingTranscriptGetCommand_initOptionSets).call(this);
30
+ }
31
+ async commandAction(logger, args) {
32
+ try {
33
+ const isAppOnlyAccessToken = accessToken.isAppOnlyAccessToken(auth.connection.accessTokens[this.resource].accessToken);
34
+ if (this.verbose) {
35
+ await logger.logToStderr(`Retrieving transcript for the given meeting...`);
36
+ }
37
+ let requestUrl = `${this.resource}/beta/`;
38
+ if (isAppOnlyAccessToken) {
39
+ if (!args.options.userId && !args.options.userName && !args.options.email) {
40
+ throw `The option 'userId', 'userName' or 'email' is required when retrieving meeting transcript using app only permissions`;
41
+ }
42
+ requestUrl += 'users/';
43
+ if (args.options.userId) {
44
+ requestUrl += args.options.userId;
45
+ }
46
+ else if (args.options.userName) {
47
+ requestUrl += args.options.userName;
48
+ }
49
+ else if (args.options.email) {
50
+ if (this.verbose) {
51
+ await logger.logToStderr(`Getting user ID for user with email '${args.options.email}'.`);
52
+ }
53
+ const userId = await entraUser.getUserIdByEmail(args.options.email);
54
+ requestUrl += userId;
55
+ }
56
+ }
57
+ else {
58
+ if (args.options.userId || args.options.userName || args.options.email) {
59
+ throw `The options 'userId', 'userName', and 'email' cannot be used while retrieving meeting transcript using delegated permissions`;
60
+ }
61
+ requestUrl += `me`;
62
+ }
63
+ requestUrl += `/onlineMeetings/${args.options.meetingId}/transcripts/${args.options.id}`;
64
+ if (args.options.outputFile) {
65
+ requestUrl += '/content?$format=text/vtt';
66
+ }
67
+ const requestOptions = {
68
+ url: requestUrl,
69
+ headers: {
70
+ accept: 'application/json;odata.metadata=none'
71
+ },
72
+ responseType: args.options.outputFile ? 'stream' : 'json'
73
+ };
74
+ const meetingTranscript = await request.get(requestOptions);
75
+ if (meetingTranscript) {
76
+ if (args.options.outputFile) {
77
+ // Not possible to use async/await for this promise
78
+ await new Promise((resolve, reject) => {
79
+ const writer = fs.createWriteStream(args.options.outputFile);
80
+ meetingTranscript.data.pipe(writer);
81
+ writer.on('error', err => {
82
+ reject(err);
83
+ });
84
+ writer.on('close', async () => {
85
+ const filePath = args.options.outputFile;
86
+ if (this.verbose) {
87
+ await logger.logToStderr(`File saved to path ${filePath}`);
88
+ }
89
+ return resolve();
90
+ });
91
+ });
92
+ }
93
+ else {
94
+ await logger.log(meetingTranscript);
95
+ }
96
+ }
97
+ else {
98
+ throw `The specified meeting transcript was not found`;
99
+ }
100
+ }
101
+ catch (err) {
102
+ this.handleRejectedODataJsonPromise(err);
103
+ }
104
+ }
105
+ }
106
+ _TeamsMeetingTranscriptGetCommand_instances = new WeakSet(), _TeamsMeetingTranscriptGetCommand_initTelemetry = function _TeamsMeetingTranscriptGetCommand_initTelemetry() {
107
+ this.telemetry.push((args) => {
108
+ Object.assign(this.telemetryProperties, {
109
+ userId: typeof args.options.userId !== 'undefined',
110
+ userName: typeof args.options.userName !== 'undefined',
111
+ email: typeof args.options.email !== 'undefined',
112
+ outputFile: typeof args.options.outputFile !== 'undefined'
113
+ });
114
+ });
115
+ }, _TeamsMeetingTranscriptGetCommand_initOptions = function _TeamsMeetingTranscriptGetCommand_initOptions() {
116
+ this.options.unshift({
117
+ option: '-u, --userId [userId]'
118
+ }, {
119
+ option: '-n, --userName [userName]'
120
+ }, {
121
+ option: '--email [email]'
122
+ }, {
123
+ option: '-m, --meetingId <meetingId>'
124
+ }, {
125
+ option: '-i, --id <id>'
126
+ }, {
127
+ option: '-f, --outputFile [outputFile]'
128
+ });
129
+ }, _TeamsMeetingTranscriptGetCommand_initValidators = function _TeamsMeetingTranscriptGetCommand_initValidators() {
130
+ this.validators.push(async (args) => {
131
+ if (args.options.userId && !validation.isValidGuid(args.options.userId)) {
132
+ return `${args.options.userId} is not a valid Guid`;
133
+ }
134
+ if (args.options.userName && !validation.isValidUserPrincipalName(args.options.userName)) {
135
+ return `${args.options.userName} is not a valid user principal name (UPN)`;
136
+ }
137
+ if (args.options.email && !validation.isValidUserPrincipalName(args.options.email)) {
138
+ return `${args.options.email} is not a valid email`;
139
+ }
140
+ if (args.options.outputFile && !fs.existsSync(path.dirname(args.options.outputFile))) {
141
+ return 'Specified path where to save the file does not exits';
142
+ }
143
+ return true;
144
+ });
145
+ }, _TeamsMeetingTranscriptGetCommand_initOptionSets = function _TeamsMeetingTranscriptGetCommand_initOptionSets() {
146
+ this.optionSets.push({
147
+ options: ['userId', 'userName', 'email'],
148
+ runsWhen: (args) => args.options.userId || args.options.userName || args.options.email
149
+ });
150
+ };
151
+ export default new TeamsMeetingTranscriptGetCommand();
152
+ //# sourceMappingURL=meeting-transcript-get.js.map
@@ -32,6 +32,7 @@ export default {
32
32
  MEETING_LIST: `${prefix} meeting list`,
33
33
  MEETING_ATTENDANCEREPORT_GET: `${prefix} meeting attendancereport get`,
34
34
  MEETING_ATTENDANCEREPORT_LIST: `${prefix} meeting attendancereport list`,
35
+ MEETING_TRANSCRIPT_GET: `${prefix} meeting transcript get`,
35
36
  MEETING_TRANSCRIPT_LIST: `${prefix} meeting transcript list`,
36
37
  MEMBERSETTINGS_LIST: `${prefix} membersettings list`,
37
38
  MEMBERSETTINGS_SET: `${prefix} membersettings set`,
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Community.js.map
@@ -0,0 +1,28 @@
1
+ import { odata } from '../../../../utils/odata.js';
2
+ import GraphCommand from '../../../base/GraphCommand.js';
3
+ import commands from '../../commands.js';
4
+ class VivaEngageCommunityListCommand extends GraphCommand {
5
+ get name() {
6
+ return commands.ENGAGE_COMMUNITY_LIST;
7
+ }
8
+ get description() {
9
+ return 'Lists all Viva Engage communities';
10
+ }
11
+ defaultProperties() {
12
+ return ['id', 'displayName', 'privacy'];
13
+ }
14
+ async commandAction(logger) {
15
+ if (this.verbose) {
16
+ await logger.logToStderr('Getting all Viva Engage communities...');
17
+ }
18
+ try {
19
+ const results = await odata.getAllItems(`${this.resource}/v1.0/employeeExperience/communities`);
20
+ await logger.log(results);
21
+ }
22
+ catch (err) {
23
+ this.handleRejectedODataJsonPromise(err);
24
+ }
25
+ }
26
+ }
27
+ export default new VivaEngageCommunityListCommand();
28
+ //# sourceMappingURL=engage-community-list.js.map
@@ -3,6 +3,7 @@ export default {
3
3
  CONNECTIONS_APP_CREATE: `${prefix} connections app create`,
4
4
  ENGAGE_COMMUNITY_ADD: `${prefix} engage community add`,
5
5
  ENGAGE_COMMUNITY_GET: `${prefix} engage community get`,
6
+ ENGAGE_COMMUNITY_LIST: `${prefix} engage community list`,
6
7
  ENGAGE_GROUP_LIST: `${prefix} engage group list`,
7
8
  ENGAGE_GROUP_USER_ADD: `${prefix} engage group user add`,
8
9
  ENGAGE_GROUP_USER_REMOVE: `${prefix} engage group user remove`,
package/dist/request.js CHANGED
@@ -4,6 +4,7 @@ import auth, { Auth } from './Auth.js';
4
4
  import { app } from './utils/app.js';
5
5
  import { formatting } from './utils/formatting.js';
6
6
  import { timings } from './cli/timings.js';
7
+ import { timersUtil } from './utils/timersUtil.js';
7
8
  class Request {
8
9
  set debug(debug) {
9
10
  // if the value to set is the same as current value return early to avoid
@@ -125,76 +126,60 @@ class Request {
125
126
  options.method = 'HEAD';
126
127
  return this.execute(options);
127
128
  }
128
- execute(options, resolve, reject) {
129
+ async execute(options) {
129
130
  const start = process.hrtime.bigint();
130
131
  if (!this._logger) {
131
- return Promise.reject('Logger not set on the request object');
132
+ throw 'Logger not set on the request object';
132
133
  }
133
134
  this.updateRequestForCloudType(options, auth.connection.cloudType);
134
- return new Promise((_resolve, _reject) => {
135
- (() => {
136
- if (options.headers && options.headers['x-anonymous']) {
137
- return Promise.resolve('');
138
- }
139
- else {
140
- const url = options.headers && options.headers['x-resource'] ? options.headers['x-resource'] : options.url;
141
- const resource = Auth.getResourceFromUrl(url);
142
- return auth.ensureAccessToken(resource, this._logger, this._debug);
143
- }
144
- })()
145
- .then((accessToken) => {
146
- if (options.headers) {
147
- if (options.headers['x-anonymous']) {
148
- delete options.headers['x-anonymous'];
149
- }
150
- if (options.headers['x-resource']) {
151
- delete options.headers['x-resource'];
152
- }
153
- if (accessToken !== '') {
154
- options.headers.authorization = `Bearer ${accessToken}`;
155
- }
156
- }
157
- const proxyUrl = process.env.HTTP_PROXY || process.env.HTTPS_PROXY;
158
- if (proxyUrl) {
159
- options.proxy = this.createProxyConfigFromUrl(proxyUrl);
135
+ try {
136
+ let accessToken = '';
137
+ if (options.headers && options.headers['x-anonymous']) {
138
+ accessToken = '';
139
+ }
140
+ else {
141
+ const url = options.headers && options.headers['x-resource'] ? options.headers['x-resource'] : options.url;
142
+ const resource = Auth.getResourceFromUrl(url);
143
+ accessToken = await auth.ensureAccessToken(resource, this._logger, this._debug);
144
+ }
145
+ if (options.headers) {
146
+ if (options.headers['x-anonymous']) {
147
+ delete options.headers['x-anonymous'];
160
148
  }
161
- return this.req(options);
162
- })
163
- .then((res) => {
164
- if (resolve) {
165
- resolve((options.responseType === 'stream' || options.fullResponse) ? res : res.data);
149
+ if (options.headers['x-resource']) {
150
+ delete options.headers['x-resource'];
166
151
  }
167
- else {
168
- const end = process.hrtime.bigint();
169
- timings.api.push(Number(end - start));
170
- _resolve((options.responseType === 'stream' || options.fullResponse) ? res : res.data);
152
+ if (accessToken !== '') {
153
+ options.headers.authorization = `Bearer ${accessToken}`;
171
154
  }
172
- }, async (error) => {
173
- if (error && error.response &&
174
- (error.response.status === 429 ||
175
- error.response.status === 503)) {
176
- let retryAfter = parseInt(error.response.headers['retry-after'] || '10');
177
- if (isNaN(retryAfter)) {
178
- retryAfter = 10;
179
- }
180
- if (this._debug) {
181
- await this._logger.log(`Request throttled. Waiting ${retryAfter}sec before retrying...`);
182
- }
183
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
184
- setTimeout(async () => { this.execute(options, resolve || _resolve, reject || _reject); }, retryAfter * 1000);
155
+ }
156
+ const proxyUrl = process.env.HTTP_PROXY || process.env.HTTPS_PROXY;
157
+ if (proxyUrl) {
158
+ options.proxy = this.createProxyConfigFromUrl(proxyUrl);
159
+ }
160
+ const res = await this.req(options);
161
+ const end = process.hrtime.bigint();
162
+ timings.api.push(Number(end - start));
163
+ return options.responseType === 'stream' || options.fullResponse ?
164
+ res :
165
+ res.data;
166
+ }
167
+ catch (error) {
168
+ const end = process.hrtime.bigint();
169
+ timings.api.push(Number(end - start));
170
+ if (error && error.response && (error.response.status === 429 || error.response.status === 503)) {
171
+ let retryAfter = parseInt(error.response.headers['retry-after'] || '10');
172
+ if (isNaN(retryAfter)) {
173
+ retryAfter = 10;
185
174
  }
186
- else {
187
- if (reject) {
188
- reject(error);
189
- }
190
- else {
191
- const end = process.hrtime.bigint();
192
- timings.api.push(Number(end - start));
193
- _reject(error);
194
- }
175
+ if (this._debug) {
176
+ await this._logger.log(`Request throttled. Waiting ${retryAfter} sec before retrying...`);
195
177
  }
196
- });
197
- });
178
+ await timersUtil.setTimeout(retryAfter * 1000);
179
+ return this.execute(options);
180
+ }
181
+ throw error;
182
+ }
198
183
  }
199
184
  updateRequestForCloudType(options, cloudType) {
200
185
  const url = new URL(options.url);
@@ -0,0 +1,51 @@
1
+ import request from "../request.js";
2
+ export const driveUtil = {
3
+ /**
4
+ * Retrieves the Drive associated with the specified site and URL.
5
+ * @param siteId Site ID
6
+ * @param url Drive URL
7
+ * @returns The Drive associated with the drive URL.
8
+ */
9
+ async getDriveByUrl(siteId, url) {
10
+ const requestOptions = {
11
+ url: `https://graph.microsoft.com/v1.0/sites/${siteId}/drives?$select=webUrl,id`,
12
+ headers: {
13
+ accept: 'application/json;odata.metadata=none'
14
+ },
15
+ responseType: 'json'
16
+ };
17
+ const drives = await request.get(requestOptions);
18
+ const lowerCaseFolderUrl = url.href.toLowerCase();
19
+ const drive = drives.value
20
+ .sort((a, b) => b.webUrl.localeCompare(a.webUrl))
21
+ .find((d) => {
22
+ const driveUrl = d.webUrl.toLowerCase();
23
+ return lowerCaseFolderUrl.startsWith(driveUrl) &&
24
+ (driveUrl.length === lowerCaseFolderUrl.length ||
25
+ lowerCaseFolderUrl[driveUrl.length] === '/');
26
+ });
27
+ if (!drive) {
28
+ throw `Drive '${url.href}' not found`;
29
+ }
30
+ return drive;
31
+ },
32
+ /**
33
+ * Retrieves the ID of a drive item (file, folder, etc.) associated with the given drive and item URL.
34
+ * @param drive The Drive object containing the item
35
+ * @param itemUrl Item URL
36
+ * @returns Drive item ID
37
+ */
38
+ async getDriveItemId(drive, itemUrl) {
39
+ const relativeItemUrl = itemUrl.href.replace(new RegExp(`${drive.webUrl}`, 'i'), '').replace(/\/+$/, '');
40
+ const requestOptions = {
41
+ url: `https://graph.microsoft.com/v1.0/drives/${drive.id}/root${relativeItemUrl ? `:${relativeItemUrl}` : ''}?$select=id`,
42
+ headers: {
43
+ accept: 'application/json;odata.metadata=none'
44
+ },
45
+ responseType: 'json'
46
+ };
47
+ const driveItem = await request.get(requestOptions);
48
+ return driveItem?.id;
49
+ }
50
+ };
51
+ //# sourceMappingURL=driveUtil.js.map
package/dist/utils/spo.js CHANGED
@@ -490,10 +490,10 @@ export const spo = {
490
490
  * @param webUrl Web url
491
491
  * @param email The email of the user
492
492
  * @param logger the Logger object
493
- * @param verbose set if verbose logging should be logged
493
+ * @param verbose set for verbose logging
494
494
  */
495
495
  async getUserByEmail(webUrl, email, logger, verbose) {
496
- if (verbose) {
496
+ if (verbose && logger) {
497
497
  await logger.logToStderr(`Retrieving the spo user by email ${email}`);
498
498
  }
499
499
  const requestUrl = `${webUrl}/_api/web/siteusers/GetByEmail('${formatting.encodeQueryParameter(email)}')`;
@@ -564,10 +564,10 @@ export const spo = {
564
564
  * @param webUrl Web url
565
565
  * @param name The name of the group
566
566
  * @param logger the Logger object
567
- * @param verbose set if verbose logging should be logged
567
+ * @param verbose set for verbose logging
568
568
  */
569
569
  async getGroupByName(webUrl, name, logger, verbose) {
570
- if (verbose) {
570
+ if (verbose && logger) {
571
571
  await logger.logToStderr(`Retrieving the group by name ${name}`);
572
572
  }
573
573
  const requestUrl = `${webUrl}/_api/web/sitegroups/GetByName('${formatting.encodeQueryParameter(name)}')`;
@@ -586,10 +586,10 @@ export const spo = {
586
586
  * @param webUrl Web url
587
587
  * @param name the name of the role definition
588
588
  * @param logger the Logger object
589
- * @param debug set if debug logging should be logged
589
+ * @param verbose set for verbose logging
590
590
  */
591
- async getRoleDefinitionByName(webUrl, name, logger, debug) {
592
- if (debug) {
591
+ async getRoleDefinitionByName(webUrl, name, logger, verbose) {
592
+ if (verbose && logger) {
593
593
  await logger.logToStderr(`Retrieving the role definitions for ${name}`);
594
594
  }
595
595
  const roledefinitions = await odata.getAllItems(`${webUrl}/_api/web/roledefinitions`);
@@ -1516,6 +1516,72 @@ export const spo = {
1516
1516
  };
1517
1517
  const itemsResponse = await request.get(requestOptionsItems);
1518
1518
  return (itemsResponse);
1519
+ },
1520
+ /**
1521
+ * Retrieves the file by id.
1522
+ * Returns a FileProperties object
1523
+ * @param webUrl Web url
1524
+ * @param id the id of the file
1525
+ * @param logger the Logger object
1526
+ * @param verbose set for verbose logging
1527
+ */
1528
+ async getFileById(webUrl, id, logger, verbose) {
1529
+ if (verbose && logger) {
1530
+ await logger.logToStderr(`Retrieving the file with id ${id}`);
1531
+ }
1532
+ const requestUrl = `${webUrl}/_api/web/GetFileById('${formatting.encodeQueryParameter(id)}')`;
1533
+ const requestOptions = {
1534
+ url: requestUrl,
1535
+ headers: {
1536
+ 'accept': 'application/json;odata=nometadata'
1537
+ },
1538
+ responseType: 'json'
1539
+ };
1540
+ const file = await request.get(requestOptions);
1541
+ return file;
1542
+ },
1543
+ /**
1544
+ * Gets the primary owner login from a site as admin.
1545
+ * @param adminUrl The SharePoint admin URL
1546
+ * @param siteId The site ID
1547
+ * @param logger The logger object
1548
+ * @param verbose If in verbose mode
1549
+ * @returns Owner login name
1550
+ */
1551
+ async getPrimaryAdminLoginNameAsAdmin(adminUrl, siteId, logger, verbose) {
1552
+ if (verbose) {
1553
+ await logger.logToStderr('Getting the primary admin login name...');
1554
+ }
1555
+ const requestOptions = {
1556
+ url: `${adminUrl}/_api/SPO.Tenant/sites('${siteId}')?$select=OwnerLoginName`,
1557
+ headers: {
1558
+ accept: 'application/json;odata=nometadata'
1559
+ },
1560
+ responseType: 'json'
1561
+ };
1562
+ const response = await request.get(requestOptions);
1563
+ return response.OwnerLoginName;
1564
+ },
1565
+ /**
1566
+ * Gets the primary owner login from a site.
1567
+ * @param siteUrl The site URL
1568
+ * @param logger The logger object
1569
+ * @param verbose If in verbose mode
1570
+ * @returns Owner login name
1571
+ */
1572
+ async getPrimaryOwnerLoginFromSite(siteUrl, logger, verbose) {
1573
+ if (verbose) {
1574
+ await logger.logToStderr('Getting the primary admin login name...');
1575
+ }
1576
+ const requestOptions = {
1577
+ url: `${siteUrl}/_api/site/owner`,
1578
+ headers: {
1579
+ 'accept': 'application/json;odata=nometadata'
1580
+ },
1581
+ responseType: 'json'
1582
+ };
1583
+ const responseContent = await request.get(requestOptions);
1584
+ return responseContent?.LoginName;
1519
1585
  }
1520
1586
  };
1521
1587
  //# sourceMappingURL=spo.js.map
@@ -0,0 +1,12 @@
1
+ import { setTimeout } from "timers/promises";
2
+ export const timersUtil = {
3
+ /**
4
+ * Timeout for a specific duration.
5
+ * @param duration Duration in milliseconds.
6
+ */
7
+ /* c8 ignore next 3 */
8
+ async setTimeout(duration) {
9
+ return setTimeout(duration);
10
+ }
11
+ };
12
+ //# sourceMappingURL=timersUtil.js.map
@@ -198,6 +198,14 @@ export const urlUtil = {
198
198
  return rootUrl.origin;
199
199
  }
200
200
  },
201
+ /**
202
+ * Removes leading slashes from the URL.
203
+ * @param url The URL to process.
204
+ * @returns The URL without leading slashes.
205
+ */
206
+ removeLeadingSlashes(url) {
207
+ return url.replace(/^\/+/, '');
208
+ },
201
209
  /**
202
210
  * Removes trailing slashes from the URL.
203
211
  * @param url The URL to process.
package/dist/utils/zod.js CHANGED
@@ -60,7 +60,7 @@ function parseDefault(def, _options, currentOption) {
60
60
  function parseEnum(def, _options, currentOption) {
61
61
  if (currentOption) {
62
62
  currentOption.type = 'string';
63
- currentOption.autocomplete = def.values;
63
+ currentOption.autocomplete = [...def.values];
64
64
  }
65
65
  return;
66
66
  }
@@ -9,13 +9,13 @@ Get the total storage used across all group mailboxes and group sites
9
9
  ## Usage
10
10
 
11
11
  ```sh
12
- m365 entra m365group report activitystorage [options]
12
+ m365 entra m365group report activitystorage [options]
13
13
  ```
14
14
 
15
15
  ## Alias
16
16
 
17
17
  ```sh
18
- m365 aad m365group report activitystorage [options]
18
+ m365 aad m365group report activitystorage [options]
19
19
  ```
20
20
 
21
21
  ## Options
@@ -63,13 +63,13 @@ For more information about using these options, see the Microsoft Graph API docu
63
63
  Creates an external item with simple properties that everyone is allowed to access
64
64
 
65
65
  ```sh
66
- m365 external item add --id "pnp-ensure-siteassets-library" --connectionId "samplesolutiongallery" --content "Ensure that the Site Assets library is created." --title "Ensure the Site Assets Library is created" --description "Ensure that the Site Assets library is created." --authors "Phil Harding" --acls "grant,everyone,everyone"
66
+ m365 external item add --id "pnp-ensure-siteassets-library" --externalConnectionId "samplesolutiongallery" --content "Ensure that the Site Assets library is created." --title "Ensure the Site Assets Library is created" --description "Ensure that the Site Assets library is created." --authors "Phil Harding" --acls "grant,everyone,everyone"
67
67
  ```
68
68
 
69
69
  Creates an external item with multi-value properties accessible only to users from the specified Entra group
70
70
 
71
71
  ```sh
72
- m365 external item add --id "pnp-ensure-siteassets-library" --connectionId "samplesolutiongallery" --content "Ensure that the Site Assets library is created." --title "Ensure the Site Assets Library is created" --description "Ensure that the Site Assets library is created." --authors@odata.type "Collection(String)" --authors "Phil Harding;#Steve Smith" --acls "grant,group,Super users"
72
+ m365 external item add --id "pnp-ensure-siteassets-library" --externalConnectionId "samplesolutiongallery" --content "Ensure that the Site Assets library is created." --title "Ensure the Site Assets Library is created" --description "Ensure that the Site Assets library is created." --authors@odata.type "Collection(String)" --authors "Phil Harding;#Steve Smith" --acls "grant,group,Super users"
73
73
  ```
74
74
 
75
75
  ## Response
@@ -123,7 +123,7 @@ m365 external item add --id "pnp-ensure-siteassets-library" --connectionId "samp
123
123
  <TabItem value="Markdown">
124
124
 
125
125
  ```md
126
- # m365 external item add --id "pnp-ensure-siteassets-library" --connectionId "samplesolutiongallery" --content "Ensure that the Site Assets library is created." --title "Ensure the Site Assets Library is created" --description "Ensure that the Site Assets library is created." --authors "Phil Harding" --acls "grant,everyone,everyone"
126
+ # m365 external item add --id "pnp-ensure-siteassets-library" --externalConnectionId "samplesolutiongallery" --content "Ensure that the Site Assets library is created." --title "Ensure the Site Assets Library is created" --description "Ensure that the Site Assets library is created." --authors "Phil Harding" --acls "grant,everyone,everyone"
127
127
 
128
128
  Date: 2023-10-28
129
129
 
@@ -0,0 +1,79 @@
1
+ import Global from '/docs/cmd/_global.mdx';
2
+
3
+ # file move
4
+
5
+ Moves a file to another location using the Microsoft Graph
6
+
7
+ ## Usage
8
+
9
+ ```sh
10
+ m365 file move [options]
11
+ ```
12
+
13
+ ## Options
14
+
15
+ ```md definition-list
16
+ `-u, --webUrl <webUrl>`
17
+ : The URL of the site where the file is located.
18
+
19
+ `-s, --sourceUrl <sourceUrl>`
20
+ : Server-relative or absolute URL of the file.
21
+
22
+ `-t, --targetUrl <targetUrl>`
23
+ : Server-relative or absolute URL of the location.
24
+
25
+ `--newName [newName]`
26
+ : New name of the destination file.
27
+
28
+ `--nameConflictBehavior [nameConflictBehavior]`
29
+ : Behavior when a document with the same name is already present at the destination. Possible values: `fail`, `replace`, `rename`. Default is `fail`.
30
+ ```
31
+
32
+ <Global />
33
+
34
+ ## Remarks
35
+
36
+ - If the source and target locations are within the same document library or drive, the command will utilize the Move DriveItem API, preserving the version history of the file.
37
+ - If the source and target locations are in different document libraries or drives, the command will use a copy-and-delete combination to move the file. Please note that in this case, version history will not be retained.
38
+
39
+ ## Examples
40
+
41
+ Move a file by server-relative URL to a folder in the same document library
42
+
43
+ ```sh
44
+ m365 file move --webUrl "https://contoso.sharepoint.com/sites/project" --sourceUrl "/sites/project/Shared Documents/Document.pdf" --targetUrl "/sites/project/Shared Documents/NewFolder"
45
+ ```
46
+
47
+ Move a file by server-relative URL to a document library in another site collection with server relative URL
48
+
49
+ ```sh
50
+ m365 file move --webUrl "https://contoso.sharepoint.com/sites/project" --sourceUrl "/sites/project/Shared Documents/Document.pdf" --targetUrl "/sites/IT/Shared Documents"
51
+ ```
52
+
53
+ Move a file by absolute URL to a document library in another site collection with absolute URL
54
+
55
+ ```sh
56
+ m365 file move --webUrl "https://contoso.sharepoint.com" --sourceUrl "https://contoso.sharepoint.com/Shared Documents/Document.pdf" --targetUrl "https://contoso.sharepoint.com/sites/IT/Shared Documents"
57
+ ```
58
+
59
+ Move a file to a document library in another site collection and rename the file
60
+
61
+ ```sh
62
+ m365 file move --webUrl "https://contoso.sharepoint.com" --sourceUrl "/Shared Documents/Document.pdf" --targetUrl "/sites/IT/Shared Documents" --newName "newName"
63
+ ```
64
+
65
+ Move a file to a document library in another site collection and rename the file if a file with the same name already exists.
66
+
67
+ ```sh
68
+ m365 file move --webUrl "https://contoso.sharepoint.com" --sourceUrl "/Shared Documents/Document.pdf" --targetUrl "/sites/IT/Shared Documents" --nameConflictBehavior rename
69
+ ```
70
+
71
+ Move a file to Onedrive for business
72
+
73
+ ```sh
74
+ m365 file move --webUrl "https://contoso.sharepoint.com" --sourceUrl "/Shared Documents/Document.pdf" --targetUrl "https://contoso-my.sharepoint.com/personal/john_contoso_onmicrosoft_com/documents"
75
+ ```
76
+
77
+ ## Response
78
+
79
+ The command won't return a response on success.