@vnphu/nestjs-api-explorer 0.2.0 → 0.2.1
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-explorer.html.d.ts","sourceRoot":"","sources":["../src/api-explorer.html.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AAEnE,wBAAgB,eAAe,CAAC,OAAO,EAAE,0BAA0B,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"api-explorer.html.d.ts","sourceRoot":"","sources":["../src/api-explorer.html.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AAEnE,wBAAgB,eAAe,CAAC,OAAO,EAAE,0BAA0B,GAAG,MAAM,CAknD3E"}
|
|
@@ -254,7 +254,7 @@ function getExplorerHtml(options) {
|
|
|
254
254
|
|
|
255
255
|
/* ── Summary Panel ── */
|
|
256
256
|
#summary-panel {
|
|
257
|
-
width:
|
|
257
|
+
width: 400px; flex-shrink: 0; border-left: 1px solid var(--border);
|
|
258
258
|
background: var(--bg-white); display: flex; flex-direction: column; overflow: hidden;
|
|
259
259
|
}
|
|
260
260
|
#summary-panel.hidden { display: none; }
|
|
@@ -263,6 +263,13 @@ function getExplorerHtml(options) {
|
|
|
263
263
|
display: flex; align-items: center; justify-content: space-between;
|
|
264
264
|
}
|
|
265
265
|
.summary-header-title { font-size: 11px; font-weight: 700; color: var(--text); text-transform: uppercase; letter-spacing: 0.5px; }
|
|
266
|
+
.summary-copy-btn {
|
|
267
|
+
display: flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 500;
|
|
268
|
+
color: var(--text-muted); background: none; border: 1px solid var(--border);
|
|
269
|
+
border-radius: var(--radius-sm); padding: 3px 8px; cursor: pointer; transition: all 0.15s;
|
|
270
|
+
}
|
|
271
|
+
.summary-copy-btn:hover { background: var(--bg-input); color: var(--accent); border-color: var(--accent); }
|
|
272
|
+
.summary-copy-btn.copied { color: #16a34a; border-color: #86efac; background: #f0fdf4; }
|
|
266
273
|
#summary-body { flex: 1; overflow-y: auto; padding: 10px 14px 16px; display: flex; flex-direction: column; gap: 14px; }
|
|
267
274
|
.summary-section { display: flex; flex-direction: column; gap: 6px; }
|
|
268
275
|
.summary-section-label {
|
|
@@ -829,6 +836,10 @@ function getExplorerHtml(options) {
|
|
|
829
836
|
<div id="summary-panel" class="hidden">
|
|
830
837
|
<div class="summary-header">
|
|
831
838
|
<span class="summary-header-title">Request Summary</span>
|
|
839
|
+
<button id="summary-copy-btn" class="summary-copy-btn hidden" title="Copy summary">
|
|
840
|
+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
841
|
+
<span id="summary-copy-label">Copy</span>
|
|
842
|
+
</button>
|
|
832
843
|
</div>
|
|
833
844
|
<div id="summary-body">
|
|
834
845
|
<div class="summary-empty" id="summary-empty">
|
|
@@ -928,11 +939,9 @@ function groupRoutes(routes) {
|
|
|
928
939
|
|
|
929
940
|
function renderRouteItem(r) {
|
|
930
941
|
const active = S.selected?.method === r.method && S.selected?.path === r.path ? ' active' : '';
|
|
931
|
-
const desc = r.description ? \`<span class="route-desc">\${esc(r.description.split('\\n')[0])}</span>\` : '';
|
|
932
942
|
return \`<div class="route-item\${active}" data-method="\${r.method}" data-path="\${esc(r.path)}">
|
|
933
943
|
<span class="method-badge method-\${r.method}">\${r.method}</span>
|
|
934
944
|
<span class="route-path" title="\${esc(r.path)}">\${esc(r.path)}</span>
|
|
935
|
-
\${desc}
|
|
936
945
|
</div>\`;
|
|
937
946
|
}
|
|
938
947
|
|
|
@@ -1011,8 +1020,28 @@ function selectRoute(route) {
|
|
|
1011
1020
|
document.querySelectorAll('#req-panel-inner .tab-panel').forEach(p => p.classList.remove('active'));
|
|
1012
1021
|
document.getElementById('tab-params').classList.add('active');
|
|
1013
1022
|
|
|
1014
|
-
// Auto-
|
|
1023
|
+
// Auto-fill body editor from body schema if available
|
|
1015
1024
|
const bodyMethods = ['POST', 'PUT', 'PATCH'];
|
|
1025
|
+
if (bodyMethods.includes(route.method) && route.body?.length) {
|
|
1026
|
+
const template = {};
|
|
1027
|
+
route.body.forEach(f => {
|
|
1028
|
+
if (f.type === 'number') template[f.name] = 0;
|
|
1029
|
+
else if (f.type === 'boolean') template[f.name] = false;
|
|
1030
|
+
else if (f.type === 'array') template[f.name] = [];
|
|
1031
|
+
else if (f.type === 'object') template[f.name] = {};
|
|
1032
|
+
else template[f.name] = '';
|
|
1033
|
+
});
|
|
1034
|
+
S.body.content = JSON.stringify(template, null, 2);
|
|
1035
|
+
S.body.type = 'json';
|
|
1036
|
+
el.bodyEditor.value = S.body.content;
|
|
1037
|
+
// Sync body type radio
|
|
1038
|
+
document.querySelectorAll('[name="body-type"]').forEach(r => {
|
|
1039
|
+
r.checked = r.value === 'json';
|
|
1040
|
+
});
|
|
1041
|
+
el.formatBtn.style.display = '';
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
// Auto-switch to Body tab for methods that send a body
|
|
1016
1045
|
if (bodyMethods.includes(route.method) && !route.params.length) {
|
|
1017
1046
|
el.reqTabBar.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
|
1018
1047
|
el.reqTabBar.querySelector('[data-tab="body"]').classList.add('active');
|
|
@@ -1198,16 +1227,21 @@ function renderSummary() {
|
|
|
1198
1227
|
const empty = $('summary-empty');
|
|
1199
1228
|
const content = $('summary-content');
|
|
1200
1229
|
|
|
1230
|
+
const copyBtn = $('summary-copy-btn');
|
|
1231
|
+
|
|
1201
1232
|
if (!S.selected) {
|
|
1202
1233
|
panel.classList.remove('hidden');
|
|
1203
1234
|
empty.style.display = 'flex';
|
|
1204
|
-
content.
|
|
1235
|
+
content.classList.add('hidden');
|
|
1236
|
+
copyBtn.classList.add('hidden');
|
|
1205
1237
|
return;
|
|
1206
1238
|
}
|
|
1207
1239
|
|
|
1208
1240
|
panel.classList.remove('hidden');
|
|
1209
1241
|
empty.style.display = 'none';
|
|
1242
|
+
content.classList.remove('hidden');
|
|
1210
1243
|
content.style.display = 'flex';
|
|
1244
|
+
copyBtn.classList.remove('hidden');
|
|
1211
1245
|
|
|
1212
1246
|
const method = S.selected.method;
|
|
1213
1247
|
const fullUrl = buildUrl();
|
|
@@ -1320,6 +1354,65 @@ function renderSummary() {
|
|
|
1320
1354
|
\`;
|
|
1321
1355
|
}
|
|
1322
1356
|
|
|
1357
|
+
// ── Copy Summary ───────────────────────────────────────────────────
|
|
1358
|
+
function copySummary() {
|
|
1359
|
+
if (!S.selected) return;
|
|
1360
|
+
const r = S.selected;
|
|
1361
|
+
const lines = [];
|
|
1362
|
+
|
|
1363
|
+
lines.push(\`\${r.method} \${buildUrl()}\`);
|
|
1364
|
+
if (r.description) lines.push(\`\`, ...r.description.split('\\n').map(l => \`# \${l}\`));
|
|
1365
|
+
|
|
1366
|
+
if (r.params?.length) {
|
|
1367
|
+
lines.push(\`\`, \`[Path Params]\`);
|
|
1368
|
+
r.params.forEach(p => lines.push(\` \${p}: \${S.pathParams[p] || ''}\`));
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
const activeQuery = S.queryParams.filter(p => p.enabled && p.key);
|
|
1372
|
+
if (activeQuery.length) {
|
|
1373
|
+
lines.push(\`\`, \`[Query Params]\`);
|
|
1374
|
+
activeQuery.forEach(p => lines.push(\` \${p.key}: \${p.value}\`));
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
if (r.query?.length) {
|
|
1378
|
+
lines.push(\`\`, \`[Query Schema]\`);
|
|
1379
|
+
r.query.forEach(f => lines.push(\` \${f.name}: \${f.type}\${f.required ? ' (required)' : ''}\${f.rules?.length ? ' | ' + f.rules.join(', ') : ''}\${f.description ? ' — ' + f.description : ''}\`));
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
const activeHeaders = S.reqHeaders.filter(h => h.enabled && h.key);
|
|
1383
|
+
if (activeHeaders.length) {
|
|
1384
|
+
lines.push(\`\`, \`[Headers]\`);
|
|
1385
|
+
activeHeaders.forEach(h => lines.push(\` \${h.key}: \${h.value}\`));
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
if (r.headers?.length) {
|
|
1389
|
+
lines.push(\`\`, \`[Required Headers]\`);
|
|
1390
|
+
r.headers.forEach(f => lines.push(\` \${f.name}\${f.required ? ' (required)' : ''}\${f.description ? ' — ' + f.description : ''}\`));
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
if (r.body?.length) {
|
|
1394
|
+
lines.push(\`\`, \`[Body Schema]\`);
|
|
1395
|
+
r.body.forEach(f => lines.push(\` \${f.name}: \${f.type}\${f.required ? ' (required)' : ' (optional)'}\${f.rules?.length ? ' | ' + f.rules.join(', ') : ''}\${f.description ? ' — ' + f.description : ''}\`));
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
if (['POST','PUT','PATCH'].includes(r.method) && S.body.type !== 'none' && S.body.content) {
|
|
1399
|
+
lines.push(\`\`, \`[Body Content (\${S.body.type})]\`, S.body.content);
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
if (r.response?.length) {
|
|
1403
|
+
lines.push(\`\`, \`[Response Schema]\`);
|
|
1404
|
+
r.response.forEach(f => lines.push(\` \${f.name}: \${f.type}\${f.description ? ' — ' + f.description : ''}\`));
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
navigator.clipboard.writeText(lines.join('\\n')).then(() => {
|
|
1408
|
+
const btn = $('summary-copy-btn');
|
|
1409
|
+
const label = $('summary-copy-label');
|
|
1410
|
+
btn.classList.add('copied');
|
|
1411
|
+
label.textContent = 'Copied!';
|
|
1412
|
+
setTimeout(() => { btn.classList.remove('copied'); label.textContent = 'Copy'; }, 1800);
|
|
1413
|
+
});
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1323
1416
|
// Render a list of DocField items (body/query/headers/response) in the summary panel
|
|
1324
1417
|
function renderDocFields(label, fields) {
|
|
1325
1418
|
if (!fields || fields.length === 0) return '';
|
|
@@ -1487,6 +1580,8 @@ function bindEvents() {
|
|
|
1487
1580
|
el.baseUrl.addEventListener('input', () => { renderUrlBar(); renderSummary(); });
|
|
1488
1581
|
el.sendBtn.addEventListener('click', sendRequest);
|
|
1489
1582
|
|
|
1583
|
+
$('summary-copy-btn').addEventListener('click', copySummary);
|
|
1584
|
+
|
|
1490
1585
|
el.addQueryBtn.addEventListener('click', () => {
|
|
1491
1586
|
S.queryParams.push({ id: uid(), key: '', value: '', enabled: true });
|
|
1492
1587
|
renderQueryParams();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-explorer.html.js","sourceRoot":"","sources":["../src/api-explorer.html.ts"],"names":[],"mappings":";;AAEA,
|
|
1
|
+
{"version":3,"file":"api-explorer.html.js","sourceRoot":"","sources":["../src/api-explorer.html.ts"],"names":[],"mappings":";;AAEA,0CAknDC;AAlnDD,SAAgB,eAAe,CAAC,OAAmC;IACjE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IAChC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAE/C,OAAO,UAAU,CAAC;;;;;WAKT,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA80BC,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA0xBf,CAAC;AACT,CAAC"}
|
package/package.json
CHANGED