openapi-explorer 2.1.656 → 2.1.658

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 (80) hide show
  1. package/dist/browser/openapi-explorer.min.js +2 -2
  2. package/dist/es/components/api-request.js +58 -140
  3. package/dist/es/components/api-response.js +9 -34
  4. package/dist/es/components/json-tree.js +4 -18
  5. package/dist/es/components/request-form-table.js +13 -36
  6. package/dist/es/components/schema-table.js +28 -42
  7. package/dist/es/components/schema-tree.js +31 -61
  8. package/dist/es/components/syntax-highlighter.js +7 -26
  9. package/dist/es/components/tag-input.js +2 -14
  10. package/dist/es/openapi-explorer-oauth-handler.js +0 -2
  11. package/dist/es/openapi-explorer.js +62 -174
  12. package/dist/es/react.js +4 -4
  13. package/dist/es/styles/input-styles.js +1 -1
  14. package/dist/es/styles/schema-styles.js +1 -1
  15. package/dist/es/templates/advance-search-template.js +1 -5
  16. package/dist/es/templates/callback-template.js +2 -2
  17. package/dist/es/templates/code-samples-template.js +1 -3
  18. package/dist/es/templates/components-template.js +41 -4
  19. package/dist/es/templates/endpoint-template.js +6 -17
  20. package/dist/es/templates/expanded-endpoint-template.js +4 -7
  21. package/dist/es/templates/focused-endpoint-template.js +0 -10
  22. package/dist/es/templates/mainBodyTemplate.js +3 -2
  23. package/dist/es/templates/navbar-template.js +9 -12
  24. package/dist/es/templates/overview-template.js +1 -1
  25. package/dist/es/templates/security-scheme-template.js +12 -73
  26. package/dist/es/templates/server-template.js +1 -8
  27. package/dist/es/utils/color-utils.js +2 -21
  28. package/dist/es/utils/common-utils.js +3 -20
  29. package/dist/es/utils/schema-utils.js +35 -132
  30. package/dist/es/utils/spec-parser.js +35 -120
  31. package/dist/es/utils/theme.js +3 -6
  32. package/dist/es/utils/xml/xml.js +1 -40
  33. package/dist/lib/components/api-request.js +58 -157
  34. package/dist/lib/components/api-response.js +9 -54
  35. package/dist/lib/components/json-tree.js +4 -27
  36. package/dist/lib/components/request-form-table.js +14 -42
  37. package/dist/lib/components/schema-table.js +28 -52
  38. package/dist/lib/components/schema-tree.js +31 -72
  39. package/dist/lib/components/syntax-highlighter.js +6 -49
  40. package/dist/lib/components/tag-input.js +2 -18
  41. package/dist/lib/languages/en.js +2 -3
  42. package/dist/lib/languages/fr.js +2 -3
  43. package/dist/lib/languages/index.js +0 -6
  44. package/dist/lib/openapi-explorer-oauth-handler.js +0 -6
  45. package/dist/lib/openapi-explorer.js +61 -197
  46. package/dist/lib/react.js +4 -5
  47. package/dist/lib/styles/advanced-search-styles.js +1 -5
  48. package/dist/lib/styles/api-request-styles.js +1 -5
  49. package/dist/lib/styles/border-styles.js +1 -5
  50. package/dist/lib/styles/endpoint-styles.js +1 -5
  51. package/dist/lib/styles/flex-styles.js +1 -5
  52. package/dist/lib/styles/font-styles.js +1 -5
  53. package/dist/lib/styles/info-styles.js +1 -5
  54. package/dist/lib/styles/input-styles.js +1 -5
  55. package/dist/lib/styles/key-frame-styles.js +1 -5
  56. package/dist/lib/styles/nav-styles.js +1 -5
  57. package/dist/lib/styles/prism-styles.js +1 -5
  58. package/dist/lib/styles/schema-styles.js +1 -5
  59. package/dist/lib/styles/tab-styles.js +1 -5
  60. package/dist/lib/styles/table-styles.js +1 -5
  61. package/dist/lib/styles/tag-input-styles.js +1 -5
  62. package/dist/lib/templates/advance-search-template.js +0 -6
  63. package/dist/lib/templates/callback-template.js +1 -3
  64. package/dist/lib/templates/code-samples-template.js +0 -4
  65. package/dist/lib/templates/components-template.js +43 -9
  66. package/dist/lib/templates/endpoint-template.js +6 -29
  67. package/dist/lib/templates/expanded-endpoint-template.js +3 -17
  68. package/dist/lib/templates/focused-endpoint-template.js +0 -19
  69. package/dist/lib/templates/mainBodyTemplate.js +2 -13
  70. package/dist/lib/templates/navbar-template.js +9 -20
  71. package/dist/lib/templates/overview-template.js +0 -5
  72. package/dist/lib/templates/security-scheme-template.js +12 -79
  73. package/dist/lib/templates/server-template.js +1 -12
  74. package/dist/lib/utils/color-utils.js +4 -25
  75. package/dist/lib/utils/common-utils.js +3 -33
  76. package/dist/lib/utils/schema-utils.js +33 -141
  77. package/dist/lib/utils/spec-parser.js +35 -128
  78. package/dist/lib/utils/theme.js +3 -16
  79. package/dist/lib/utils/xml/xml.js +1 -42
  80. package/package.json +2 -2
@@ -3,39 +3,31 @@ import { unsafeHTML } from 'lit/directives/unsafe-html.js';
3
3
  import { marked } from 'marked';
4
4
  import base64url from 'base64url';
5
5
  import { getI18nText } from '../languages/index.js';
6
-
7
6
  function onApiKeyChange(apiKeyId, e) {
8
7
  e.preventDefault();
9
8
  let apiKeyValue = '';
10
9
  const securityObj = this.resolvedSpec.securitySchemes.find(v => v.apiKeyId === apiKeyId);
11
-
12
10
  if (!securityObj) {
13
11
  return;
14
12
  }
15
-
16
13
  const trEl = e.target.closest('tr');
17
-
18
14
  if (securityObj.type && securityObj.type === 'http' && securityObj.scheme && securityObj.scheme.toLowerCase() === 'basic') {
19
15
  const userVal = trEl.querySelector('.api-key-user').value.trim();
20
16
  const passwordVal = trEl.querySelector('.api-key-password').value.trim();
21
-
22
17
  if (passwordVal) {
23
18
  apiKeyValue = `Basic ${btoa(`${userVal}:${passwordVal}`)}`;
24
19
  }
25
20
  } else {
26
21
  apiKeyValue = trEl.querySelector('.api-key-input').value.trim();
27
-
28
22
  if (apiKeyValue) {
29
23
  if (securityObj.scheme && securityObj.scheme.toLowerCase() === 'bearer') {
30
24
  apiKeyValue = `Bearer ${apiKeyValue.replace(/^Bearer\s+/i, '')}`;
31
25
  }
32
26
  }
33
27
  }
34
-
35
28
  securityObj.finalKeyValue = apiKeyValue;
36
29
  this.requestUpdate();
37
30
  }
38
-
39
31
  function onClearAllApiKeys() {
40
32
  this.resolvedSpec.securitySchemes.forEach(v => {
41
33
  v.user = '';
@@ -44,17 +36,17 @@ function onClearAllApiKeys() {
44
36
  v.finalKeyValue = '';
45
37
  });
46
38
  this.requestUpdate();
47
- } // Updates the OAuth Access Token (API key), so it reflects in UI and gets used in TRY calls
48
-
39
+ }
49
40
 
41
+ // Updates the OAuth Access Token (API key), so it reflects in UI and gets used in TRY calls
50
42
  function updateOAuthKey(apiKeyId, tokenType = 'Bearer', accessToken) {
51
43
  const securityObj = this.resolvedSpec.securitySchemes.find(v => v.apiKeyId === apiKeyId);
52
44
  const tokenPrefix = tokenType && tokenType.toLowerCase() === 'bearer' ? 'Bearer' : tokenType;
53
45
  securityObj.finalKeyValue = `${tokenPrefix}${tokenPrefix ? ' ' : ''}${accessToken}`;
54
46
  this.requestUpdate();
55
- } // Gets Access-Token in exchange of Authorization Code
56
-
47
+ }
57
48
 
49
+ // Gets Access-Token in exchange of Authorization Code
58
50
  async function fetchAccessToken(tokenUrl, suggestedClientId, clientSecret, redirectUrl, grantType, authCode, sendClientSecretIn = 'header', apiKeyId, authFlowDivEl, scopes = null) {
59
51
  const respDisplayEl = authFlowDivEl ? authFlowDivEl.querySelector('.oauth-resp-display') : undefined;
60
52
  const {
@@ -66,33 +58,26 @@ async function fetchAccessToken(tokenUrl, suggestedClientId, clientSecret, redir
66
58
  const urlFormParams = new URLSearchParams();
67
59
  const headers = new Headers();
68
60
  urlFormParams.append('grant_type', grantType);
69
-
70
61
  if (redirectUrl) {
71
62
  urlFormParams.append('redirect_uri', redirectUrl);
72
63
  }
73
-
74
64
  if (authCode) {
75
65
  urlFormParams.append('code', authCode);
76
66
  }
77
-
78
67
  if (sendClientSecretIn === 'header') {
79
68
  headers.set('Authorization', `Basic ${btoa(`${clientId}:${clientSecret}`)}`);
80
69
  } else {
81
70
  urlFormParams.append('client_id', clientId);
82
-
83
71
  if (clientSecret) {
84
72
  urlFormParams.append('client_secret', clientSecret);
85
73
  }
86
74
  }
87
-
88
75
  if (scopes) {
89
76
  urlFormParams.append('scope', scopes);
90
77
  }
91
-
92
78
  if (codeVerifier) {
93
79
  urlFormParams.append('code_verifier', codeVerifier);
94
80
  }
95
-
96
81
  try {
97
82
  const resp = await fetch(tokenUrl, {
98
83
  method: 'POST',
@@ -100,18 +85,14 @@ async function fetchAccessToken(tokenUrl, suggestedClientId, clientSecret, redir
100
85
  body: urlFormParams
101
86
  });
102
87
  const tokenResp = await resp.json();
103
-
104
88
  if (!resp.ok) {
105
89
  if (respDisplayEl) {
106
90
  respDisplayEl.innerHTML = `<span style="color:var(--red)">${tokenResp.error_description || tokenResp.error_description || 'Unable to get access token'}</span>`;
107
91
  }
108
-
109
92
  return;
110
93
  }
111
-
112
94
  if (tokenResp.token_type && tokenResp.access_token) {
113
95
  updateOAuthKey.call(this, apiKeyId, tokenResp.token_type, tokenResp.access_token);
114
-
115
96
  if (respDisplayEl) {
116
97
  respDisplayEl.innerHTML = '<span style="color:var(--green)">Access Token Received</span>';
117
98
  }
@@ -122,24 +103,20 @@ async function fetchAccessToken(tokenUrl, suggestedClientId, clientSecret, redir
122
103
  }
123
104
  }
124
105
  }
125
-
126
106
  function getCookieValue(keyId) {
127
107
  const foundCookie = (document.cookie || '').split(';').find(c => c.split('=')[0] === keyId);
128
108
  return foundCookie && foundCookie.split('=')[1] || '';
129
109
  }
130
-
131
110
  function toObject(urlSearchParams) {
132
111
  const result = {};
133
112
  const entries = urlSearchParams && urlSearchParams.entries() || [];
134
-
135
113
  for (const [key, value] of entries) {
136
114
  result[key] = value;
137
115
  }
138
-
139
116
  return result;
140
- } // Gets invoked when it receives the Authorization Code from the other window via message-event
141
-
117
+ }
142
118
 
119
+ // Gets invoked when it receives the Authorization Code from the other window via message-event
143
120
  export async function checkForAuthToken(redirectToApiLocation) {
144
121
  const parameters = toObject(new URLSearchParams(window.location.search));
145
122
  const hashQuery = toObject(new URLSearchParams(window.location.hash.slice(1)));
@@ -158,15 +135,12 @@ export async function checkForAuthToken(redirectToApiLocation) {
158
135
  newUrl.searchParams.delete('hd');
159
136
  newUrl.searchParams.delete('authuser');
160
137
  newUrl.searchParams.delete('redirect_auth');
161
-
162
138
  if (!parameters.state) {
163
139
  return;
164
140
  }
165
-
166
141
  const sanitizedUrlWithHash = newUrl.toString().replace(/#((code|state|access_token|id_token|authuser|expires_in|hd|prompt|scope|token_type)=[^&]+&?)*$/ig, '');
167
142
  history.replaceState({}, undefined, sanitizedUrlWithHash);
168
143
  let parsedState;
169
-
170
144
  try {
171
145
  // If somehow the state contains a question mark, just remove it, a ? is not a valid here
172
146
  parsedState = JSON.parse(base64url.decode(parameters.state.replace(/\?.*$/, '')));
@@ -175,13 +149,11 @@ export async function checkForAuthToken(redirectToApiLocation) {
175
149
  console.error('The state parameter in the OAuth response is invalid', error, parameters.state);
176
150
  return;
177
151
  }
178
-
179
152
  const {
180
153
  apiKeyId,
181
154
  flowId,
182
155
  url
183
156
  } = parsedState;
184
-
185
157
  if (redirectToApiLocation && url && !parameters.redirect_auth) {
186
158
  const apiExplorerLocation = new URL(url);
187
159
  Object.keys(parameters).forEach(key => apiExplorerLocation.searchParams.append(key, parameters[key]));
@@ -189,19 +161,15 @@ export async function checkForAuthToken(redirectToApiLocation) {
189
161
  window.location.replace(apiExplorerLocation.toString());
190
162
  return;
191
163
  }
192
-
193
164
  if (parameters.code) {
194
165
  var _this$selectedServer;
195
-
196
166
  const securityObj = this.resolvedSpec.securitySchemes.find(v => v.apiKeyId === apiKeyId);
197
167
  const tokenUrl = securityObj && securityObj.flows[flowId] && new URL(securityObj.flows[flowId].tokenUrl || '', (_this$selectedServer = this.selectedServer) === null || _this$selectedServer === void 0 ? void 0 : _this$selectedServer.computedUrl);
198
168
  await fetchAccessToken.call(this, tokenUrl, securityObj.clientId, securityObj.clientSecret, securityObj.redirectUri || window.location.href, 'authorization_code', parameters.code, null, apiKeyId);
199
169
  return;
200
170
  }
201
-
202
171
  updateOAuthKey.call(this, apiKeyId, parameters.token_type, parameters.access_token);
203
172
  }
204
-
205
173
  async function onInvokeOAuthFlow(apiKeyId, flowType, authUrl, tokenUrl, e) {
206
174
  const authFlowDivEl = e.target.closest('.oauth-flow');
207
175
  const clientId = authFlowDivEl.querySelector('#oauth-client-id') ? authFlowDivEl.querySelector('#oauth-client-id').value.trim() : '';
@@ -210,18 +178,17 @@ async function onInvokeOAuthFlow(apiKeyId, flowType, authUrl, tokenUrl, e) {
210
178
  const checkedScopeEls = [...authFlowDivEl.querySelectorAll('input[type="checkbox"]:checked')];
211
179
  const securityObj = this.resolvedSpec.securitySchemes.find(v => v.apiKeyId === apiKeyId);
212
180
  let grantType = '';
213
- let responseType = ''; // clear previous error messages
181
+ let responseType = '';
214
182
 
183
+ // clear previous error messages
215
184
  const errEls = [...authFlowDivEl.parentNode.querySelectorAll('.oauth-resp-display')];
216
185
  errEls.forEach(v => {
217
186
  v.innerHTML = '';
218
187
  });
219
-
220
188
  if (flowType === 'authorizationCode' || flowType === 'implicit') {
221
189
  const authUrlObj = new URL(authUrl);
222
190
  const authCodeParams = new URLSearchParams(authUrlObj.search);
223
191
  let codeVerifier;
224
-
225
192
  if (flowType === 'authorizationCode') {
226
193
  const randomBytes = new Uint32Array(12);
227
194
  (window.crypto || window.msCrypto).getRandomValues(randomBytes);
@@ -236,7 +203,6 @@ async function onInvokeOAuthFlow(apiKeyId, flowType, authUrl, tokenUrl, e) {
236
203
  } else if (flowType === 'implicit') {
237
204
  responseType = 'token';
238
205
  }
239
-
240
206
  localStorage.setItem('openapi-explorer-oauth', JSON.stringify({
241
207
  codeVerifier,
242
208
  clientId,
@@ -244,11 +210,9 @@ async function onInvokeOAuthFlow(apiKeyId, flowType, authUrl, tokenUrl, e) {
244
210
  flowId: flowType
245
211
  }));
246
212
  const selectedScopes = checkedScopeEls.map(v => v.value).join(' ');
247
-
248
213
  if (selectedScopes) {
249
214
  authCodeParams.set('scope', selectedScopes);
250
215
  }
251
-
252
216
  authCodeParams.set('client_id', clientId);
253
217
  authCodeParams.set('redirect_uri', securityObj.redirectUri || window.location.href);
254
218
  authCodeParams.set('response_type', responseType);
@@ -265,25 +229,20 @@ async function onInvokeOAuthFlow(apiKeyId, flowType, authUrl, tokenUrl, e) {
265
229
  fetchAccessToken.call(this, tokenUrl, clientId, clientSecret, '', grantType, '', sendClientSecretIn, apiKeyId, authFlowDivEl, selectedScopes);
266
230
  }
267
231
  }
268
- /* eslint-disable indent */
269
232
 
233
+ /* eslint-disable indent */
270
234
 
271
235
  function oAuthFlowTemplate(flowName, securityObj, authFlow) {
272
236
  var _this$selectedServer3, _this$selectedServer4, _this$selectedServer5;
273
-
274
237
  const apiKeyId = securityObj.apiKeyId;
275
-
276
238
  const getFullUrl = url => {
277
239
  var _this$selectedServer2;
278
-
279
240
  return url ? new URL(url, (_this$selectedServer2 = this.selectedServer) === null || _this$selectedServer2 === void 0 ? void 0 : _this$selectedServer2.computedUrl) : undefined;
280
241
  };
281
-
282
242
  const authorizationUrl = getFullUrl(authFlow.authorizationUrl, (_this$selectedServer3 = this.selectedServer) === null || _this$selectedServer3 === void 0 ? void 0 : _this$selectedServer3.computedUrl);
283
243
  const tokenUrl = getFullUrl(authFlow.tokenUrl, (_this$selectedServer4 = this.selectedServer) === null || _this$selectedServer4 === void 0 ? void 0 : _this$selectedServer4.computedUrl);
284
244
  const refreshUrl = getFullUrl(authFlow.refreshUrl, (_this$selectedServer5 = this.selectedServer) === null || _this$selectedServer5 === void 0 ? void 0 : _this$selectedServer5.computedUrl);
285
245
  let flowNameDisplay;
286
-
287
246
  if (flowName === 'authorizationCode') {
288
247
  flowNameDisplay = 'Authorization Code Flow';
289
248
  } else if (flowName === 'clientCredentials') {
@@ -293,20 +252,16 @@ function oAuthFlowTemplate(flowName, securityObj, authFlow) {
293
252
  } else {
294
253
  flowNameDisplay = flowName;
295
254
  }
296
-
297
255
  return html` <div class="oauth-flow" style="padding:10px 0;margin-bottom:10px"> <div class="tiny-title upper" style="margin-bottom:5px">${flowNameDisplay}</div> ${authorizationUrl ? html`<div><span style="width:75px;display:inline-block">Auth URL</span> <span class="mono-font"> ${authorizationUrl} </span></div>` : ''} ${tokenUrl ? html`<div><span style="width:75px;display:inline-block">Token URL</span> <span class="mono-font">${tokenUrl}</span></div>` : ''} ${refreshUrl ? html`<div><span style="width:75px;display:inline-block">Refresh URL</span> <span class="mono-font">${refreshUrl}</span></div>` : ''} ${flowName === 'authorizationCode' || flowName === 'clientCredentials' || flowName === 'implicit' ? html` ${authFlow.scopes ? html` <span> Scopes </span> <div class="oauth-scopes" part="section-auth-scopes" style="width:100%;display:flex;flex-direction:column;flex-wrap:wrap;margin:0 0 .125rem 0"> ${Object.entries(authFlow.scopes).map((scopeAndDescr, index) => html` <div class="m-checkbox" style="display:inline-flex;align-items:center"> <input type="checkbox" checked="checked" part="checkbox checkbox-auth-scope" id="${flowName}${index}" value="${scopeAndDescr[0]}"> <label for="${flowName}${index}" style="margin-left:5px"> <span class="mono-font">${scopeAndDescr[0]}</span> ${scopeAndDescr[0] !== scopeAndDescr[1] ? ` - ${scopeAndDescr[1] || ''}` : ''} </label> </div> `)} </div> ` : ''} <div style="display:flex"> <div> <input id="oauth-client-id" type="text" part="textbox textbox-auth-client-id" value="${securityObj.clientId || ''}" placeholder="Client ID" spellcheck="false" class="oauth-client-input"> ${flowName === 'clientCredentials' ? html` <input id="oauth-client-secret" type="password" part="textbox textbox-auth-client-secret" value="" placeholder="Client Secret" spellcheck="false" class="oauth-client-input"> <select id="oauth-send-client-secret-in" aria-label="oauth client secret location" style="margin-right:5px" class="oauth-client-input"> <option value="header" selected="selected"> Authorization Header </option> <option value="request-body"> Request Body </option> </select> ` : html`<div style="width:5px"></div>`} </div> ${flowName === 'authorizationCode' || flowName === 'clientCredentials' || flowName === 'implicit' ? html` <div class="oauth-client-input" style="margin-left:1rem"> <button class="m-btn thin-border" part="btn btn-outline" @click="${e => {
298
256
  onInvokeOAuthFlow.call(this, apiKeyId, flowName, authorizationUrl, tokenUrl, e);
299
257
  }}">GET TOKEN</button> </div>` : ''} </div> <div class="oauth-resp-display red-text small-font-size"></div> ` : ''} </div> `;
300
258
  }
301
-
302
259
  function renderSecurityScheme(v) {
303
260
  if (!v.type) {
304
261
  return '';
305
262
  }
306
-
307
263
  if (v.type.toLowerCase() === 'apikey' || v.type.toLowerCase() === 'http' && v.scheme && v.scheme.toLowerCase() === 'bearer') {
308
264
  var _v$bearerFormat, _v$bearerFormat2;
309
-
310
265
  return html` <div style="padding-top:1rem"> ${v.type.toLowerCase() === 'apikey' ? html`Send <code>${v.name || 'API key'}</code> in <code>${v.in || 'the request'}</code> with the given value:` : html`Send <code>Authorization</code> in <code>header</code> containing the word <code>Bearer</code> followed by a space and then the ${(_v$bearerFormat = v.bearerFormat) !== null && _v$bearerFormat !== void 0 ? _v$bearerFormat : 'Token String'}.`} </div> <form style="height:50px;margin-top:1rem;padding:10px 0;margin-bottom:10px"> ${v.in === 'cookie' ? html` <div style="display:block"> <input type="text" value="${getCookieValue(v.apiKeyId)}" disabled="disabled" class="api-key-input" placeholder="IygRVGf54B59e0GAkKmigGfuiVlp/uhFfk2ifA+jMMJzau2F1jPldc09gPTfnMw13BFBxqUZIFDm55DPfwkb0A==" spellcheck="false" style="resize:horizontal;width:100%"> <br> <small> <strong>Cookies</strong>&nbsp;are set and configured by the remote service, therefore it is not possible to configure them from the browser. </small> </div>` : !v.finalKeyValue ? html` <input type="text" value="${v.value}" placeholder="${(_v$bearerFormat2 = v.bearerFormat) !== null && _v$bearerFormat2 !== void 0 ? _v$bearerFormat2 : 'api-token'}" spellcheck="false" class="api-key-input fs-exclude" data-hj-suppress data-sl="mask"> <button type="submit" class="m-btn thin-border" style="margin-left:5px" part="btn btn-outline" @click="${e => {
311
266
  onApiKeyChange.call(this, v.apiKeyId, e);
312
267
  }}"> ${getI18nText('authentication.set')} </button>` : html`<span class="blue-text" style="margin-right:1rem">Key Applied</span> <button class="m-btn thin-border small" part="btn btn-outline" @click="${() => {
@@ -314,7 +269,6 @@ function renderSecurityScheme(v) {
314
269
  this.requestUpdate();
315
270
  }}">REMOVE</button>`} </form>`;
316
271
  }
317
-
318
272
  if (v.type.toLowerCase() === 'http' && v.scheme && v.scheme.toLowerCase() === 'basic') {
319
273
  if (v.finalKeyValue) {
320
274
  return html` <div style="padding-top:1rem">${getI18nText('authentication.http-basic-desc')}</div> <div style="height:50px;margin-top:1rem;padding:10px 0;margin-bottom:10px"> <span class="blue-text" style="margin-right:1rem">Key Applied</span> <button class="m-btn thin-border small" part="btn btn-outline" @click="${() => {
@@ -322,61 +276,46 @@ function renderSecurityScheme(v) {
322
276
  this.requestUpdate();
323
277
  }}">REMOVE</button> </div>`;
324
278
  }
325
-
326
279
  return html` <div style="padding-top:1rem">${getI18nText('authentication.http-basic-desc')}</div> <div style="height:50px;margin-top:1rem;padding:10px 0;margin-bottom:10px"> <form style="display:flex"> <input type="text" value="${v.user}" placeholder="${getI18nText('authentication.username')}" spellcheck="false" class="api-key-user" style="width:100px"> <input class="api-key-password fs-exclude" data-hj-suppress data-sl="mask" type="password" value="${v.password}" placeholder="${getI18nText('authentication.password')}" spellcheck="false" style="width:100px;margin:0 5px"> <button type="submit" class="m-btn thin-border" @click="${e => {
327
280
  onApiKeyChange.call(this, v.apiKeyId, e);
328
281
  }}" part="btn btn-outline"> ${v.finalKeyValue ? 'UPDATE' : getI18nText('authentication.set')} </button> </form> </div>`;
329
282
  }
330
-
331
283
  if (v.type.toLowerCase() === 'oauth2' && Object.keys(v.flows).length) {
332
284
  return html`${Object.keys(v.flows).map(f => oAuthFlowTemplate.call(this, f, v, v.flows[f]))}`;
333
285
  }
334
-
335
286
  return '';
336
287
  }
337
-
338
288
  export default function securitySchemeTemplate() {
339
289
  const schemes = this.resolvedSpec && this.resolvedSpec.securitySchemes;
340
-
341
290
  if (!schemes) {
342
291
  return undefined;
343
292
  }
344
-
345
293
  const providedApiKeys = schemes.filter(v => v.finalKeyValue);
346
294
  return html` <section id="auth" part="section-auth" class="observe-me ${this.renderStyle === 'focused' ? 'section-gap--focused-mode' : 'section-gap'}"> <slot name="authentication"> <div class="section-padding"> <slot name="authentication-header"> <div class="sub-title regular-font">${getI18nText('headers.authentication')}</div> </slot> <div class="small-font-size" style="display:flex;align-items:center;min-height:40px"> ${providedApiKeys.length > 0 ? html` <div class="blue-text"> ${providedApiKeys.length} API key applied </div> <div style="flex:1"></div> <button class="m-btn thin-border" part="btn btn-outline" @click="${() => {
347
295
  onClearAllApiKeys.call(this);
348
296
  }}">CLEAR ALL API KEYS</button>` : html`<div class="red-text">${getI18nText('authentication.no-api-key-applied')}</div>`} </div> ${schemes.length > 0 ? html` <table role="presentation" class="m-table" style="width:100%"> ${schemes.map(v => html` <tr> <td colspan="1" style="max-width:500px;overflow-wrap:break-word"> <div style="min-height:24px;display:flex;flex-direction:column;justify-content:center;align-items:center"> <div style="display:flex;justify-content:center"> <span style="font-weight:700">${getTypeDisplayHeader(v)}</span> </div> </div> ${v.description ? html` <div class="m-markdown"> ${unsafeHTML(marked(v.description || ''))} </div>` : ''} </td> <td colspan="3">${renderSecurityScheme.call(this, v)}</td> </tr>`)} </table>` : ''} <slot name="authentication-footer"></slot> </div> </slot> </section> `;
349
297
  }
350
-
351
298
  function getOauthScopeTemplate(rawScopes) {
352
299
  const scopes = Array.isArray(rawScopes) ? rawScopes.map(s => s === null || s === void 0 ? void 0 : s.trim()).filter(s => s) : [];
353
-
354
300
  if (!scopes.length) {
355
301
  return '';
356
302
  }
357
-
358
303
  return html` <div> <b>Required scopes:</b> <br> <div style="margin-left:8px"> ${scopes.map(scope => html`<span>${scope}</span>&nbsp;`)} </div> </div>`;
359
304
  }
360
-
361
305
  function getTypeDisplayHeader(securityScheme) {
362
306
  if (securityScheme.type === 'apiKey') {
363
307
  return `API Key (${securityScheme.name})`;
364
308
  }
365
-
366
309
  if (securityScheme.type === 'oauth2') {
367
310
  return 'OAuth2.0';
368
311
  }
369
-
370
312
  if (securityScheme.type === 'http') {
371
313
  return securityScheme.scheme === 'basic' ? getI18nText('authentication.http-basic') : 'HTTP Bearer';
372
314
  }
373
-
374
315
  return securityScheme.type;
375
316
  }
376
-
377
317
  export function pathSecurityTemplate(pathSecurityOptions) {
378
318
  const requiredSecurityOptions = (pathSecurityOptions === null || pathSecurityOptions === void 0 ? void 0 : pathSecurityOptions.filter(o => o && Object.keys(o).length)) || [];
379
-
380
319
  if (this.resolvedSpec.securitySchemes && requiredSecurityOptions.length) {
381
320
  const orSecurityKeys1 = [];
382
321
  requiredSecurityOptions.forEach(pSecurity => {
@@ -384,10 +323,10 @@ export function pathSecurityTemplate(pathSecurityOptions) {
384
323
  const andKeyTypes = [];
385
324
  Object.keys(pSecurity).forEach(pathSecurityKey => {
386
325
  const s = this.resolvedSpec.securitySchemes.find(ss => ss.apiKeyId === pathSecurityKey);
387
-
388
326
  if (s) {
389
327
  andKeyTypes.push(getTypeDisplayHeader(s));
390
- andSecurityKeys1.push({ ...s,
328
+ andSecurityKeys1.push({
329
+ ...s,
391
330
  scopes: pSecurity[pathSecurityKey]
392
331
  });
393
332
  }
@@ -399,7 +338,7 @@ export function pathSecurityTemplate(pathSecurityOptions) {
399
338
  });
400
339
  return html`<div class="security-info-button" data-content-id="auth" @click="${e => this.scrollToEventTarget(e, false)}"> <div style="position:relative;display:flex;min-width:350px;max-width:700px;justify-content:flex-end"> <svg width="16" height="24" style="cursor:pointer"> <g> <path style="fill:var(--fg3)" d="m13.8,8.5l0,-2.6l0,0c0,-3.2 -2.6,-5.8 -5.8,-5.8s-5.8,2.6 -5.8,5.8l0,0l0,2.6l-2.1,0l0,11.2l16,0l0,-11.2l-2.1,0l-0,0l0,0l0,0l-0,0zm-9.8,-2.6c0,0 0,0 0,0c0,-2.2 1.8,-4 4,-4c2.2,0 4,1.8 4,4c0,0 0,0 0,0l0,2.6l-8.03,0l0,-2.6l0,0l0,0z"/> </g> </svg> ${orSecurityKeys1.map((orSecurityItem1, i) => html` ${i !== 0 ? html`<div style="padding:3px 4px"> OR </div>` : ''} <div class="security-tooltip tooltip" style="cursor:pointer"> <div style="padding:2px 4px;white-space:nowrap;text-overflow:ellipsis;max-width:150px;overflow:hidden"> <span part="anchor anchor-operation-security"> ${orSecurityItem1.securityTypes} </span> </div> <div class="tooltip-text" style="position:absolute;color:var(--fg);top:26px;right:0;border:1px solid var(--border-color);padding:2px 4px;display:block"> ${orSecurityItem1.securityDefs.length > 1 ? html`<div>Requires <b>all</b> of the following </div>` : ''} <div style="padding-left:8px"> ${orSecurityItem1.securityDefs.map((andSecurityItem, j) => html` ${andSecurityItem.type === 'oauth2' ? html` <div> ${orSecurityItem1.securityDefs.length > 1 ? html`<b>${j + 1}.</b> &nbsp;` : html`Requires`} OAuth token (${andSecurityItem.apiKeyId}) in <b>Authorization header</b> ${getOauthScopeTemplate(andSecurityItem.scopes)} </div>` : andSecurityItem.type === 'http' ? html` <div> ${orSecurityItem1.securityDefs.length > 1 ? html`<b>${j + 1}.</b> &nbsp;` : html`${getI18nText('authentication.requires')}`} ${andSecurityItem.scheme === 'basic' ? getI18nText('authentication.http-basic-note') : 'Bearer Token'} ${getI18nText('authentication.in-auth-header')} ${getOauthScopeTemplate(andSecurityItem.scopes)} </div>` : html` <div> ${orSecurityItem1.securityDefs.length > 1 ? html`<b>${j + 1}.</b> &nbsp;` : html`Requires`} Token in <b>${andSecurityItem.name} ${andSecurityItem.in}</b> ${getOauthScopeTemplate(andSecurityItem.scopes)} </div>`} `)} </div> </div> </div> `)} </div> </div>`;
401
340
  }
402
-
403
341
  return '';
404
342
  }
343
+
405
344
  /* eslint-enable indent */
@@ -2,14 +2,12 @@ import { html } from 'lit';
2
2
  import { marked } from 'marked';
3
3
  import { unsafeHTML } from 'lit/directives/unsafe-html.js';
4
4
  import { getI18nText } from '../languages/index.js';
5
-
6
5
  function onApiServerChange(e, server) {
7
6
  if (e && e.target.checked) {
8
7
  this.selectedServer = server;
9
8
  this.requestUpdate();
10
9
  }
11
10
  }
12
-
13
11
  function onApiServerVarChange(e, serverObj) {
14
12
  const inputEls = [...e.currentTarget.closest('table').querySelectorAll('input, select')];
15
13
  let tempUrl = serverObj.url;
@@ -20,26 +18,21 @@ function onApiServerVarChange(e, serverObj) {
20
18
  serverObj.computedUrl = tempUrl;
21
19
  this.requestUpdate();
22
20
  }
23
- /* eslint-disable indent */
24
-
25
21
 
22
+ /* eslint-disable indent */
26
23
  function serverVarsTemplate() {
27
24
  var _this$selectedServer;
28
-
29
25
  return Object.keys(((_this$selectedServer = this.selectedServer) === null || _this$selectedServer === void 0 ? void 0 : _this$selectedServer.variables) || {}).length ? html` <div class="table-title">${getI18nText('api-servers.server-variables')}</div> <table role="presentation" class="m-table"> ${Object.entries(this.selectedServer.variables).map(kv => html` <tr> <td colspan="1" style="vertical-align:middle">${kv[0]}</td> <td colspan="2"> ${kv[1].enum ? html` <select data-var="${kv[0]}" @input="${e => {
30
26
  onApiServerVarChange.call(this, e, this.selectedServer);
31
27
  }}"> ${Object.entries(kv[1].enum).map(e => kv[1].default === e[1] ? html` <option selected="selected" label="${e[1]}" value="${e[1]}">` : html` <option label="${e[1]}" value="${e[1]}">`)} </select>` : html` <input type="text" part="textbox textbox-server-var" spellcheck="false" data-var="${kv[0]}" value="${kv[1].default}" @input="${e => {
32
28
  onApiServerVarChange.call(this, e, this.selectedServer);
33
29
  }}">`} </td> </tr> ${kv[1].description ? html`<tr><td colspan="2" style="border:none"><span class="m-markdown-small"> ${unsafeHTML(marked(kv[1].description))} </span></td></tr>` : ''} `)} </table> ` : '';
34
30
  }
35
-
36
31
  export default function serverTemplate() {
37
32
  var _this$selectedServer2;
38
-
39
33
  if (!this.resolvedSpec) {
40
34
  return undefined;
41
35
  }
42
-
43
36
  return html` <section id="servers" part="section-servers" style="margin-top:24px;margin-bottom:24px" class="regular-font observe-me section-padding ${this.renderStyle === 'read' ? 'section-gap--read-mode' : this.renderStyle === 'focused' ? 'section-gap--focused-mode' : 'section-gap'}"> <div class="sub-title">${getI18nText('headers.api-servers')}</div> <div class="mono-font" style="margin:12px 0;font-size:calc(var(--font-size-small) + 1px)"> ${!this.resolvedSpec.servers || !this.resolvedSpec.servers.length ? '' : html` ${this.resolvedSpec.servers.map((server, i) => html` <input type="radio" name="api_server" id="srvr-opt-${i}" value="${server.url}" @change="${e => {
44
37
  onApiServerChange.call(this, e, server);
45
38
  }}" .checked="${this.selectedServer.url === server.url}" style="margin:4px 0;cursor:pointer"> <label style="cursor:pointer" for="srvr-opt-${i}"> ${server.url} ${server.description ? html`- <span class="regular-font">${server.description} </span>` : ''} </label> <br> `)} `} <div class="table-title primary-text" part="label-selected-server"> ${getI18nText('api-servers.selected')}: ${((_this$selectedServer2 = this.selectedServer) === null || _this$selectedServer2 === void 0 ? void 0 : _this$selectedServer2.computedUrl) || 'none'}</div> </div> <slot name="servers"></slot> ${serverVarsTemplate.call(this)} </section>`;
@@ -1,24 +1,19 @@
1
1
  /* eslint-disable no-mixed-operators */
2
-
3
2
  /* eslint-disable no-bitwise */
4
3
  export default {
5
4
  color: {
6
5
  inputReverseFg: '#fff',
7
6
  inputReverseBg: '#333',
8
7
  headerBg: '#444',
9
-
10
8
  getRgb(hexStr) {
11
9
  let hex = (hexStr || '').trim();
12
-
13
10
  if (hex.indexOf('#') === 0) {
14
11
  hex = hex.slice(1, 7);
15
- } // convert 3-digit hex to 6-digits.
16
-
17
-
12
+ }
13
+ // convert 3-digit hex to 6-digits.
18
14
  if (hex.length === 3 || hex.length === 4) {
19
15
  hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
20
16
  }
21
-
22
17
  if (hex.length !== 6) {
23
18
  // eslint-disable-next-line no-console
24
19
  console.error(`Invalid HEX color: '${hexStr}'`);
@@ -28,24 +23,20 @@ export default {
28
23
  b: 0
29
24
  };
30
25
  }
31
-
32
26
  return {
33
27
  r: parseInt(hex.slice(0, 2), 16),
34
28
  g: parseInt(hex.slice(2, 4), 16),
35
29
  b: parseInt(hex.slice(4, 6), 16)
36
30
  };
37
31
  },
38
-
39
32
  luminanace(hexColorCode) {
40
33
  const rgb = this.getRgb(hexColorCode);
41
34
  return rgb.r * 0.299 + rgb.g * 0.587 + rgb.b * 0.114;
42
35
  },
43
-
44
36
  invert(hexColorCode) {
45
37
  // compare with `>=128`, but giving little more preference to white over black
46
38
  return this.luminanace(hexColorCode) > 149 ? '#000000' : '#ffffff';
47
39
  },
48
-
49
40
  // https://stackoverflow.com/a/41491220/5091874
50
41
  selectTextColorFromBackground(bcHexColor) {
51
42
  const {
@@ -58,49 +49,39 @@ export default {
58
49
  if (col <= 0.03928) {
59
50
  return col / 12.92;
60
51
  }
61
-
62
52
  return ((col + 0.055) / 1.055) ** 2.4;
63
53
  });
64
54
  const L = 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2];
65
55
  return L > 0.179 ? '#000000' : '#FFFFFF';
66
56
  },
67
-
68
57
  opacity(hex, opacity) {
69
58
  const rgb = this.getRgb(hex);
70
59
  return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${opacity})`;
71
60
  },
72
-
73
61
  brightness(hex, amt) {
74
62
  const rgb = this.getRgb(hex);
75
63
  rgb.r += amt;
76
64
  rgb.g += amt;
77
65
  rgb.b += amt;
78
-
79
66
  if (rgb.r > 255) {
80
67
  rgb.r = 255;
81
68
  } else if (rgb.r < 0) {
82
69
  rgb.r = 0;
83
70
  }
84
-
85
71
  if (rgb.g > 255) {
86
72
  rgb.g = 255;
87
73
  } else if (rgb.g < 0) {
88
74
  rgb.g = 0;
89
75
  }
90
-
91
76
  if (rgb.b > 255) {
92
77
  rgb.b = 255;
93
78
  } else if (rgb.b < 0) {
94
79
  rgb.b = 0;
95
80
  }
96
-
97
81
  return `#${rgb.r.toString(16).padStart(2, '0')}${rgb.g.toString(16).padStart(2, '0')}${rgb.b.toString(16).padStart(2, '0')}`;
98
82
  }
99
-
100
83
  },
101
-
102
84
  isValidHexColor(colorCode) {
103
85
  return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|[A-Fa-f0-9]{8}|[A-Fa-f0-9]{4})$/i.test(colorCode);
104
86
  }
105
-
106
87
  };
@@ -1,6 +1,6 @@
1
1
  import { getI18nText } from '../languages/index.js';
2
- /* For Delayed Event Handler Execution */
3
2
 
3
+ /* For Delayed Event Handler Execution */
4
4
  export function debounce(fn, delay) {
5
5
  let timeoutID = null;
6
6
  return (...args) => {
@@ -19,28 +19,24 @@ export function sleep(ms) {
19
19
  export function copyToClipboard(copyData, eventTarget) {
20
20
  // In lots of places we have more than a couple of spaces for <pre> display purposes, we remove those extra spaces here.
21
21
  let data = copyData === null || copyData === void 0 ? void 0 : copyData.trim().replace(/\s{8}/g, ' ');
22
-
23
22
  try {
24
23
  // If the parsed type is a number, then leave it alone
25
24
  if (typeof JSON.parse(data) === 'object') {
26
25
  // Convert to 2 spaces in all JSON text
27
26
  data = JSON.stringify(JSON.parse(data), null, 2).trim();
28
27
  }
29
- } catch (error) {// Ignore non JSON text;
28
+ } catch (error) {
29
+ // Ignore non JSON text;
30
30
  }
31
-
32
31
  const textArea = document.createElement('textarea');
33
32
  textArea.value = data;
34
33
  textArea.style.position = 'fixed'; // avoid scrolling to bottom
35
-
36
34
  document.body.appendChild(textArea);
37
35
  textArea.focus();
38
36
  textArea.select();
39
-
40
37
  try {
41
38
  document.execCommand('copy');
42
39
  const btnEl = eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.target;
43
-
44
40
  if (btnEl) {
45
41
  btnEl.innerText = getI18nText('operations.copied');
46
42
  setTimeout(() => {
@@ -50,7 +46,6 @@ export function copyToClipboard(copyData, eventTarget) {
50
46
  } catch (err) {
51
47
  console.error('Unable to copy', err); // eslint-disable-line no-console
52
48
  }
53
-
54
49
  document.body.removeChild(textArea);
55
50
  }
56
51
  export function getBaseUrlFromUrl(url) {
@@ -64,7 +59,6 @@ export function pathIsInSearch(searchVal, path) {
64
59
  if (!searchVal) {
65
60
  return true;
66
61
  }
67
-
68
62
  const stringToSearch = `${path.method} ${path.path} ${path.summary || ''} ${path.description || ''} ${path.operationId || ''}`;
69
63
  return stringToSearch.includes(searchVal) || stringToSearch.toLowerCase().includes(searchVal) || stringToSearch.normalize('NFD').replace(/[\u0300-\u036f]/g, '').includes(searchVal) || stringToSearch.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '').includes(searchVal);
70
64
  }
@@ -72,10 +66,8 @@ export function schemaKeys(schemaProps, result = new Set()) {
72
66
  if (!schemaProps) {
73
67
  return result;
74
68
  }
75
-
76
69
  Object.keys(schemaProps).forEach(key => {
77
70
  result.add(key);
78
-
79
71
  if (schemaProps[key].properties) {
80
72
  schemaKeys(schemaProps[key].properties, result);
81
73
  } else if (schemaProps[key].items && schemaProps[key].items.properties) {
@@ -88,40 +80,31 @@ export function advancedSearch(searchVal, allSpecTags, searchOptions = []) {
88
80
  if (!searchVal.trim() || searchOptions.length === 0) {
89
81
  return undefined;
90
82
  }
91
-
92
83
  const pathsMatched = [];
93
84
  allSpecTags.forEach(tag => {
94
85
  tag.paths.forEach(path => {
95
86
  let stringToSearch = '';
96
-
97
87
  if (searchOptions.includes('search-api-path')) {
98
88
  stringToSearch = path.path;
99
89
  }
100
-
101
90
  if (searchOptions.includes('search-api-descr')) {
102
91
  stringToSearch = `${stringToSearch} ${path.summary || path.description || ''}`;
103
92
  }
104
-
105
93
  if (searchOptions.includes('search-api-params')) {
106
94
  stringToSearch = `${stringToSearch} ${path.parameters && path.parameters.map(v => v.name).join(' ') || ''}`;
107
95
  }
108
-
109
96
  if (searchOptions.includes('search-api-request-body') && path.requestBody) {
110
97
  let schemaKeySet = new Set();
111
-
112
98
  for (const contentType in path.requestBody && path.requestBody.content) {
113
99
  if (path.requestBody.content[contentType].schema && path.requestBody.content[contentType].schema.properties) {
114
100
  schemaKeySet = schemaKeys(path.requestBody.content[contentType].schema.properties);
115
101
  }
116
-
117
102
  stringToSearch = `${stringToSearch} ${[...schemaKeySet].join(' ')}`;
118
103
  }
119
104
  }
120
-
121
105
  if (searchOptions.includes('search-api-resp-descr')) {
122
106
  stringToSearch = `${stringToSearch} ${Object.values(path.responses).map(v => v.description || '').join(' ')}`;
123
107
  }
124
-
125
108
  if (stringToSearch.toLowerCase().includes(searchVal.trim().toLowerCase())) {
126
109
  pathsMatched.push({
127
110
  elementId: path.elementId,