@pnp/cli-microsoft365 7.0.0-beta.2756488 → 7.0.0-beta.68abdfc
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/dist/m365/search/commands/externalconnection/externalconnection-remove.js +34 -35
- package/dist/m365/spfx/commands/project/project-externalize/rules/DynamicRule.js +51 -59
- package/dist/m365/spo/commands/folder/folder-remove.js +28 -30
- package/dist/m365/spo/commands/tenant/tenant-appcatalog-add.js +16 -13
- package/dist/m365/spo/commands/tenant/tenant-applicationcustomizer-set.js +2 -80
- package/dist/m365/spo/commands/tenant/tenant-recyclebinitem-remove.js +48 -48
- package/dist/m365/teams/commands/chat/chat-get.js +4 -4
- package/dist/m365/teams/commands/chat/chat-message-send.js +4 -4
- package/docs/docs/cmd/spo/tenant/tenant-applicationcustomizer-set.mdx +3 -12
- package/package.json +1 -1
|
@@ -35,31 +35,48 @@ class SearchExternalConnectionRemoveCommand extends GraphCommand_1.default {
|
|
|
35
35
|
__classPrivateFieldGet(this, _SearchExternalConnectionRemoveCommand_instances, "m", _SearchExternalConnectionRemoveCommand_initOptionSets).call(this);
|
|
36
36
|
}
|
|
37
37
|
getExternalConnectionId(args) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
38
|
+
if (args.options.id) {
|
|
39
|
+
return Promise.resolve(args.options.id);
|
|
40
|
+
}
|
|
41
|
+
const requestOptions = {
|
|
42
|
+
url: `${this.resource}/v1.0/external/connections?$filter=name eq '${formatting_1.formatting.encodeQueryParameter(args.options.name)}'&$select=id`,
|
|
43
|
+
headers: {
|
|
44
|
+
accept: 'application/json;odata.metadata=none'
|
|
45
|
+
},
|
|
46
|
+
responseType: 'json'
|
|
47
|
+
};
|
|
48
|
+
return request_1.default
|
|
49
|
+
.get(requestOptions)
|
|
50
|
+
.then((res) => {
|
|
50
51
|
if (res.value.length === 1) {
|
|
51
|
-
return res.value[0].id;
|
|
52
|
+
return Promise.resolve(res.value[0].id);
|
|
52
53
|
}
|
|
53
54
|
if (res.value.length === 0) {
|
|
54
|
-
|
|
55
|
+
return Promise.reject(`The specified connection does not exist in Microsoft Search`);
|
|
55
56
|
}
|
|
56
|
-
|
|
57
|
+
return Promise.reject(`Multiple external connections with name ${args.options.name} found. Please disambiguate (IDs): ${res.value.map(x => x.id).join(', ')}`);
|
|
57
58
|
});
|
|
58
59
|
}
|
|
59
60
|
commandAction(logger, args) {
|
|
60
61
|
return __awaiter(this, void 0, void 0, function* () {
|
|
62
|
+
const removeExternalConnection = () => __awaiter(this, void 0, void 0, function* () {
|
|
63
|
+
try {
|
|
64
|
+
const externalConnectionId = yield this.getExternalConnectionId(args);
|
|
65
|
+
const requestOptions = {
|
|
66
|
+
url: `${this.resource}/v1.0/external/connections/${formatting_1.formatting.encodeQueryParameter(externalConnectionId)}`,
|
|
67
|
+
headers: {
|
|
68
|
+
accept: 'application/json;odata.metadata=none'
|
|
69
|
+
},
|
|
70
|
+
responseType: 'json'
|
|
71
|
+
};
|
|
72
|
+
yield request_1.default.delete(requestOptions);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
this.handleRejectedODataJsonPromise(err);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
61
78
|
if (args.options.force) {
|
|
62
|
-
yield
|
|
79
|
+
yield removeExternalConnection();
|
|
63
80
|
}
|
|
64
81
|
else {
|
|
65
82
|
const result = yield Cli_1.Cli.prompt({
|
|
@@ -69,29 +86,11 @@ class SearchExternalConnectionRemoveCommand extends GraphCommand_1.default {
|
|
|
69
86
|
message: `Are you sure you want to remove the external connection '${args.options.id || args.options.name}'?`
|
|
70
87
|
});
|
|
71
88
|
if (result.continue) {
|
|
72
|
-
yield
|
|
89
|
+
yield removeExternalConnection();
|
|
73
90
|
}
|
|
74
91
|
}
|
|
75
92
|
});
|
|
76
93
|
}
|
|
77
|
-
removeExternalConnection(args) {
|
|
78
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
79
|
-
try {
|
|
80
|
-
const externalConnectionId = yield this.getExternalConnectionId(args);
|
|
81
|
-
const requestOptions = {
|
|
82
|
-
url: `${this.resource}/v1.0/external/connections/${formatting_1.formatting.encodeQueryParameter(externalConnectionId)}`,
|
|
83
|
-
headers: {
|
|
84
|
-
accept: 'application/json;odata.metadata=none'
|
|
85
|
-
},
|
|
86
|
-
responseType: 'json'
|
|
87
|
-
};
|
|
88
|
-
yield request_1.default.delete(requestOptions);
|
|
89
|
-
}
|
|
90
|
-
catch (err) {
|
|
91
|
-
this.handleRejectedODataJsonPromise(err);
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
94
|
}
|
|
96
95
|
_SearchExternalConnectionRemoveCommand_instances = new WeakSet(), _SearchExternalConnectionRemoveCommand_initTelemetry = function _SearchExternalConnectionRemoveCommand_initTelemetry() {
|
|
97
96
|
this.telemetry.push((args) => {
|
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
exports.DynamicRule = void 0;
|
|
13
4
|
const fs = require("fs");
|
|
@@ -21,32 +12,36 @@ class DynamicRule extends BasicDependencyRule_1.BasicDependencyRule {
|
|
|
21
12
|
this.fileVariationSuffixes = ['.min', '.bundle', '-min', '.bundle.min'];
|
|
22
13
|
}
|
|
23
14
|
visit(project) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
15
|
+
if (!project.packageJson ||
|
|
16
|
+
!project.packageJson.dependencies) {
|
|
17
|
+
return Promise.resolve({ entries: [], suggestions: [] });
|
|
18
|
+
}
|
|
19
|
+
const validPackageNames = Object.getOwnPropertyNames(project.packageJson.dependencies)
|
|
20
|
+
.filter(x => this.restrictedNamespaces.map(y => x.indexOf(y) === -1).reduce((y, z) => y && z))
|
|
21
|
+
.filter(x => this.restrictedModules.indexOf(x) === -1);
|
|
22
|
+
return Promise
|
|
23
|
+
.all(validPackageNames.map((x) => this.getExternalEntryForPackage(x, project)))
|
|
24
|
+
.then((res) => {
|
|
32
25
|
return {
|
|
33
|
-
entries: res
|
|
26
|
+
entries: res
|
|
27
|
+
.filter(x => x !== undefined)
|
|
28
|
+
.map(x => x),
|
|
34
29
|
suggestions: []
|
|
35
30
|
};
|
|
36
31
|
});
|
|
37
32
|
}
|
|
38
33
|
getExternalEntryForPackage(packageName, project) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
34
|
+
const version = project.packageJson.dependencies[packageName];
|
|
35
|
+
const filesPaths = this.getFilePath(packageName).map(x => this.cleanFilePath(x));
|
|
36
|
+
if (!version || filesPaths.length === 0) {
|
|
37
|
+
return Promise.resolve(undefined);
|
|
38
|
+
}
|
|
39
|
+
const filesPathsVariations = filesPaths
|
|
40
|
+
.map(x => this.fileVariationSuffixes.map(y => x.indexOf(y) === -1 ? x.replace('.js', `${y}.js`) : x))
|
|
41
|
+
.reduce((x, y) => [...x, ...y]);
|
|
42
|
+
const pathsAndVariations = [...filesPaths, ...filesPathsVariations];
|
|
43
|
+
return Promise.all(pathsAndVariations.map(x => this.getExternalEntryForFilePath(x, packageName, version)))
|
|
44
|
+
.then((externalizeEntryCandidates) => {
|
|
50
45
|
const dExternalizeEntryCandidates = externalizeEntryCandidates.filter(x => x !== undefined);
|
|
51
46
|
const minifiedModule = dExternalizeEntryCandidates.find(x => !x.globalName && this.pathContainsMinifySuffix(x.path));
|
|
52
47
|
const minifiedNonModule = dExternalizeEntryCandidates.find(x => x.globalName && this.pathContainsMinifySuffix(x.path));
|
|
@@ -62,29 +57,31 @@ class DynamicRule extends BasicDependencyRule_1.BasicDependencyRule {
|
|
|
62
57
|
.filter(y => y > -1).length > 0;
|
|
63
58
|
}
|
|
64
59
|
getExternalEntryForFilePath(filePath, packageName, version) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
60
|
+
const url = this.getFileUrl(packageName, version, filePath);
|
|
61
|
+
return this
|
|
62
|
+
.testUrl(url)
|
|
63
|
+
.then((testResult) => {
|
|
68
64
|
if (!testResult) {
|
|
69
|
-
return undefined;
|
|
70
|
-
}
|
|
71
|
-
const moduleInfo = yield this.getModuleType(url);
|
|
72
|
-
if (moduleInfo.scriptType === 'CommonJs') {
|
|
73
|
-
return undefined; //browsers don't support those module types without an additional library
|
|
74
|
-
}
|
|
75
|
-
else if (moduleInfo.scriptType === 'ES2015' || moduleInfo.scriptType === 'AMD') {
|
|
76
|
-
return {
|
|
77
|
-
key: packageName,
|
|
78
|
-
path: url
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
else { //TODO for non-module and UMD we should technically add dependencies as well
|
|
82
|
-
return {
|
|
83
|
-
key: packageName,
|
|
84
|
-
path: url,
|
|
85
|
-
globalName: moduleInfo.exports && moduleInfo.exports.length > 0 ? moduleInfo.exports[0] : packageName // examples where this is not good https://unpkg.com/@pnp/polyfill-ie11@^1.0.2/dist/index.js https://unpkg.com/moment-timezone@^0.5.27/builds/moment-timezone-with-data.js
|
|
86
|
-
};
|
|
65
|
+
return Promise.resolve(undefined);
|
|
87
66
|
}
|
|
67
|
+
return this.getModuleType(url).then((moduleInfo) => {
|
|
68
|
+
if (moduleInfo.scriptType === 'CommonJs') {
|
|
69
|
+
return Promise.resolve(undefined); //browsers don't support those module types without an additional library
|
|
70
|
+
}
|
|
71
|
+
else if (moduleInfo.scriptType === 'ES2015' || moduleInfo.scriptType === 'AMD') {
|
|
72
|
+
return {
|
|
73
|
+
key: packageName,
|
|
74
|
+
path: url
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
else { //TODO for non-module and UMD we should technically add dependencies as well
|
|
78
|
+
return {
|
|
79
|
+
key: packageName,
|
|
80
|
+
path: url,
|
|
81
|
+
globalName: moduleInfo.exports && moduleInfo.exports.length > 0 ? moduleInfo.exports[0] : packageName // examples where this is not good https://unpkg.com/@pnp/polyfill-ie11@^1.0.2/dist/index.js https://unpkg.com/moment-timezone@^0.5.27/builds/moment-timezone-with-data.js
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
});
|
|
88
85
|
});
|
|
89
86
|
}
|
|
90
87
|
getModuleType(url) {
|
|
@@ -104,15 +101,10 @@ class DynamicRule extends BasicDependencyRule_1.BasicDependencyRule {
|
|
|
104
101
|
return `https://unpkg.com/${packageName}@${version}/${filePath}`;
|
|
105
102
|
}
|
|
106
103
|
testUrl(url) {
|
|
107
|
-
return
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
catch (_a) {
|
|
113
|
-
return false;
|
|
114
|
-
}
|
|
115
|
-
});
|
|
104
|
+
return request_1.default
|
|
105
|
+
.head({ url: url, headers: { 'x-anonymous': 'true' } })
|
|
106
|
+
.then(() => true)
|
|
107
|
+
.catch(() => false);
|
|
116
108
|
}
|
|
117
109
|
getFilePath(packageName) {
|
|
118
110
|
const packageJsonFilePath = `node_modules/${packageName}/package.json`;
|
|
@@ -38,8 +38,34 @@ class SpoFolderRemoveCommand extends SpoCommand_1.default {
|
|
|
38
38
|
}
|
|
39
39
|
commandAction(logger, args) {
|
|
40
40
|
return __awaiter(this, void 0, void 0, function* () {
|
|
41
|
+
const removeFolder = () => __awaiter(this, void 0, void 0, function* () {
|
|
42
|
+
if (this.verbose) {
|
|
43
|
+
logger.logToStderr(`Removing folder in site at ${args.options.webUrl}...`);
|
|
44
|
+
}
|
|
45
|
+
const serverRelativeUrl = urlUtil_1.urlUtil.getServerRelativePath(args.options.webUrl, args.options.url);
|
|
46
|
+
let requestUrl = `${args.options.webUrl}/_api/web/GetFolderByServerRelativeUrl('${formatting_1.formatting.encodeQueryParameter(serverRelativeUrl)}')`;
|
|
47
|
+
if (args.options.recycle) {
|
|
48
|
+
requestUrl += `/recycle()`;
|
|
49
|
+
}
|
|
50
|
+
const requestOptions = {
|
|
51
|
+
url: requestUrl,
|
|
52
|
+
method: 'POST',
|
|
53
|
+
headers: {
|
|
54
|
+
'X-HTTP-Method': 'DELETE',
|
|
55
|
+
'If-Match': '*',
|
|
56
|
+
'accept': 'application/json;odata=nometadata'
|
|
57
|
+
},
|
|
58
|
+
responseType: 'json'
|
|
59
|
+
};
|
|
60
|
+
try {
|
|
61
|
+
yield request_1.default.post(requestOptions);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
this.handleRejectedODataJsonPromise(err);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
41
67
|
if (args.options.force) {
|
|
42
|
-
yield
|
|
68
|
+
yield removeFolder();
|
|
43
69
|
}
|
|
44
70
|
else {
|
|
45
71
|
const result = yield Cli_1.Cli.prompt({
|
|
@@ -49,39 +75,11 @@ class SpoFolderRemoveCommand extends SpoCommand_1.default {
|
|
|
49
75
|
message: `Are you sure you want to ${args.options.recycle ? "recycle" : "remove"} the folder ${args.options.url} located in site ${args.options.webUrl}?`
|
|
50
76
|
});
|
|
51
77
|
if (result.continue) {
|
|
52
|
-
yield
|
|
78
|
+
yield removeFolder();
|
|
53
79
|
}
|
|
54
80
|
}
|
|
55
81
|
});
|
|
56
82
|
}
|
|
57
|
-
removeFolder(logger, options) {
|
|
58
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
-
if (this.verbose) {
|
|
60
|
-
logger.logToStderr(`Removing folder in site at ${options.webUrl}...`);
|
|
61
|
-
}
|
|
62
|
-
const serverRelativeUrl = urlUtil_1.urlUtil.getServerRelativePath(options.webUrl, options.url);
|
|
63
|
-
let requestUrl = `${options.webUrl}/_api/web/GetFolderByServerRelativeUrl('${formatting_1.formatting.encodeQueryParameter(serverRelativeUrl)}')`;
|
|
64
|
-
if (options.recycle) {
|
|
65
|
-
requestUrl += `/recycle()`;
|
|
66
|
-
}
|
|
67
|
-
const requestOptions = {
|
|
68
|
-
url: requestUrl,
|
|
69
|
-
method: 'POST',
|
|
70
|
-
headers: {
|
|
71
|
-
'X-HTTP-Method': 'DELETE',
|
|
72
|
-
'If-Match': '*',
|
|
73
|
-
'accept': 'application/json;odata=nometadata'
|
|
74
|
-
},
|
|
75
|
-
responseType: 'json'
|
|
76
|
-
};
|
|
77
|
-
try {
|
|
78
|
-
yield request_1.default.post(requestOptions);
|
|
79
|
-
}
|
|
80
|
-
catch (err) {
|
|
81
|
-
this.handleRejectedODataJsonPromise(err);
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
83
|
}
|
|
86
84
|
_SpoFolderRemoveCommand_instances = new WeakSet(), _SpoFolderRemoveCommand_initTelemetry = function _SpoFolderRemoveCommand_initTelemetry() {
|
|
87
85
|
this.telemetry.push((args) => {
|
|
@@ -62,8 +62,7 @@ class SpoTenantAppCatalogAddCommand extends SpoCommand_1.default {
|
|
|
62
62
|
});
|
|
63
63
|
}
|
|
64
64
|
ensureNoExistingSite(url, force, logger) {
|
|
65
|
-
|
|
66
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
65
|
+
return new Promise((resolve, reject) => {
|
|
67
66
|
if (this.verbose) {
|
|
68
67
|
logger.logToStderr(`Checking if site ${url} exists...`);
|
|
69
68
|
}
|
|
@@ -75,13 +74,14 @@ class SpoTenantAppCatalogAddCommand extends SpoCommand_1.default {
|
|
|
75
74
|
_: []
|
|
76
75
|
}
|
|
77
76
|
};
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
Cli_1.Cli
|
|
78
|
+
.executeCommandWithOutput(spoSiteGetCommand, siteGetOptions)
|
|
79
|
+
.then(() => {
|
|
80
80
|
if (this.verbose) {
|
|
81
81
|
logger.logToStderr(`Found site ${url}`);
|
|
82
82
|
}
|
|
83
83
|
if (!force) {
|
|
84
|
-
|
|
84
|
+
return reject(new Command_1.CommandError(`Another site exists at ${url}`));
|
|
85
85
|
}
|
|
86
86
|
if (this.verbose) {
|
|
87
87
|
logger.logToStderr(`Deleting site ${url}...`);
|
|
@@ -90,21 +90,24 @@ class SpoTenantAppCatalogAddCommand extends SpoCommand_1.default {
|
|
|
90
90
|
url: url,
|
|
91
91
|
skipRecycleBin: true,
|
|
92
92
|
wait: true,
|
|
93
|
-
|
|
93
|
+
force: true,
|
|
94
94
|
verbose: this.verbose,
|
|
95
95
|
debug: this.debug
|
|
96
96
|
};
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
97
|
+
Cli_1.Cli
|
|
98
|
+
.executeCommand(spoSiteRemoveCommand, { options: Object.assign(Object.assign({}, siteRemoveOptions), { _: [] }) })
|
|
99
|
+
.then(() => resolve(), (err) => reject(err));
|
|
100
|
+
}, (err) => {
|
|
101
|
+
if (err.error.message !== 'File Not Found.' && err.error.message !== '404 FILE NOT FOUND') {
|
|
102
|
+
// some other error occurred
|
|
103
|
+
return reject(err.error);
|
|
102
104
|
}
|
|
103
105
|
if (this.verbose) {
|
|
104
106
|
logger.logToStderr(`No site found at ${url}`);
|
|
105
107
|
}
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
+
// site not found. continue
|
|
109
|
+
resolve();
|
|
110
|
+
});
|
|
108
111
|
});
|
|
109
112
|
}
|
|
110
113
|
createAppCatalog(options, logger) {
|
|
@@ -23,8 +23,6 @@ const validation_1 = require("../../../../utils/validation");
|
|
|
23
23
|
const SpoCommand_1 = require("../../../base/SpoCommand");
|
|
24
24
|
const commands_1 = require("../../commands");
|
|
25
25
|
const os = require("os");
|
|
26
|
-
const Cli_1 = require("../../../../cli/Cli");
|
|
27
|
-
const spoListItemListCommand = require("../listitem/listitem-list");
|
|
28
26
|
const request_1 = require("../../../../request");
|
|
29
27
|
class SpoTenantApplicationCustomizerSetCommand extends SpoCommand_1.default {
|
|
30
28
|
get name() {
|
|
@@ -48,20 +46,6 @@ class SpoTenantApplicationCustomizerSetCommand extends SpoCommand_1.default {
|
|
|
48
46
|
if (!appCatalogUrl) {
|
|
49
47
|
throw 'No app catalog URL found';
|
|
50
48
|
}
|
|
51
|
-
if (args.options.newClientSideComponentId !== undefined) {
|
|
52
|
-
const componentManifest = yield this.getComponentManifest(appCatalogUrl, args.options.newClientSideComponentId, logger);
|
|
53
|
-
const clientComponentManifest = JSON.parse(componentManifest.ClientComponentManifest);
|
|
54
|
-
if (clientComponentManifest.extensionType !== "ApplicationCustomizer") {
|
|
55
|
-
throw `The extension type of this component is not of type 'ApplicationCustomizer' but of type '${clientComponentManifest.extensionType}'`;
|
|
56
|
-
}
|
|
57
|
-
const solution = yield this.getSolutionFromAppCatalog(appCatalogUrl, componentManifest.SolutionId, logger);
|
|
58
|
-
if (!solution.ContainsTenantWideExtension) {
|
|
59
|
-
throw `The solution does not contain an extension that can be deployed to all sites. Make sure that you've entered the correct component Id.`;
|
|
60
|
-
}
|
|
61
|
-
else if (!solution.SkipFeatureDeployment) {
|
|
62
|
-
throw 'The solution has not been deployed to all sites. Make sure to deploy this solution to all sites.';
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
49
|
const listServerRelativeUrl = urlUtil_1.urlUtil.getServerRelativePath(appCatalogUrl, '/lists/TenantWideExtensions');
|
|
66
50
|
const listItemId = yield this.getListItemId(appCatalogUrl, args.options, listServerRelativeUrl, logger);
|
|
67
51
|
yield this.updateTenantWideExtension(appCatalogUrl, args.options, listServerRelativeUrl, listItemId, logger);
|
|
@@ -88,59 +72,9 @@ class SpoTenantApplicationCustomizerSetCommand extends SpoCommand_1.default {
|
|
|
88
72
|
return listItemInstances[0].Id;
|
|
89
73
|
});
|
|
90
74
|
}
|
|
91
|
-
getComponentManifest(appCatalogUrl, clientSideComponentId, logger) {
|
|
92
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
93
|
-
if (this.verbose) {
|
|
94
|
-
logger.logToStderr('Retrieving component manifest item from the ComponentManifests list on the app catalog site so that we get the solution id');
|
|
95
|
-
}
|
|
96
|
-
const camlQuery = `<View><ViewFields><FieldRef Name='ClientComponentId'></FieldRef><FieldRef Name='SolutionId'></FieldRef><FieldRef Name='ClientComponentManifest'></FieldRef></ViewFields><Query><Where><Eq><FieldRef Name='ClientComponentId' /><Value Type='Guid'>${clientSideComponentId}</Value></Eq></Where></Query></View>`;
|
|
97
|
-
const commandOptions = {
|
|
98
|
-
webUrl: appCatalogUrl,
|
|
99
|
-
listUrl: `${urlUtil_1.urlUtil.getServerRelativeSiteUrl(appCatalogUrl)}/Lists/ComponentManifests`,
|
|
100
|
-
camlQuery: camlQuery,
|
|
101
|
-
verbose: this.verbose,
|
|
102
|
-
debug: this.debug,
|
|
103
|
-
output: 'json'
|
|
104
|
-
};
|
|
105
|
-
const output = yield Cli_1.Cli.executeCommandWithOutput(spoListItemListCommand, { options: Object.assign(Object.assign({}, commandOptions), { _: [] }) });
|
|
106
|
-
if (this.verbose) {
|
|
107
|
-
logger.logToStderr(output.stderr);
|
|
108
|
-
}
|
|
109
|
-
const outputParsed = JSON.parse(output.stdout);
|
|
110
|
-
if (outputParsed.length === 0) {
|
|
111
|
-
throw 'No component found with the specified clientSideComponentId found in the component manifest list. Make sure that the application is added to the application catalog';
|
|
112
|
-
}
|
|
113
|
-
return outputParsed[0];
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
getSolutionFromAppCatalog(appCatalogUrl, solutionId, logger) {
|
|
117
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
118
|
-
if (this.verbose) {
|
|
119
|
-
logger.logToStderr(`Retrieving solution with id ${solutionId} from the application catalog`);
|
|
120
|
-
}
|
|
121
|
-
const camlQuery = `<View><ViewFields><FieldRef Name='SkipFeatureDeployment'></FieldRef><FieldRef Name='ContainsTenantWideExtension'></FieldRef></ViewFields><Query><Where><Eq><FieldRef Name='AppProductID' /><Value Type='Guid'>${solutionId}</Value></Eq></Where></Query></View>`;
|
|
122
|
-
const commandOptions = {
|
|
123
|
-
webUrl: appCatalogUrl,
|
|
124
|
-
listUrl: `${urlUtil_1.urlUtil.getServerRelativeSiteUrl(appCatalogUrl)}/AppCatalog`,
|
|
125
|
-
camlQuery: camlQuery,
|
|
126
|
-
verbose: this.verbose,
|
|
127
|
-
debug: this.debug,
|
|
128
|
-
output: 'json'
|
|
129
|
-
};
|
|
130
|
-
const output = yield Cli_1.Cli.executeCommandWithOutput(spoListItemListCommand, { options: Object.assign(Object.assign({}, commandOptions), { _: [] }) });
|
|
131
|
-
if (this.verbose) {
|
|
132
|
-
logger.logToStderr(output.stderr);
|
|
133
|
-
}
|
|
134
|
-
const outputParsed = JSON.parse(output.stdout);
|
|
135
|
-
if (outputParsed.length === 0) {
|
|
136
|
-
throw `No component found with the solution id ${solutionId}. Make sure that the solution is available in the app catalog`;
|
|
137
|
-
}
|
|
138
|
-
return outputParsed[0];
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
75
|
updateTenantWideExtension(appCatalogUrl, options, listServerRelativeUrl, itemId, logger) {
|
|
142
76
|
return __awaiter(this, void 0, void 0, function* () {
|
|
143
|
-
const { title, id, clientSideComponentId, newTitle,
|
|
77
|
+
const { title, id, clientSideComponentId, newTitle, clientSideComponentProperties, webTemplate } = options;
|
|
144
78
|
if (this.verbose) {
|
|
145
79
|
logger.logToStderr(`Updating tenant-wide application customizer: "${title || id || clientSideComponentId}"...`);
|
|
146
80
|
}
|
|
@@ -151,12 +85,6 @@ class SpoTenantApplicationCustomizerSetCommand extends SpoCommand_1.default {
|
|
|
151
85
|
FieldValue: newTitle
|
|
152
86
|
});
|
|
153
87
|
}
|
|
154
|
-
if (newClientSideComponentId !== undefined) {
|
|
155
|
-
formValues.push({
|
|
156
|
-
FieldName: 'TenantWideExtensionComponentId',
|
|
157
|
-
FieldValue: newClientSideComponentId
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
88
|
if (clientSideComponentProperties !== undefined) {
|
|
161
89
|
formValues.push({
|
|
162
90
|
FieldName: 'TenantWideExtensionComponentProperties',
|
|
@@ -190,7 +118,6 @@ _SpoTenantApplicationCustomizerSetCommand_instances = new WeakSet(), _SpoTenantA
|
|
|
190
118
|
id: typeof args.options.id !== 'undefined',
|
|
191
119
|
clientSideComponentId: typeof args.options.clientSideComponentId !== 'undefined',
|
|
192
120
|
newTitle: typeof args.options.newTitle !== 'undefined',
|
|
193
|
-
newClientSideComponentId: typeof args.options.newClientSideComponentId !== 'undefined',
|
|
194
121
|
clientSideComponentProperties: typeof args.options.clientSideComponentProperties !== 'undefined',
|
|
195
122
|
webTemplate: typeof args.options.webTemplate !== 'undefined'
|
|
196
123
|
});
|
|
@@ -204,8 +131,6 @@ _SpoTenantApplicationCustomizerSetCommand_instances = new WeakSet(), _SpoTenantA
|
|
|
204
131
|
option: '-c, --clientSideComponentId [clientSideComponentId]'
|
|
205
132
|
}, {
|
|
206
133
|
option: '--newTitle [newTitle]'
|
|
207
|
-
}, {
|
|
208
|
-
option: '--newClientSideComponentId [newClientSideComponentId]'
|
|
209
134
|
}, {
|
|
210
135
|
option: '-p, --clientSideComponentProperties [clientSideComponentProperties]'
|
|
211
136
|
}, {
|
|
@@ -219,10 +144,7 @@ _SpoTenantApplicationCustomizerSetCommand_instances = new WeakSet(), _SpoTenantA
|
|
|
219
144
|
if (args.options.clientSideComponentId && !validation_1.validation.isValidGuid(args.options.clientSideComponentId)) {
|
|
220
145
|
return `${args.options.clientSideComponentId} is not a valid GUID`;
|
|
221
146
|
}
|
|
222
|
-
if (args.options.
|
|
223
|
-
return `${args.options.newClientSideComponentId} is not a valid GUID`;
|
|
224
|
-
}
|
|
225
|
-
if (!args.options.newTitle && !args.options.newClientSideComponentId && !args.options.clientSideComponentProperties && !args.options.webTemplate) {
|
|
147
|
+
if (!args.options.newTitle && !args.options.clientSideComponentProperties && !args.options.webTemplate) {
|
|
226
148
|
return `Please specify an option to be updated`;
|
|
227
149
|
}
|
|
228
150
|
return true;
|
|
@@ -39,8 +39,54 @@ class SpoTenantRecycleBinItemRemoveCommand extends SpoCommand_1.default {
|
|
|
39
39
|
}
|
|
40
40
|
commandAction(logger, args) {
|
|
41
41
|
return __awaiter(this, void 0, void 0, function* () {
|
|
42
|
+
const removeDeletedSite = () => __awaiter(this, void 0, void 0, function* () {
|
|
43
|
+
try {
|
|
44
|
+
this.spoAdminUrl = yield spo_1.spo.getSpoAdminUrl(logger, this.debug);
|
|
45
|
+
const res = yield spo_1.spo.ensureFormDigest(this.spoAdminUrl, logger, this.context, this.debug);
|
|
46
|
+
if (this.verbose) {
|
|
47
|
+
logger.logToStderr(`Removing deleted site collection ${args.options.siteUrl}...`);
|
|
48
|
+
}
|
|
49
|
+
const requestOptions = {
|
|
50
|
+
url: `${this.spoAdminUrl}/_vti_bin/client.svc/ProcessQuery`,
|
|
51
|
+
headers: {
|
|
52
|
+
'X-RequestDigest': res.FormDigestValue
|
|
53
|
+
},
|
|
54
|
+
data: `<Request AddExpandoFieldTypeSuffix="true" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName="${config_1.default.applicationName}" xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009"><Actions><ObjectPath Id="16" ObjectPathId="15" /><Query Id="17" ObjectPathId="15"><Query SelectAllProperties="false"><Properties><Property Name="PollingInterval" ScalarProperty="true" /><Property Name="IsComplete" ScalarProperty="true" /></Properties></Query></Query></Actions><ObjectPaths><Method Id="15" ParentId="1" Name="RemoveDeletedSite"><Parameters><Parameter Type="String">${formatting_1.formatting.escapeXml(args.options.siteUrl)}</Parameter></Parameters></Method><Constructor Id="1" TypeId="{268004ae-ef6b-4e9b-8425-127220d84719}" /></ObjectPaths></Request>`
|
|
55
|
+
};
|
|
56
|
+
const processQuery = yield request_1.default.post(requestOptions);
|
|
57
|
+
const json = JSON.parse(processQuery);
|
|
58
|
+
const response = json[0];
|
|
59
|
+
if (response.ErrorInfo) {
|
|
60
|
+
throw response.ErrorInfo.ErrorMessage;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
const operation = json[json.length - 1];
|
|
64
|
+
const isComplete = operation.IsComplete;
|
|
65
|
+
if (!args.options.wait || isComplete) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
yield new Promise((resolve, reject) => {
|
|
69
|
+
setTimeout(() => {
|
|
70
|
+
spo_1.spo.waitUntilFinished({
|
|
71
|
+
operationId: JSON.stringify(operation._ObjectIdentity_),
|
|
72
|
+
siteUrl: this.spoAdminUrl,
|
|
73
|
+
resolve,
|
|
74
|
+
reject,
|
|
75
|
+
logger,
|
|
76
|
+
currentContext: this.context,
|
|
77
|
+
debug: this.debug,
|
|
78
|
+
verbose: this.verbose
|
|
79
|
+
});
|
|
80
|
+
}, operation.PollingInterval);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
this.handleRejectedODataJsonPromise(err);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
42
88
|
if (args.options.force) {
|
|
43
|
-
yield
|
|
89
|
+
yield removeDeletedSite();
|
|
44
90
|
}
|
|
45
91
|
else {
|
|
46
92
|
const result = yield Cli_1.Cli.prompt({
|
|
@@ -50,57 +96,11 @@ class SpoTenantRecycleBinItemRemoveCommand extends SpoCommand_1.default {
|
|
|
50
96
|
message: `Are you sure you want to remove the deleted site collection ${args.options.siteUrl} from tenant recycle bin?`
|
|
51
97
|
});
|
|
52
98
|
if (result.continue) {
|
|
53
|
-
yield
|
|
99
|
+
yield removeDeletedSite();
|
|
54
100
|
}
|
|
55
101
|
}
|
|
56
102
|
});
|
|
57
103
|
}
|
|
58
|
-
removeDeletedSite(logger, args) {
|
|
59
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
60
|
-
try {
|
|
61
|
-
const spoAdminUrl = yield spo_1.spo.getSpoAdminUrl(logger, this.debug);
|
|
62
|
-
const res = yield spo_1.spo.ensureFormDigest(spoAdminUrl, logger, this.context, this.debug);
|
|
63
|
-
if (this.verbose) {
|
|
64
|
-
logger.logToStderr(`Removing deleted site collection ${args.options.siteUrl}...`);
|
|
65
|
-
}
|
|
66
|
-
const requestOptions = {
|
|
67
|
-
url: `${spoAdminUrl}/_vti_bin/client.svc/ProcessQuery`,
|
|
68
|
-
headers: {
|
|
69
|
-
'X-RequestDigest': res.FormDigestValue
|
|
70
|
-
},
|
|
71
|
-
data: `<Request AddExpandoFieldTypeSuffix="true" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName="${config_1.default.applicationName}" xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009"><Actions><ObjectPath Id="16" ObjectPathId="15" /><Query Id="17" ObjectPathId="15"><Query SelectAllProperties="false"><Properties><Property Name="PollingInterval" ScalarProperty="true" /><Property Name="IsComplete" ScalarProperty="true" /></Properties></Query></Query></Actions><ObjectPaths><Method Id="15" ParentId="1" Name="RemoveDeletedSite"><Parameters><Parameter Type="String">${formatting_1.formatting.escapeXml(args.options.siteUrl)}</Parameter></Parameters></Method><Constructor Id="1" TypeId="{268004ae-ef6b-4e9b-8425-127220d84719}" /></ObjectPaths></Request>`
|
|
72
|
-
};
|
|
73
|
-
const processQuery = yield request_1.default.post(requestOptions);
|
|
74
|
-
const json = JSON.parse(processQuery);
|
|
75
|
-
const response = json[0];
|
|
76
|
-
if (response.ErrorInfo) {
|
|
77
|
-
throw response.ErrorInfo.ErrorMessage;
|
|
78
|
-
}
|
|
79
|
-
const operation = json[json.length - 1];
|
|
80
|
-
const isComplete = operation.IsComplete;
|
|
81
|
-
if (!args.options.wait || isComplete) {
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
yield new Promise((resolve, reject) => {
|
|
85
|
-
setTimeout(() => {
|
|
86
|
-
spo_1.spo.waitUntilFinished({
|
|
87
|
-
operationId: JSON.stringify(operation._ObjectIdentity_),
|
|
88
|
-
siteUrl: spoAdminUrl,
|
|
89
|
-
resolve,
|
|
90
|
-
reject,
|
|
91
|
-
logger,
|
|
92
|
-
currentContext: this.context,
|
|
93
|
-
debug: this.debug,
|
|
94
|
-
verbose: this.verbose
|
|
95
|
-
});
|
|
96
|
-
}, operation.PollingInterval);
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
catch (err) {
|
|
100
|
-
this.handleRejectedODataJsonPromise(err);
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
104
|
}
|
|
105
105
|
_SpoTenantRecycleBinItemRemoveCommand_instances = new WeakSet(), _SpoTenantRecycleBinItemRemoveCommand_initTelemetry = function _SpoTenantRecycleBinItemRemoveCommand_initTelemetry() {
|
|
106
106
|
this.telemetry.push((args) => {
|
|
@@ -79,7 +79,7 @@ class TeamsChatGetCommand extends GraphCommand_1.default {
|
|
|
79
79
|
const currentUserEmail = accessToken_1.accessToken.getUserNameFromAccessToken(Auth_1.default.service.accessTokens[this.resource].accessToken).toLowerCase();
|
|
80
80
|
const existingChats = yield chatUtil_1.chatUtil.findExistingChatsByParticipants([currentUserEmail, ...participants]);
|
|
81
81
|
if (!existingChats || existingChats.length === 0) {
|
|
82
|
-
throw 'No chat conversation was found with these participants.';
|
|
82
|
+
throw new Error('No chat conversation was found with these participants.');
|
|
83
83
|
}
|
|
84
84
|
if (existingChats.length === 1) {
|
|
85
85
|
return existingChats[0].id;
|
|
@@ -87,14 +87,14 @@ class TeamsChatGetCommand extends GraphCommand_1.default {
|
|
|
87
87
|
const disambiguationText = existingChats.map(c => {
|
|
88
88
|
return `- ${c.id}${c.topic && ' - '}${c.topic} - ${c.createdDateTime && new Date(c.createdDateTime).toLocaleString()}`;
|
|
89
89
|
}).join(os.EOL);
|
|
90
|
-
throw `Multiple chat conversations with these participants found. Please disambiguate:${os.EOL}${disambiguationText}
|
|
90
|
+
throw new Error(`Multiple chat conversations with these participants found. Please disambiguate:${os.EOL}${disambiguationText}`);
|
|
91
91
|
});
|
|
92
92
|
}
|
|
93
93
|
getChatIdByName(name) {
|
|
94
94
|
return __awaiter(this, void 0, void 0, function* () {
|
|
95
95
|
const existingChats = yield chatUtil_1.chatUtil.findExistingGroupChatsByName(name);
|
|
96
96
|
if (!existingChats || existingChats.length === 0) {
|
|
97
|
-
throw 'No chat conversation was found with this name.';
|
|
97
|
+
throw new Error('No chat conversation was found with this name.');
|
|
98
98
|
}
|
|
99
99
|
if (existingChats.length === 1) {
|
|
100
100
|
return existingChats[0].id;
|
|
@@ -103,7 +103,7 @@ class TeamsChatGetCommand extends GraphCommand_1.default {
|
|
|
103
103
|
const memberstring = c.members.map(m => m.email).join(', ');
|
|
104
104
|
return `- ${c.id} - ${c.createdDateTime && new Date(c.createdDateTime).toLocaleString()} - ${memberstring}`;
|
|
105
105
|
}).join(os.EOL);
|
|
106
|
-
throw `Multiple chat conversations with this name found. Please disambiguate:${os.EOL}${disambiguationText}
|
|
106
|
+
throw new Error(`Multiple chat conversations with this name found. Please disambiguate:${os.EOL}${disambiguationText}`);
|
|
107
107
|
});
|
|
108
108
|
}
|
|
109
109
|
}
|
|
@@ -74,14 +74,14 @@ class TeamsChatMessageSendCommand extends GraphCommand_1.default {
|
|
|
74
74
|
const disambiguationText = existingChats.map(c => {
|
|
75
75
|
return `- ${c.id}${c.topic && ' - '}${c.topic} - ${c.createdDateTime && new Date(c.createdDateTime).toLocaleString()}`;
|
|
76
76
|
}).join(os.EOL);
|
|
77
|
-
throw `Multiple chat conversations with this name found. Please disambiguate:${os.EOL}${disambiguationText}
|
|
77
|
+
throw new Error(`Multiple chat conversations with this name found. Please disambiguate:${os.EOL}${disambiguationText}`);
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
80
|
getChatIdByName(chatName) {
|
|
81
81
|
return __awaiter(this, void 0, void 0, function* () {
|
|
82
82
|
const existingChats = yield chatUtil_1.chatUtil.findExistingGroupChatsByName(chatName);
|
|
83
83
|
if (!existingChats || existingChats.length === 0) {
|
|
84
|
-
throw 'No chat conversation was found with this name.';
|
|
84
|
+
throw new Error('No chat conversation was found with this name.');
|
|
85
85
|
}
|
|
86
86
|
if (existingChats.length === 1) {
|
|
87
87
|
return existingChats[0].id;
|
|
@@ -90,7 +90,7 @@ class TeamsChatMessageSendCommand extends GraphCommand_1.default {
|
|
|
90
90
|
const memberstring = c.members.map(m => m.email).join(', ');
|
|
91
91
|
return `- ${c.id} - ${c.createdDateTime && new Date(c.createdDateTime).toLocaleString()} - ${memberstring}`;
|
|
92
92
|
}).join(os.EOL);
|
|
93
|
-
throw `Multiple chat conversations with this name found. Please disambiguate:${os.EOL}${disambiguationText}
|
|
93
|
+
throw new Error(`Multiple chat conversations with this name found. Please disambiguate:${os.EOL}${disambiguationText}`);
|
|
94
94
|
});
|
|
95
95
|
}
|
|
96
96
|
// This Microsoft Graph API request throws an intermittent 404 exception, saying that it cannot find the principal.
|
|
@@ -146,7 +146,7 @@ class TeamsChatMessageSendCommand extends GraphCommand_1.default {
|
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
148
|
};
|
|
149
|
-
|
|
149
|
+
yield request_1.default.post(requestOptions);
|
|
150
150
|
});
|
|
151
151
|
}
|
|
152
152
|
}
|
|
@@ -25,9 +25,6 @@ m365 spo tenant applicationcustomizer set [options]
|
|
|
25
25
|
`--newTitle [newTitle]`
|
|
26
26
|
: The updated title of the Application Customizer.
|
|
27
27
|
|
|
28
|
-
`--newClientSideComponentId [newClientSideComponentId]`
|
|
29
|
-
: The new Client Side Component Id (GUID) of the Application Customizer.
|
|
30
|
-
|
|
31
28
|
`-p, --clientSideComponentProperties [clientSideComponentProperties]`
|
|
32
29
|
: The Client Side Component properties of the Application Customizer.
|
|
33
30
|
|
|
@@ -58,13 +55,7 @@ When using the `--clientSideComponentProperties` option it's possible to enter a
|
|
|
58
55
|
Updates the title of an Application Customizer that is deployed as a tenant-wide extension by its id
|
|
59
56
|
|
|
60
57
|
```sh
|
|
61
|
-
m365 spo tenant applicationcustomizer set --id 3 --newTitle
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Updates the Client Side Component Id of an Application Customizer that is deployed as a tenant-wide extension by its id
|
|
65
|
-
|
|
66
|
-
```sh
|
|
67
|
-
m365 spo tenant applicationcustomizer set --id 3 --newClientSideComponentId "b44a5182-9877-4029-baec-0181c70dacbc"
|
|
58
|
+
m365 spo tenant applicationcustomizer set --id 3 --newTitle "Some customizer"
|
|
68
59
|
```
|
|
69
60
|
|
|
70
61
|
Updates the properties of an Application Customizer that is deployed as a tenant-wide extension by its id
|
|
@@ -76,13 +67,13 @@ m365 spo tenant applicationcustomizer set --id 3 --clientSideComponentProperties
|
|
|
76
67
|
Updates the title of an Application Customizer that is deployed as a tenant-wide extension by its title
|
|
77
68
|
|
|
78
69
|
```sh
|
|
79
|
-
m365 spo tenant applicationcustomizer set --title "Some customizer" --newTitle
|
|
70
|
+
m365 spo tenant applicationcustomizer set --title "Some customizer" --newTitle "Updated customizer"
|
|
80
71
|
```
|
|
81
72
|
|
|
82
73
|
Updates the title of an Application Customizer that is deployed as a tenant-wide extension by its clientSideComponentId
|
|
83
74
|
|
|
84
75
|
```sh
|
|
85
|
-
m365 spo tenant applicationcustomizer set --clientSideComponentId "7f8fd1f2-9d26-4a4a-a607-bf4622d7ec11" --newTitle
|
|
76
|
+
m365 spo tenant applicationcustomizer set --clientSideComponentId "7f8fd1f2-9d26-4a4a-a607-bf4622d7ec11" --newTitle "Some customizer"
|
|
86
77
|
```
|
|
87
78
|
|
|
88
79
|
## Response
|
package/package.json
CHANGED