@microsoft/m365-spec-parser 0.2.4-alpha.ad0d7aa1a.0 → 0.2.4-alpha.af47bc3a8.0
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/index.esm2017.js +21 -7
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +107 -61
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +21 -7
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +110 -62
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/src/constants.d.ts +1 -3
- package/dist/src/interfaces.d.ts +9 -0
- package/dist/src/manifestUpdater.d.ts +3 -3
- package/dist/src/specParser.d.ts +2 -0
- package/dist/src/utils.d.ts +3 -1
- package/package.json +4 -4
package/dist/index.esm2017.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import fs from 'fs-extra';
|
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import { ManifestUtil } from '@microsoft/teams-manifest';
|
|
7
7
|
import { createHash } from 'crypto';
|
|
8
|
+
import { $RefParser } from '@apidevtools/json-schema-ref-parser';
|
|
8
9
|
|
|
9
10
|
// Copyright (c) Microsoft Corporation.
|
|
10
11
|
/**
|
|
@@ -114,12 +115,7 @@ ConstantString.AdaptiveCardType = "AdaptiveCard";
|
|
|
114
115
|
ConstantString.TextBlockType = "TextBlock";
|
|
115
116
|
ConstantString.ImageType = "Image";
|
|
116
117
|
ConstantString.ContainerType = "Container";
|
|
117
|
-
ConstantString.RegistrationIdPostfix =
|
|
118
|
-
apiKey: "REGISTRATION_ID",
|
|
119
|
-
oauth2: "CONFIGURATION_ID",
|
|
120
|
-
http: "REGISTRATION_ID",
|
|
121
|
-
openIdConnect: "REGISTRATION_ID",
|
|
122
|
-
};
|
|
118
|
+
ConstantString.RegistrationIdPostfix = "REGISTRATION_ID";
|
|
123
119
|
ConstantString.ResponseCodeFor20X = [
|
|
124
120
|
"200",
|
|
125
121
|
"201",
|
|
@@ -131,6 +127,7 @@ ConstantString.ResponseCodeFor20X = [
|
|
|
131
127
|
"207",
|
|
132
128
|
"208",
|
|
133
129
|
"226",
|
|
130
|
+
"2XX",
|
|
134
131
|
"default",
|
|
135
132
|
];
|
|
136
133
|
ConstantString.AllOperationMethods = [
|
|
@@ -208,6 +205,9 @@ class Utils {
|
|
|
208
205
|
static isAPIKeyAuth(authScheme) {
|
|
209
206
|
return authScheme.type === "apiKey";
|
|
210
207
|
}
|
|
208
|
+
static isAPIKeyAuthButNotInCookie(authScheme) {
|
|
209
|
+
return authScheme.type === "apiKey" && authScheme.in !== "cookie";
|
|
210
|
+
}
|
|
211
211
|
static isOAuthWithAuthCodeFlow(authScheme) {
|
|
212
212
|
return !!(authScheme.type === "oauth2" &&
|
|
213
213
|
authScheme.flows &&
|
|
@@ -223,7 +223,8 @@ class Utils {
|
|
|
223
223
|
for (const auths of authSchemeArray) {
|
|
224
224
|
if (auths.length === 1) {
|
|
225
225
|
if (Utils.isOAuthWithAuthCodeFlow(auths[0].authScheme) ||
|
|
226
|
-
Utils.isBearerTokenAuth(auths[0].authScheme)
|
|
226
|
+
Utils.isBearerTokenAuth(auths[0].authScheme) ||
|
|
227
|
+
Utils.isAPIKeyAuthButNotInCookie(auths[0].authScheme)) {
|
|
227
228
|
return false;
|
|
228
229
|
}
|
|
229
230
|
}
|
|
@@ -254,6 +255,20 @@ class Utils {
|
|
|
254
255
|
result.sort((a, b) => a[0].name.localeCompare(b[0].name));
|
|
255
256
|
return result;
|
|
256
257
|
}
|
|
258
|
+
static getAuthMap(spec) {
|
|
259
|
+
const authMap = {};
|
|
260
|
+
for (const url in spec.paths) {
|
|
261
|
+
for (const method in spec.paths[url]) {
|
|
262
|
+
const operation = spec.paths[url][method];
|
|
263
|
+
const authArray = Utils.getAuthArray(operation.security, spec);
|
|
264
|
+
if (authArray && authArray.length > 0) {
|
|
265
|
+
const currentAuth = authArray[0][0];
|
|
266
|
+
authMap[operation.operationId] = currentAuth;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return authMap;
|
|
271
|
+
}
|
|
257
272
|
static getAuthInfo(spec) {
|
|
258
273
|
let authInfo = undefined;
|
|
259
274
|
for (const url in spec.paths) {
|
|
@@ -1678,7 +1693,7 @@ function inferProperties(card) {
|
|
|
1678
1693
|
|
|
1679
1694
|
// Copyright (c) Microsoft Corporation.
|
|
1680
1695
|
class ManifestUpdater {
|
|
1681
|
-
static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options,
|
|
1696
|
+
static async updateManifestWithAiPlugin(manifestPath, outputSpecPath, apiPluginFilePath, spec, options, authMap, existingPluginManifestInfo) {
|
|
1682
1697
|
const manifest = await fs.readJSON(manifestPath);
|
|
1683
1698
|
const apiPluginRelativePath = ManifestUpdater.getRelativePath(manifestPath, apiPluginFilePath);
|
|
1684
1699
|
const useCopilotExtensionsInSchema = await ManifestUtil.useCopilotExtensionsInSchema(manifest);
|
|
@@ -1708,7 +1723,7 @@ class ManifestUpdater {
|
|
|
1708
1723
|
}
|
|
1709
1724
|
const appName = this.removeEnvs(manifest.name.short);
|
|
1710
1725
|
const specRelativePath = ManifestUpdater.getRelativePath(manifestPath, outputSpecPath);
|
|
1711
|
-
const [apiPlugin, warnings] = await ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName,
|
|
1726
|
+
const [apiPlugin, warnings] = await ManifestUpdater.generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authMap, options, existingPluginManifestInfo);
|
|
1712
1727
|
return [manifest, apiPlugin, warnings];
|
|
1713
1728
|
}
|
|
1714
1729
|
static updateManifestDescription(manifest, spec) {
|
|
@@ -1730,28 +1745,13 @@ class ManifestUpdater {
|
|
|
1730
1745
|
throw new SpecParserError(Utils.format(ConstantString.UnsupportedSchema, method, pathUrl, JSON.stringify(schema)), ErrorType.UpdateManifestFailed);
|
|
1731
1746
|
}
|
|
1732
1747
|
}
|
|
1733
|
-
static async generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName,
|
|
1748
|
+
static async generatePluginManifestSchema(spec, specRelativePath, apiPluginFilePath, appName, authMap, options, existingPluginManifestInfo) {
|
|
1734
1749
|
var _a, _b, _c, _d;
|
|
1735
1750
|
const warnings = [];
|
|
1736
1751
|
const functions = [];
|
|
1737
|
-
const
|
|
1752
|
+
const functionNamesMap = {};
|
|
1738
1753
|
const conversationStarters = [];
|
|
1739
1754
|
const paths = spec.paths;
|
|
1740
|
-
const pluginAuthObj = {
|
|
1741
|
-
type: "None",
|
|
1742
|
-
};
|
|
1743
|
-
if (authInfo) {
|
|
1744
|
-
if (Utils.isOAuthWithAuthCodeFlow(authInfo.authScheme)) {
|
|
1745
|
-
pluginAuthObj.type = "OAuthPluginVault";
|
|
1746
|
-
}
|
|
1747
|
-
else if (Utils.isBearerTokenAuth(authInfo.authScheme)) {
|
|
1748
|
-
pluginAuthObj.type = "ApiKeyPluginVault";
|
|
1749
|
-
}
|
|
1750
|
-
if (pluginAuthObj.type !== "None") {
|
|
1751
|
-
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix[authInfo.authScheme.type]}`);
|
|
1752
|
-
pluginAuthObj.reference_id = `\${{${safeRegistrationIdName}}}`;
|
|
1753
|
-
}
|
|
1754
|
-
}
|
|
1755
1755
|
for (const pathUrl in paths) {
|
|
1756
1756
|
const pathItem = paths[pathUrl];
|
|
1757
1757
|
if (pathItem) {
|
|
@@ -1834,7 +1834,29 @@ class ManifestUpdater {
|
|
|
1834
1834
|
}
|
|
1835
1835
|
}
|
|
1836
1836
|
functions.push(funcObj);
|
|
1837
|
-
|
|
1837
|
+
const authInfo = authMap[operationId];
|
|
1838
|
+
let key = "None";
|
|
1839
|
+
let authName = "None";
|
|
1840
|
+
if (authInfo) {
|
|
1841
|
+
if (Utils.isOAuthWithAuthCodeFlow(authInfo.authScheme)) {
|
|
1842
|
+
key = "OAuthPluginVault";
|
|
1843
|
+
authName = authInfo.name;
|
|
1844
|
+
}
|
|
1845
|
+
else if (Utils.isBearerTokenAuth(authInfo.authScheme) ||
|
|
1846
|
+
Utils.isAPIKeyAuthButNotInCookie(authInfo.authScheme)) {
|
|
1847
|
+
key = "ApiKeyPluginVault";
|
|
1848
|
+
authName = authInfo.name;
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
if (functionNamesMap[key]) {
|
|
1852
|
+
functionNamesMap[key].functionNames.push(safeFunctionName);
|
|
1853
|
+
}
|
|
1854
|
+
else {
|
|
1855
|
+
functionNamesMap[key] = {
|
|
1856
|
+
functionNames: [safeFunctionName],
|
|
1857
|
+
authName: authName,
|
|
1858
|
+
};
|
|
1859
|
+
}
|
|
1838
1860
|
const conversationStarterStr = (summary !== null && summary !== void 0 ? summary : description).slice(0, ConstantString.ConversationStarterMaxLens);
|
|
1839
1861
|
if (conversationStarterStr) {
|
|
1840
1862
|
conversationStarters.push(conversationStarterStr);
|
|
@@ -1844,6 +1866,12 @@ class ManifestUpdater {
|
|
|
1844
1866
|
}
|
|
1845
1867
|
}
|
|
1846
1868
|
}
|
|
1869
|
+
if (Object.keys(functionNamesMap).length === 0) {
|
|
1870
|
+
functionNamesMap["None"] = {
|
|
1871
|
+
functionNames: [],
|
|
1872
|
+
authName: "None",
|
|
1873
|
+
};
|
|
1874
|
+
}
|
|
1847
1875
|
let apiPlugin;
|
|
1848
1876
|
if (await fs.pathExists(apiPluginFilePath)) {
|
|
1849
1877
|
apiPlugin = await fs.readJSON(apiPluginFilePath);
|
|
@@ -1879,24 +1907,35 @@ class ManifestUpdater {
|
|
|
1879
1907
|
const relativePath = ManifestUpdater.getRelativePath(existingPluginManifestInfo.manifestPath, existingPluginManifestInfo.specPath);
|
|
1880
1908
|
apiPlugin.runtimes = apiPlugin.runtimes.filter((runtime) => runtime.spec.url !== relativePath);
|
|
1881
1909
|
}
|
|
1882
|
-
const
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1910
|
+
for (const authType in functionNamesMap) {
|
|
1911
|
+
const pluginAuthObj = {
|
|
1912
|
+
type: authType,
|
|
1913
|
+
};
|
|
1914
|
+
const authName = functionNamesMap[authType].authName;
|
|
1915
|
+
if (pluginAuthObj.type !== "None") {
|
|
1916
|
+
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authName}_${ConstantString.RegistrationIdPostfix}`);
|
|
1917
|
+
pluginAuthObj.reference_id = `\${{${safeRegistrationIdName}}}`;
|
|
1918
|
+
}
|
|
1919
|
+
const functionNamesInfo = functionNamesMap[authType];
|
|
1920
|
+
const index = apiPlugin.runtimes.findIndex((runtime) => {
|
|
1921
|
+
var _a, _b;
|
|
1922
|
+
return runtime.spec.url === specRelativePath &&
|
|
1923
|
+
runtime.type === "OpenApi" &&
|
|
1924
|
+
((_b = (_a = runtime.auth) === null || _a === void 0 ? void 0 : _a.type) !== null && _b !== void 0 ? _b : "None") === authType;
|
|
1896
1925
|
});
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1926
|
+
if (index === -1) {
|
|
1927
|
+
apiPlugin.runtimes.push({
|
|
1928
|
+
type: "OpenApi",
|
|
1929
|
+
auth: pluginAuthObj,
|
|
1930
|
+
spec: {
|
|
1931
|
+
url: specRelativePath,
|
|
1932
|
+
},
|
|
1933
|
+
run_for_functions: functionNamesInfo.functionNames,
|
|
1934
|
+
});
|
|
1935
|
+
}
|
|
1936
|
+
else {
|
|
1937
|
+
apiPlugin.runtimes[index].run_for_functions = functionNamesInfo.functionNames;
|
|
1938
|
+
}
|
|
1900
1939
|
}
|
|
1901
1940
|
if (!apiPlugin.name_for_human) {
|
|
1902
1941
|
apiPlugin.name_for_human = appName;
|
|
@@ -1937,7 +1976,7 @@ class ManifestUpdater {
|
|
|
1937
1976
|
};
|
|
1938
1977
|
if (authInfo) {
|
|
1939
1978
|
const auth = authInfo.authScheme;
|
|
1940
|
-
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix
|
|
1979
|
+
const safeRegistrationIdName = Utils.getSafeRegistrationIdEnvName(`${authInfo.name}_${ConstantString.RegistrationIdPostfix}`);
|
|
1941
1980
|
if (Utils.isAPIKeyAuth(auth) || Utils.isBearerTokenAuth(auth)) {
|
|
1942
1981
|
composeExtension.authorization = {
|
|
1943
1982
|
authType: "apiSecretServiceAuth",
|
|
@@ -2064,6 +2103,7 @@ class SpecParser {
|
|
|
2064
2103
|
};
|
|
2065
2104
|
this.pathOrSpec = pathOrDoc;
|
|
2066
2105
|
this.parser = new SwaggerParser();
|
|
2106
|
+
this.refParser = new $RefParser();
|
|
2067
2107
|
this.options = Object.assign(Object.assign({}, this.defaultOptions), (options !== null && options !== void 0 ? options : {}));
|
|
2068
2108
|
}
|
|
2069
2109
|
/**
|
|
@@ -2076,12 +2116,15 @@ class SpecParser {
|
|
|
2076
2116
|
let hash = "";
|
|
2077
2117
|
try {
|
|
2078
2118
|
await this.loadSpec();
|
|
2079
|
-
if (!this.
|
|
2119
|
+
if (!this.refParser.$refs.circular) {
|
|
2080
2120
|
await this.parser.validate(this.spec);
|
|
2081
2121
|
}
|
|
2082
2122
|
else {
|
|
2123
|
+
// The following code hangs for Graph API, support will be added when SwaggerParser is updated.
|
|
2124
|
+
/*
|
|
2083
2125
|
const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
|
|
2084
2126
|
await this.parser.validate(clonedUnResolveSpec);
|
|
2127
|
+
*/
|
|
2085
2128
|
}
|
|
2086
2129
|
}
|
|
2087
2130
|
catch (e) {
|
|
@@ -2109,7 +2152,7 @@ class SpecParser {
|
|
|
2109
2152
|
};
|
|
2110
2153
|
}
|
|
2111
2154
|
// Remote reference not supported
|
|
2112
|
-
const refPaths = this.
|
|
2155
|
+
const refPaths = this.refParser.$refs.paths();
|
|
2113
2156
|
// refPaths [0] is the current spec file path
|
|
2114
2157
|
if (refPaths.length > 1) {
|
|
2115
2158
|
errors.push({
|
|
@@ -2238,7 +2281,7 @@ class SpecParser {
|
|
|
2238
2281
|
throw new SpecParserError(ConstantString.CancelledMessage, ErrorType.Cancelled);
|
|
2239
2282
|
}
|
|
2240
2283
|
const clonedUnResolveSpec = JSON.parse(JSON.stringify(newUnResolvedSpec));
|
|
2241
|
-
const newSpec =
|
|
2284
|
+
const newSpec = await this.deReferenceSpec(clonedUnResolveSpec);
|
|
2242
2285
|
return [newUnResolvedSpec, newSpec];
|
|
2243
2286
|
}
|
|
2244
2287
|
catch (err) {
|
|
@@ -2248,6 +2291,10 @@ class SpecParser {
|
|
|
2248
2291
|
throw new SpecParserError(err.toString(), ErrorType.GetSpecFailed);
|
|
2249
2292
|
}
|
|
2250
2293
|
}
|
|
2294
|
+
async deReferenceSpec(spec) {
|
|
2295
|
+
const result = await this.refParser.dereference(spec);
|
|
2296
|
+
return result;
|
|
2297
|
+
}
|
|
2251
2298
|
/**
|
|
2252
2299
|
* Generates and update artifacts from the OpenAPI specification file. Generate Adaptive Cards, update Teams app manifest, and generate a new OpenAPI specification file.
|
|
2253
2300
|
* @param manifestPath A file path of the Teams app manifest file to update.
|
|
@@ -2264,13 +2311,21 @@ class SpecParser {
|
|
|
2264
2311
|
const newSpecs = await this.getFilteredSpecs(filter, signal);
|
|
2265
2312
|
const newUnResolvedSpec = newSpecs[0];
|
|
2266
2313
|
const newSpec = newSpecs[1];
|
|
2267
|
-
const authInfo = Utils.getAuthInfo(newSpec);
|
|
2268
2314
|
const paths = newUnResolvedSpec.paths;
|
|
2269
2315
|
for (const pathUrl in paths) {
|
|
2270
2316
|
const operations = paths[pathUrl];
|
|
2271
2317
|
for (const method in operations) {
|
|
2272
2318
|
const operationItem = operations[method];
|
|
2273
2319
|
const operationId = operationItem.operationId;
|
|
2320
|
+
const containsSpecialCharacters = /[^a-zA-Z0-9_]/.test(operationId);
|
|
2321
|
+
if (containsSpecialCharacters) {
|
|
2322
|
+
operationItem.operationId = operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
2323
|
+
result.warnings.push({
|
|
2324
|
+
type: WarningType.OperationIdContainsSpecialCharacters,
|
|
2325
|
+
content: Utils.format(ConstantString.OperationIdContainsSpecialCharacters, operationId, operationItem.operationId),
|
|
2326
|
+
data: operationId,
|
|
2327
|
+
});
|
|
2328
|
+
}
|
|
2274
2329
|
const authArray = Utils.getAuthArray(operationItem.security, newSpec);
|
|
2275
2330
|
if (Utils.isNotSupportedAuth(authArray)) {
|
|
2276
2331
|
result.warnings.push({
|
|
@@ -2279,16 +2334,6 @@ class SpecParser {
|
|
|
2279
2334
|
data: operationId,
|
|
2280
2335
|
});
|
|
2281
2336
|
}
|
|
2282
|
-
const containsSpecialCharacters = /[^a-zA-Z0-9_]/.test(operationId);
|
|
2283
|
-
if (!containsSpecialCharacters) {
|
|
2284
|
-
continue;
|
|
2285
|
-
}
|
|
2286
|
-
operationItem.operationId = operationId.replace(/[^a-zA-Z0-9]/g, "_");
|
|
2287
|
-
result.warnings.push({
|
|
2288
|
-
type: WarningType.OperationIdContainsSpecialCharacters,
|
|
2289
|
-
content: Utils.format(ConstantString.OperationIdContainsSpecialCharacters, operationId, operationItem.operationId),
|
|
2290
|
-
data: operationId,
|
|
2291
|
-
});
|
|
2292
2337
|
}
|
|
2293
2338
|
}
|
|
2294
2339
|
await this.saveFilterSpec(outputSpecPath, newUnResolvedSpec);
|
|
@@ -2301,7 +2346,8 @@ class SpecParser {
|
|
|
2301
2346
|
specPath: this.pathOrSpec,
|
|
2302
2347
|
}
|
|
2303
2348
|
: undefined;
|
|
2304
|
-
const
|
|
2349
|
+
const authMap = Utils.getAuthMap(newSpec);
|
|
2350
|
+
const [updatedManifest, apiPlugin, warnings] = await ManifestUpdater.updateManifestWithAiPlugin(manifestPath, outputSpecPath, pluginFilePath, newSpec, this.options, authMap, existingPluginManifestInfo);
|
|
2305
2351
|
result.warnings.push(...warnings);
|
|
2306
2352
|
await fs.outputJSON(manifestPath, updatedManifest, { spaces: 4 });
|
|
2307
2353
|
await fs.outputJSON(pluginFilePath, apiPlugin, { spaces: 4 });
|
|
@@ -2389,7 +2435,7 @@ class SpecParser {
|
|
|
2389
2435
|
this.isSwaggerFile = true;
|
|
2390
2436
|
}
|
|
2391
2437
|
const clonedUnResolveSpec = JSON.parse(JSON.stringify(this.unResolveSpec));
|
|
2392
|
-
this.spec =
|
|
2438
|
+
this.spec = await this.deReferenceSpec(clonedUnResolveSpec);
|
|
2393
2439
|
}
|
|
2394
2440
|
}
|
|
2395
2441
|
getAPIs(spec) {
|