rapidoc 9.3.3 → 9.3.4
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/.github/workflow/words.yaml +22 -0
- package/dist/rapidoc-min.js +815 -709
- package/dist/rapidoc-min.js.LICENSE.txt +8 -7
- package/dist/rapidoc-min.js.LICENSE.txt.gz +0 -0
- package/dist/rapidoc-min.js.gz +0 -0
- package/dist/rapidoc-min.js.map +1 -1
- package/dist/rapidoc-min.js.map.gz +0 -0
- package/dist/rapidoc.js +17680 -31489
- package/dist/report.html +5 -4
- package/package.json +18 -18
- package/src/components/api-request.js +218 -112
- package/src/components/api-response.js +11 -10
- package/src/components/json-tree.js +17 -12
- package/src/components/schema-table.js +47 -39
- package/src/components/schema-tree.js +55 -52
- package/src/components/tag-input.js +7 -4
- package/src/json-schema-viewer.js +1 -1
- package/src/rapidoc-mini.js +1 -1
- package/src/rapidoc.js +98 -30
- package/src/styles/endpoint-styles.js +1 -1
- package/src/styles/info-styles.js +2 -1
- package/src/styles/input-styles.js +2 -16
- package/src/styles/nav-styles.js +57 -10
- package/src/styles/schema-styles.js +27 -15
- package/src/styles/tab-styles.js +1 -0
- package/src/templates/callback-template.js +3 -3
- package/src/templates/code-samples-template.js +1 -0
- package/src/templates/components-template.js +3 -5
- package/src/templates/endpoint-template.js +38 -25
- package/src/templates/expanded-endpoint-template.js +57 -8
- package/src/templates/focused-endpoint-template.js +4 -1
- package/src/templates/header-template.js +2 -2
- package/src/templates/json-schema-viewer-template.js +2 -1
- package/src/templates/main-body-template.js +19 -18
- package/src/templates/navbar-template.js +98 -81
- package/src/templates/overview-template.js +1 -1
- package/src/templates/security-scheme-template.js +48 -25
- package/src/templates/server-template.js +1 -1
- package/src/utils/common-utils.js +1 -1
- package/src/utils/schema-utils.js +161 -63
- package/src/utils/spec-parser.js +1 -0
- package/src/utils/theme.js +9 -3
- package/webpack.config.js +2 -1
|
@@ -4,70 +4,87 @@ import { pathIsInSearch } from '~/utils/common-utils';
|
|
|
4
4
|
|
|
5
5
|
export function expandCollapseNavBarTag(navLinkEl, action = 'toggle') {
|
|
6
6
|
const tagAndPathEl = navLinkEl?.closest('.nav-bar-tag-and-paths');
|
|
7
|
+
const pathsUnderTagEl = tagAndPathEl?.querySelector('.nav-bar-paths-under-tag');
|
|
7
8
|
if (tagAndPathEl) {
|
|
8
9
|
const isExpanded = tagAndPathEl.classList.contains('expanded');
|
|
9
10
|
if (isExpanded && (action === 'toggle' || action === 'collapse')) {
|
|
11
|
+
pathsUnderTagEl.style.maxHeight = 0;
|
|
10
12
|
tagAndPathEl.classList.replace('expanded', 'collapsed');
|
|
11
13
|
} else if (!isExpanded && (action === 'toggle' || action === 'expand')) {
|
|
12
14
|
tagAndPathEl.classList.replace('collapsed', 'expanded');
|
|
15
|
+
pathsUnderTagEl.style.maxHeight = `${pathsUnderTagEl.scrollHeight}px`;
|
|
13
16
|
}
|
|
14
17
|
}
|
|
15
18
|
}
|
|
16
19
|
|
|
17
|
-
export function expandCollapseAll(
|
|
20
|
+
export function expandCollapseAll(event, action = 'expand-all') {
|
|
21
|
+
if (!(event.type === 'click' || (event.type === 'keyup' && event.keyCode === 13))) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const navEl = event.target.closest('.nav-scroll');
|
|
18
25
|
const elList = [...navEl.querySelectorAll('.nav-bar-tag-and-paths')];
|
|
19
26
|
if (action === 'expand-all') {
|
|
20
|
-
elList.
|
|
27
|
+
elList.forEach((el) => {
|
|
28
|
+
const navBarPathsUnderTagEl = el.querySelector('.nav-bar-paths-under-tag');
|
|
21
29
|
el.classList.replace('collapsed', 'expanded');
|
|
30
|
+
navBarPathsUnderTagEl.style.maxHeight = `${navBarPathsUnderTagEl?.scrollHeight}px`;
|
|
22
31
|
});
|
|
23
32
|
} else {
|
|
24
|
-
elList.
|
|
33
|
+
elList.forEach((el) => {
|
|
25
34
|
el.classList.replace('expanded', 'collapsed');
|
|
35
|
+
el.querySelector('.nav-bar-paths-under-tag').style.maxHeight = 0;
|
|
26
36
|
});
|
|
27
37
|
}
|
|
28
38
|
}
|
|
29
39
|
|
|
30
|
-
function
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
export function navBarClickAndEnterHandler(event) {
|
|
41
|
+
if (!(event.type === 'click' || (event.type === 'keyup' && event.keyCode === 13))) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const navEl = event.target;
|
|
45
|
+
event.stopPropagation();
|
|
46
|
+
if (navEl.dataset?.action === 'navigate') {
|
|
47
|
+
this.scrollToEventTarget(event, false);
|
|
48
|
+
} else if (navEl.dataset?.action === 'expand-all' || (navEl.dataset?.action === 'collapse-all')) {
|
|
49
|
+
expandCollapseAll(event, navEl.dataset.action);
|
|
50
|
+
} else if (navEl.dataset?.action === 'expand-collapse-tag') {
|
|
51
|
+
expandCollapseNavBarTag(navEl, 'toggle');
|
|
52
|
+
}
|
|
36
53
|
}
|
|
37
54
|
|
|
38
55
|
/* eslint-disable indent */
|
|
39
56
|
export default function navbarTemplate() {
|
|
40
57
|
if (!this.resolvedSpec || this.resolvedSpec.specLoadError) {
|
|
41
58
|
return html`
|
|
42
|
-
<nav class='nav-bar' part=
|
|
43
|
-
<slot name=
|
|
59
|
+
<nav class='nav-bar' part='section-navbar'>
|
|
60
|
+
<slot name='nav-logo' class='logo'></slot>
|
|
44
61
|
</nav>
|
|
45
62
|
`;
|
|
46
63
|
}
|
|
47
64
|
return html`
|
|
48
|
-
<nav class='nav-bar ${this.renderStyle}' part=
|
|
49
|
-
<slot name=
|
|
65
|
+
<nav class='nav-bar ${this.renderStyle}' part='section-navbar'>
|
|
66
|
+
<slot name='nav-logo' class='logo'></slot>
|
|
50
67
|
${(this.allowSearch === 'false' && this.allowAdvancedSearch === 'false')
|
|
51
68
|
? ''
|
|
52
69
|
: html`
|
|
53
|
-
<div style=
|
|
70
|
+
<div style='display:flex; flex-direction:row; justify-content:center; align-items:stretch; padding:8px 24px 12px 24px; ${this.allowAdvancedSearch === 'false' ? 'border-bottom: 1px solid var(--nav-hover-bg-color)' : ''}' part='section-navbar-search'>
|
|
54
71
|
${this.allowSearch === 'false'
|
|
55
72
|
? ''
|
|
56
73
|
: html`
|
|
57
|
-
<div style=
|
|
58
|
-
<input id=
|
|
59
|
-
part =
|
|
60
|
-
style =
|
|
61
|
-
type =
|
|
62
|
-
placeholder =
|
|
63
|
-
@change =
|
|
64
|
-
spellcheck =
|
|
74
|
+
<div style = 'display:flex; flex:1; line-height:22px;'>
|
|
75
|
+
<input id = 'nav-bar-search'
|
|
76
|
+
part = 'textbox textbox-nav-filter'
|
|
77
|
+
style = 'width:100%; padding-right:20px; color:var(--nav-hover-text-color); border-color:var(--nav-accent-color); background-color:var(--nav-hover-bg-color)'
|
|
78
|
+
type = 'text'
|
|
79
|
+
placeholder = 'Filter'
|
|
80
|
+
@change = '${this.onSearchChange}'
|
|
81
|
+
spellcheck = 'false'
|
|
65
82
|
>
|
|
66
|
-
<div style=
|
|
83
|
+
<div style='margin: 6px 5px 0 -24px; font-size:var(--font-size-regular); cursor:pointer;'>↩</div>
|
|
67
84
|
</div>
|
|
68
85
|
${this.matchPaths
|
|
69
86
|
? html`
|
|
70
|
-
<button @click = '${this.onClearSearch}' class=
|
|
87
|
+
<button @click = '${this.onClearSearch}' class='m-btn thin-border' style='margin-left:5px; color:var(--nav-text-color); width:75px; padding:6px 8px;' part='btn btn-outline btn-clear-filter'>
|
|
71
88
|
CLEAR
|
|
72
89
|
</button>`
|
|
73
90
|
: ''
|
|
@@ -77,7 +94,7 @@ export default function navbarTemplate() {
|
|
|
77
94
|
${this.allowAdvancedSearch === 'false' || this.matchPaths
|
|
78
95
|
? ''
|
|
79
96
|
: html`
|
|
80
|
-
<button class=
|
|
97
|
+
<button class='m-btn primary' part='btn btn-fill btn-search' style='margin-left:5px; padding:6px 8px; width:75px' @click='${this.onShowSearchModalClicked}'>
|
|
81
98
|
SEARCH
|
|
82
99
|
</button>
|
|
83
100
|
`
|
|
@@ -85,25 +102,25 @@ export default function navbarTemplate() {
|
|
|
85
102
|
</div>
|
|
86
103
|
`
|
|
87
104
|
}
|
|
88
|
-
${html`<nav class='nav-scroll' part=
|
|
105
|
+
${html`<nav class='nav-scroll' tabindex='-1' part='section-navbar-scroll' @click='${(e) => navBarClickAndEnterHandler.call(this, e)}' @keyup='${(e) => navBarClickAndEnterHandler.call(this, e)}' >
|
|
89
106
|
${(this.showInfo === 'false' || !this.resolvedSpec.info)
|
|
90
107
|
? ''
|
|
91
108
|
: html`
|
|
92
109
|
${(this.infoDescriptionHeadingsInNavBar === 'true')
|
|
93
110
|
? html`
|
|
94
111
|
${this.resolvedSpec.infoDescriptionHeaders.length > 0
|
|
95
|
-
? html`<div class='nav-bar-info' id='link-overview' data-content-id='overview'
|
|
112
|
+
? html`<div class='nav-bar-info ${this.navActiveItemMarker}' id='link-overview' data-content-id='overview' data-action='navigate' tabindex='0' part='section-navbar-item section-navbar-overview'>
|
|
96
113
|
${this.resolvedSpec.info?.title?.trim() || 'Overview'}
|
|
97
114
|
</div>`
|
|
98
115
|
: ''
|
|
99
116
|
}
|
|
100
|
-
<div class=
|
|
117
|
+
<div class='overview-headers'>
|
|
101
118
|
${this.resolvedSpec.infoDescriptionHeaders.map((header) => html`
|
|
102
|
-
<div
|
|
103
|
-
class='nav-bar-h${header.depth}'
|
|
104
|
-
id=
|
|
119
|
+
<div
|
|
120
|
+
class='nav-bar-h${header.depth} ${this.navActiveItemMarker}'
|
|
121
|
+
id='link-overview--${new marked.Slugger().slug(header.text)}'
|
|
122
|
+
data-action='navigate'
|
|
105
123
|
data-content-id='overview--${new marked.Slugger().slug(header.text)}'
|
|
106
|
-
@click='${(e) => this.scrollToEventTarget(e, false)}'
|
|
107
124
|
>
|
|
108
125
|
${header.text}
|
|
109
126
|
</div>`)
|
|
@@ -111,28 +128,36 @@ export default function navbarTemplate() {
|
|
|
111
128
|
</div>
|
|
112
129
|
${this.resolvedSpec.infoDescriptionHeaders.length > 0 ? html`<hr style='border-top: 1px solid var(--nav-hover-bg-color); border-width:1px 0 0 0; margin: 15px 0 0 0'/>` : ''}
|
|
113
130
|
`
|
|
114
|
-
: html`<div class='nav-bar-info' id='link-overview' data-content-id='overview'
|
|
115
|
-
|
|
116
|
-
|
|
131
|
+
: html`<div class='nav-bar-info ${this.navActiveItemMarker}' id='link-overview' data-action='navigate' data-content-id='overview' tabindex='0'>
|
|
132
|
+
${this.resolvedSpec.info?.title?.trim() || 'Overview'}
|
|
133
|
+
</div>`
|
|
117
134
|
}
|
|
118
135
|
`
|
|
119
136
|
}
|
|
120
137
|
|
|
121
138
|
${this.allowServerSelection === 'false'
|
|
122
139
|
? ''
|
|
123
|
-
: html`<div class='nav-bar-info' id='link-servers' data-content-id='servers'
|
|
140
|
+
: html`<div class='nav-bar-info ${this.navActiveItemMarker}' id='link-servers' data-action='navigate' data-content-id='servers' tabindex='0' part='section-navbar-item section-navbar-servers'> API Servers </div>`
|
|
124
141
|
}
|
|
125
142
|
${(this.allowAuthentication === 'false' || !this.resolvedSpec.securitySchemes)
|
|
126
143
|
? ''
|
|
127
|
-
: html`<div class='nav-bar-info' id='link-auth' data-content-id='auth'
|
|
144
|
+
: html`<div class='nav-bar-info ${this.navActiveItemMarker}' id='link-auth' data-action='navigate' data-content-id='auth' tabindex='0' part='section-navbar-item section-navbar-auth'> Authentication </div>`
|
|
128
145
|
}
|
|
129
146
|
|
|
130
|
-
<div id='link-operations-top' class='nav-bar-section operations' data-content-id='operations-top'
|
|
131
|
-
<div style=
|
|
147
|
+
<div id='link-operations-top' class='nav-bar-section operations' data-action='navigate' data-content-id='${this.renderStyle === 'focused' ? '' : 'operations-top'}' part='section-navbar-item section-navbar-operations-top'>
|
|
148
|
+
<div style='font-size:16px; display:flex; margin-left:10px;'>
|
|
132
149
|
${this.renderStyle === 'focused'
|
|
133
150
|
? html`
|
|
134
|
-
<div
|
|
135
|
-
|
|
151
|
+
<div class='nav-bar-expand-all'
|
|
152
|
+
data-action='expand-all'
|
|
153
|
+
tabindex='0'
|
|
154
|
+
title='Expand all'
|
|
155
|
+
>▸</div>
|
|
156
|
+
<div class='nav-bar-collapse-all'
|
|
157
|
+
data-action='collapse-all'
|
|
158
|
+
tabindex='0'
|
|
159
|
+
title='Collapse all'
|
|
160
|
+
>▸</div>`
|
|
136
161
|
: ''
|
|
137
162
|
}
|
|
138
163
|
</div>
|
|
@@ -143,30 +168,21 @@ export default function navbarTemplate() {
|
|
|
143
168
|
${this.resolvedSpec.tags
|
|
144
169
|
.filter((tag) => tag.paths.filter((path) => pathIsInSearch(this.matchPaths, path, this.matchType)).length)
|
|
145
170
|
.map((tag) => html`
|
|
146
|
-
<div class='nav-bar-tag-and-paths ${tag.expanded ? 'expanded' : 'collapsed'}'>
|
|
171
|
+
<div class='nav-bar-tag-and-paths ${(this.renderStyle === 'read' ? 'expanded' : (tag.expanded ? 'expanded' : 'collapsed'))}' >
|
|
147
172
|
${tag.name === 'General ⦂'
|
|
148
|
-
? html`<hr style=
|
|
173
|
+
? html`<hr style='border:none; border-top: 1px dotted var(--nav-text-color); opacity:0.3; margin:-1px 0 0 0;'/>`
|
|
149
174
|
: html`
|
|
150
175
|
<div
|
|
151
|
-
class='nav-bar-tag'
|
|
152
|
-
|
|
153
|
-
|
|
176
|
+
class='nav-bar-tag ${this.navActiveItemMarker}'
|
|
177
|
+
part='section-navbar-item section-navbar-tag'
|
|
178
|
+
id='link-${tag.elementId}'
|
|
179
|
+
data-action='${(this.renderStyle === 'read' ? 'navigate' : this.onNavTagClick === 'show-description') ? 'navigate' : 'expand-collapse-tag'}'
|
|
180
|
+
data-content-id='${(this.renderStyle === 'read' ? `${tag.elementId}` : this.onNavTagClick === 'show-description') ? `${tag.elementId}` : ''}'
|
|
154
181
|
data-first-path-id='${tag.firstPathId}'
|
|
155
|
-
|
|
156
|
-
if (this.renderStyle === 'focused' && this.onNavTagClick === 'expand-collapse') {
|
|
157
|
-
onExpandCollapse.call(this, e);
|
|
158
|
-
} else {
|
|
159
|
-
this.scrollToEventTarget(e, false);
|
|
160
|
-
}
|
|
161
|
-
}}'
|
|
182
|
+
tabindex='0'
|
|
162
183
|
>
|
|
163
|
-
<div>${tag.name}</div>
|
|
164
|
-
<div class=
|
|
165
|
-
if (this.renderStyle === 'focused' && this.onNavTagClick === 'show-description') {
|
|
166
|
-
onExpandCollapse.call(this, e);
|
|
167
|
-
}
|
|
168
|
-
}}">
|
|
169
|
-
</div>
|
|
184
|
+
<div style="pointer-events:none;">${tag.name}</div>
|
|
185
|
+
<div class='nav-bar-tag-icon' tabindex='0' data-action='expand-collapse-tag'></div>
|
|
170
186
|
</div>
|
|
171
187
|
`
|
|
172
188
|
}
|
|
@@ -177,19 +193,19 @@ export default function navbarTemplate() {
|
|
|
177
193
|
: html`
|
|
178
194
|
<div class='tag-headers'>
|
|
179
195
|
${tag.headers.map((header) => html`
|
|
180
|
-
<div
|
|
181
|
-
class='nav-bar-h${header.depth}'
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
196
|
+
<div
|
|
197
|
+
class='nav-bar-h${header.depth} ${this.navActiveItemMarker}'
|
|
198
|
+
part='section-navbar-item section-navbar-h${header.depth}'
|
|
199
|
+
id='link-${tag.elementId}--${new marked.Slugger().slug(header.text)}'
|
|
200
|
+
data-action='navigate'
|
|
201
|
+
data-content-id='${tag.elementId}--${new marked.Slugger().slug(header.text)}'
|
|
202
|
+
tabindex='0'
|
|
185
203
|
> ${header.text}</div>`)}
|
|
186
204
|
</div>`
|
|
187
205
|
}`
|
|
188
206
|
: ''
|
|
189
207
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
<div class='nav-bar-paths-under-tag'>
|
|
208
|
+
<div class='nav-bar-paths-under-tag' style='max-height:${(tag.expanded || this.renderStyle === 'read') ? ((tag.paths?.length || 1) * 50) : 0}px;'>
|
|
193
209
|
<!-- Paths in each tag (endpoints) -->
|
|
194
210
|
${tag.paths.filter((v) => {
|
|
195
211
|
if (this.matchPaths) {
|
|
@@ -198,22 +214,21 @@ export default function navbarTemplate() {
|
|
|
198
214
|
return true;
|
|
199
215
|
}).map((p) => html`
|
|
200
216
|
<div
|
|
201
|
-
class='nav-bar-path
|
|
202
|
-
|
|
217
|
+
class='nav-bar-path ${this.navActiveItemMarker} ${this.usePathInNavBar === 'true' ? 'small-font' : ''}'
|
|
218
|
+
part='section-navbar-item section-navbar-path'
|
|
219
|
+
data-action='navigate'
|
|
203
220
|
data-content-id='${p.elementId}'
|
|
204
221
|
id='link-${p.elementId}'
|
|
205
|
-
|
|
206
|
-
this.scrollToEventTarget(e, false);
|
|
207
|
-
}}'
|
|
222
|
+
tabindex='0'
|
|
208
223
|
>
|
|
209
|
-
<span style =
|
|
210
|
-
${html`<span class=
|
|
224
|
+
<span style = 'display:flex; pointer-events: none; align-items:start; ${p.deprecated ? 'filter:opacity(0.5)' : ''}'>
|
|
225
|
+
${html`<span class='nav-method ${this.showMethodInNavBar} ${p.method}' style='pointer-events: none;'>
|
|
211
226
|
${this.showMethodInNavBar === 'as-colored-block' ? p.method.substring(0, 3).toUpperCase() : p.method.toUpperCase()}
|
|
212
227
|
</span>`
|
|
213
228
|
}
|
|
214
|
-
${p.isWebhook ? html`<span style=
|
|
229
|
+
${p.isWebhook ? html`<span style='font-weight:bold; pointer-events: none; margin-right:8px; font-size: calc(var(--font-size-small) - 2px)'>WEBHOOK</span>` : ''}
|
|
215
230
|
${this.usePathInNavBar === 'true'
|
|
216
|
-
? html`<span class='mono-font'>${p.path}</span>`
|
|
231
|
+
? html`<span style='pointer-events: none;' class='mono-font'>${p.path}</span>`
|
|
217
232
|
: p.summary || p.shortSummary
|
|
218
233
|
}
|
|
219
234
|
</span>
|
|
@@ -232,14 +247,16 @@ export default function navbarTemplate() {
|
|
|
232
247
|
</div>
|
|
233
248
|
${this.resolvedSpec.components.map((component) => (component.subComponents.length
|
|
234
249
|
? html`
|
|
235
|
-
<div class='nav-bar-tag'
|
|
250
|
+
<div class='nav-bar-tag'
|
|
251
|
+
part='section-navbar-item section-navbar-tag'
|
|
252
|
+
data-action='navigate'
|
|
236
253
|
data-content-id='cmp--${component.name.toLowerCase()}'
|
|
237
|
-
id='link-cmp--${component.name.toLowerCase()}'
|
|
238
|
-
|
|
254
|
+
id='link-cmp--${component.name.toLowerCase()}'
|
|
255
|
+
>
|
|
239
256
|
${component.name}
|
|
240
257
|
</div>
|
|
241
258
|
${component.subComponents.filter((p) => p.expanded !== false).map((p) => html`
|
|
242
|
-
<div class='nav-bar-path' data-content-id='cmp--${p.id}' id='link-cmp--${p.id}'
|
|
259
|
+
<div class='nav-bar-path' data-action='navigate' data-content-id='cmp--${p.id}' id='link-cmp--${p.id}'>
|
|
243
260
|
<span> ${p.name} </span>
|
|
244
261
|
</div>`)
|
|
245
262
|
}`
|
|
@@ -50,7 +50,7 @@ export default function overviewTemplate() {
|
|
|
50
50
|
${this.specUrl && this.allowSpecFileDownload === 'true'
|
|
51
51
|
? html`
|
|
52
52
|
<div style="display:flex; margin:12px 0; gap:8px; justify-content: start;">
|
|
53
|
-
<button class="m-btn thin-border" style="width:170px" part="btn btn-outline" @click='${(e) => { downloadResource(this.specUrl, 'openapi-spec', e); }}'>Download OpenAPI spec</button>
|
|
53
|
+
<button class="m-btn thin-border" style="min-width:170px" part="btn btn-outline" @click='${(e) => { downloadResource(this.specUrl, 'openapi-spec', e); }}'>Download OpenAPI spec</button>
|
|
54
54
|
${this.specUrl?.trim().toLowerCase().endsWith('json')
|
|
55
55
|
? html`<button class="m-btn thin-border" style="width:200px" part="btn btn-outline" @click='${(e) => { viewResource(this.specUrl, e); }}'>View OpenAPI spec (New Tab)</button>`
|
|
56
56
|
: ''
|
|
@@ -16,7 +16,7 @@ export function applyApiKey(securitySchemeId, username = '', password = '', prov
|
|
|
16
16
|
let finalApiKeyValue = '';
|
|
17
17
|
if (securityObj.scheme?.toLowerCase() === 'basic') {
|
|
18
18
|
if (username) {
|
|
19
|
-
finalApiKeyValue = `Basic ${
|
|
19
|
+
finalApiKeyValue = `Basic ${Buffer.from(`${username}:${password}`, 'utf8').toString('base64')}`;
|
|
20
20
|
}
|
|
21
21
|
} else if (providedApikeyVal) {
|
|
22
22
|
securityObj.value = providedApikeyVal;
|
|
@@ -92,6 +92,10 @@ async function fetchAccessToken(tokenUrl, clientId, clientSecret, redirectUrl, g
|
|
|
92
92
|
const urlFormParams = new URLSearchParams();
|
|
93
93
|
const headers = new Headers();
|
|
94
94
|
urlFormParams.append('grant_type', grantType);
|
|
95
|
+
if (grantType === 'authorization_code') {
|
|
96
|
+
urlFormParams.append('client_id', clientId);
|
|
97
|
+
urlFormParams.append('client_secret', clientSecret);
|
|
98
|
+
}
|
|
95
99
|
if (grantType !== 'client_credentials' && grantType !== 'password') {
|
|
96
100
|
urlFormParams.append('redirect_uri', redirectUrl);
|
|
97
101
|
}
|
|
@@ -100,7 +104,7 @@ async function fetchAccessToken(tokenUrl, clientId, clientSecret, redirectUrl, g
|
|
|
100
104
|
urlFormParams.append('code_verifier', codeVerifier); // for PKCE
|
|
101
105
|
}
|
|
102
106
|
if (sendClientSecretIn === 'header') {
|
|
103
|
-
headers.set('Authorization', `Basic ${
|
|
107
|
+
headers.set('Authorization', `Basic ${Buffer.from(`${clientId}:${clientSecret}`, 'utf8').toString('base64')}`);
|
|
104
108
|
} else {
|
|
105
109
|
urlFormParams.append('client_id', clientId);
|
|
106
110
|
urlFormParams.append('client_secret', clientSecret);
|
|
@@ -185,8 +189,8 @@ async function onInvokeOAuthFlow(securitySchemeId, flowType, authUrl, tokenUrl,
|
|
|
185
189
|
const sendClientSecretIn = authFlowDivEl.querySelector('.oauth-send-client-secret-in') ? authFlowDivEl.querySelector('.oauth-send-client-secret-in').value.trim() : 'header';
|
|
186
190
|
const checkedScopeEls = [...authFlowDivEl.querySelectorAll('.scope-checkbox:checked')];
|
|
187
191
|
const pkceCheckboxEl = authFlowDivEl.querySelector(`#${securitySchemeId}-pkce`);
|
|
188
|
-
const state = (`${Math.random().toString(36)}random
|
|
189
|
-
const nonce = (`${Math.random().toString(36)}random
|
|
192
|
+
const state = (`${Math.random().toString(36).slice(2, 9)}random${Math.random().toString(36).slice(2, 9)}`);
|
|
193
|
+
const nonce = (`${Math.random().toString(36).slice(2, 9)}random${Math.random().toString(36).slice(2, 9)}`);
|
|
190
194
|
// const codeChallenge = await generateCodeChallenge(codeVerifier);
|
|
191
195
|
const redirectUrlObj = new URL(`${window.location.origin}${window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/'))}/${this.oauthReceiver}`);
|
|
192
196
|
let grantType = '';
|
|
@@ -254,15 +258,20 @@ async function onInvokeOAuthFlow(securitySchemeId, flowType, authUrl, tokenUrl,
|
|
|
254
258
|
|
|
255
259
|
function oAuthFlowTemplate(flowName, clientId, clientSecret, securitySchemeId, authFlow, defaultScopes = [], receiveTokenIn = 'header') {
|
|
256
260
|
let { authorizationUrl, tokenUrl, refreshUrl } = authFlow;
|
|
261
|
+
const pkceOnly = authFlow['x-pkce-only'] || false;
|
|
257
262
|
const isUrlAbsolute = (url) => (url.indexOf('://') > 0 || url.indexOf('//') === 0);
|
|
263
|
+
// Calculcate base URL
|
|
264
|
+
const url = new URL(this.selectedServer.computedUrl);
|
|
265
|
+
const baseUrl = url.origin;
|
|
266
|
+
|
|
258
267
|
if (refreshUrl && !isUrlAbsolute(refreshUrl)) {
|
|
259
|
-
refreshUrl = `${
|
|
268
|
+
refreshUrl = `${baseUrl}/${refreshUrl.replace(/^\//, '')}`;
|
|
260
269
|
}
|
|
261
270
|
if (tokenUrl && !isUrlAbsolute(tokenUrl)) {
|
|
262
|
-
tokenUrl = `${
|
|
271
|
+
tokenUrl = `${baseUrl}/${tokenUrl.replace(/^\//, '')}`;
|
|
263
272
|
}
|
|
264
273
|
if (authorizationUrl && !isUrlAbsolute(authorizationUrl)) {
|
|
265
|
-
authorizationUrl = `${
|
|
274
|
+
authorizationUrl = `${baseUrl}/${authorizationUrl.replace(/^\//, '')}`;
|
|
266
275
|
}
|
|
267
276
|
let flowNameDisplay;
|
|
268
277
|
if (flowName === 'authorizationCode') {
|
|
@@ -322,7 +331,7 @@ function oAuthFlowTemplate(flowName, clientId, clientSecret, securitySchemeId, a
|
|
|
322
331
|
${flowName === 'authorizationCode'
|
|
323
332
|
? html`
|
|
324
333
|
<div style="margin: 16px 0 4px">
|
|
325
|
-
<input type="checkbox" part="checkbox checkbox-auth-scope" id="${securitySchemeId}-pkce" checked>
|
|
334
|
+
<input type="checkbox" part="checkbox checkbox-auth-scope" id="${securitySchemeId}-pkce" checked ?disabled=${pkceOnly}>
|
|
326
335
|
<label for="${securitySchemeId}-pkce" style="margin:0 16px 0 4px; line-height:24px; cursor:pointer">
|
|
327
336
|
Send Proof Key for Code Exchange (PKCE)
|
|
328
337
|
</label>
|
|
@@ -333,15 +342,17 @@ function oAuthFlowTemplate(flowName, clientId, clientSecret, securitySchemeId, a
|
|
|
333
342
|
<input type="text" part="textbox textbox-auth-client-id" value = "${clientId || ''}" placeholder="client-id" spellcheck="false" class="oauth2 ${flowName} ${securitySchemeId} oauth-client-id">
|
|
334
343
|
${flowName === 'authorizationCode' || flowName === 'clientCredentials' || flowName === 'password'
|
|
335
344
|
? html`
|
|
336
|
-
<input
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
+
<input
|
|
346
|
+
type="password" part="textbox textbox-auth-client-secret"
|
|
347
|
+
value = "${clientSecret || ''}" placeholder="client-secret" spellcheck="false"
|
|
348
|
+
class="oauth2 ${flowName} ${securitySchemeId}
|
|
349
|
+
oauth-client-secret"
|
|
350
|
+
style = "margin:0 5px;${pkceOnly ? 'display:none;' : ''}"
|
|
351
|
+
>
|
|
352
|
+
<select style="margin-right:5px;${pkceOnly ? 'display:none;' : ''}" class="${flowName} ${securitySchemeId} oauth-send-client-secret-in">
|
|
353
|
+
<option value = 'header' .selected = ${receiveTokenIn === 'header'} > Authorization Header </option>
|
|
354
|
+
<option value = 'request-body' .selected = ${receiveTokenIn === 'request-body'}> Request Body </option>
|
|
355
|
+
</select>`
|
|
345
356
|
: ''
|
|
346
357
|
}
|
|
347
358
|
${flowName === 'authorizationCode' || flowName === 'clientCredentials' || flowName === 'implicit' || flowName === 'password'
|
|
@@ -395,7 +406,7 @@ export default function securitySchemeTemplate() {
|
|
|
395
406
|
</div>
|
|
396
407
|
${this.resolvedSpec.securitySchemes && this.resolvedSpec.securitySchemes.length > 0
|
|
397
408
|
? html`
|
|
398
|
-
<table id="auth-table" class='m-table padded-12' style="width:100%;">
|
|
409
|
+
<table role="presentation" id="auth-table" class='m-table padded-12' style="width:100%;">
|
|
399
410
|
${this.resolvedSpec.securitySchemes.map((v) => html`
|
|
400
411
|
<tr id="security-scheme-${v.securitySchemeId}" class="${v.type.toLowerCase()}">
|
|
401
412
|
<td style="max-width:500px; overflow-wrap: break-word;">
|
|
@@ -462,7 +473,17 @@ export default function securitySchemeTemplate() {
|
|
|
462
473
|
? html`
|
|
463
474
|
<tr>
|
|
464
475
|
<td style="border:none; padding-left:48px">
|
|
465
|
-
${Object.keys(v.flows).map((f) => oAuthFlowTemplate
|
|
476
|
+
${Object.keys(v.flows).map((f) => oAuthFlowTemplate
|
|
477
|
+
.call(
|
|
478
|
+
this,
|
|
479
|
+
f,
|
|
480
|
+
(v.flows[f]['x-client-id'] || v['x-client-id'] || ''),
|
|
481
|
+
(v.flows[f]['x-client-secret'] || v['x-client-secret'] || ''),
|
|
482
|
+
v.securitySchemeId,
|
|
483
|
+
v.flows[f],
|
|
484
|
+
(v.flows[f]['x-default-scopes'] || v['x-default-scopes']),
|
|
485
|
+
(v.flows[f]['x-receive-token-in'] || v['x-receive-token-in']),
|
|
486
|
+
))}
|
|
466
487
|
</td>
|
|
467
488
|
</tr>
|
|
468
489
|
`
|
|
@@ -480,6 +501,13 @@ export default function securitySchemeTemplate() {
|
|
|
480
501
|
export function pathSecurityTemplate(pathSecurity) {
|
|
481
502
|
if (this.resolvedSpec.securitySchemes && pathSecurity) {
|
|
482
503
|
const orSecurityKeys1 = [];
|
|
504
|
+
if (Array.isArray(pathSecurity)) {
|
|
505
|
+
if (pathSecurity.length === 0) {
|
|
506
|
+
return '';
|
|
507
|
+
}
|
|
508
|
+
} else {
|
|
509
|
+
return '';
|
|
510
|
+
}
|
|
483
511
|
pathSecurity.forEach((pSecurity) => {
|
|
484
512
|
const andSecurityKeys1 = [];
|
|
485
513
|
const andKeyTypes = [];
|
|
@@ -508,13 +536,8 @@ export function pathSecurityTemplate(pathSecurity) {
|
|
|
508
536
|
});
|
|
509
537
|
return html`<div style="position:absolute; top:3px; right:2px; font-size:var(--font-size-small); line-height: 1.5;">
|
|
510
538
|
<div style="position:relative; display:flex; min-width:350px; max-width:700px; justify-content: flex-end;">
|
|
511
|
-
<svg width="
|
|
512
|
-
<g>
|
|
513
|
-
<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" />
|
|
514
|
-
</g>
|
|
515
|
-
</svg>
|
|
539
|
+
<svg width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" fill="none" style="stroke:var(--fg3)"> <rect x="5" y="11" width="14" height="10" rx="2" /> <circle cx="12" cy="16" r="1" /> <path d="M8 11v-4a4 4 0 0 1 8 0v4" /></svg>
|
|
516
540
|
${orSecurityKeys1.map((orSecurityItem1, i) => html`
|
|
517
|
-
|
|
518
541
|
${orSecurityItem1.securityTypes
|
|
519
542
|
? html`
|
|
520
543
|
${i !== 0 ? html`<div style="padding:3px 4px;"> OR </div>` : ''}
|
|
@@ -36,7 +36,7 @@ function serverVarsTemplate() {
|
|
|
36
36
|
return this.selectedServer && this.selectedServer.variables
|
|
37
37
|
? html`
|
|
38
38
|
<div class="table-title">SERVER VARIABLES</div>
|
|
39
|
-
<table class='m-table'>
|
|
39
|
+
<table class='m-table' role='presentation'>
|
|
40
40
|
${Object.entries(this.selectedServer.variables).map((kv) => html`
|
|
41
41
|
<tr>
|
|
42
42
|
<td style="vertical-align: middle;" >${kv[0]}</td>
|
|
@@ -19,7 +19,7 @@ export function sleep(ms) {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export function copyToClipboard(data, e) {
|
|
22
|
-
const btnEl = e.
|
|
22
|
+
const btnEl = e.target;
|
|
23
23
|
const textArea = document.createElement('textarea');
|
|
24
24
|
textArea.value = data;
|
|
25
25
|
textArea.style.position = 'fixed'; // avoid scrolling to bottom
|