api-render-ui 1.1.0 → 1.1.2

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.js CHANGED
@@ -5,7 +5,6 @@ var GLOBAL_STYLES = `.codigma-apioperatorlist {
5
5
  display: inline-flex;
6
6
  flex-direction: column;
7
7
  gap: 5px;
8
- height: 100%;
9
8
  justify-content: flex-start;
10
9
  width: 100%
11
10
  }
@@ -62,7 +61,6 @@ var GLOBAL_STYLES = `.codigma-apioperatorlist {
62
61
  display: inline-flex;
63
62
  flex-direction: column;
64
63
  gap: 8px;
65
- height: 100%;
66
64
  justify-content: flex-start;
67
65
  width: 100%
68
66
  }
@@ -188,10 +186,12 @@ var GLOBAL_STYLES = `.codigma-apioperatorlist {
188
186
  align-items: center;
189
187
  align-self: stretch;
190
188
  display: inline-flex;
191
- height: 114px;
192
189
  justify-content: flex-start;
193
190
  padding-right: 5px
194
191
  }
192
+ .codigma-apiunit-request-body-info {
193
+ align-self: stretch;
194
+ }
195
195
  .codigma-apiunit-parakeyvalues {
196
196
  align-items: flex-start;
197
197
  align-self: stretch;
@@ -251,9 +251,11 @@ var GLOBAL_STYLES = `.codigma-apioperatorlist {
251
251
  }`;
252
252
 
253
253
  // src/api-render-ui.ts
254
- var ApiRenderer = class {
254
+ var ApiRenderer = class _ApiRenderer {
255
255
  options;
256
256
  container;
257
+ // 静态标志:记录是否已注入全局样式
258
+ static globalStyleInjected = false;
257
259
  constructor(options) {
258
260
  this.options = Object.assign({
259
261
  mountPoint: document?.body,
@@ -265,9 +267,12 @@ var ApiRenderer = class {
265
267
  }
266
268
  render(apiSpec, renderUnit = false) {
267
269
  const appendInlineStyle = (text) => {
268
- const styleEl = document.createElement("style");
269
- styleEl.textContent = text;
270
- document.head.appendChild(styleEl);
270
+ if (!_ApiRenderer.globalStyleInjected) {
271
+ const styleEl = document.createElement("style");
272
+ styleEl.textContent = text;
273
+ document.head.appendChild(styleEl);
274
+ _ApiRenderer.globalStyleInjected = true;
275
+ }
271
276
  };
272
277
  appendInlineStyle(GLOBAL_STYLES);
273
278
  const elementMap = /* @__PURE__ */ new Map();
@@ -342,12 +347,47 @@ var ApiRenderer = class {
342
347
  mountElement.appendChild(this.container);
343
348
  }
344
349
  };
350
+ var auths = [
351
+ {
352
+ value: "No Auth"
353
+ },
354
+ {
355
+ value: "Basic Auth",
356
+ parameters: [
357
+ {
358
+ name: "userName",
359
+ value: ""
360
+ },
361
+ {
362
+ name: "password",
363
+ value: ""
364
+ }
365
+ ]
366
+ },
367
+ {
368
+ value: "OAuth 2.0"
369
+ }
370
+ ];
371
+ var grantTypes = [
372
+ { value: "authorization_code" },
373
+ { value: "Implicit" },
374
+ { value: "Resource Owner Password Credentials" },
375
+ { value: "client_credentials" }
376
+ ];
377
+ var clientAuthenticationOpts = [
378
+ { value: "Headers", displayName: "Send credentials in headers" },
379
+ { value: "Body", displayName: "Send credentials in body" }
380
+ ];
381
+ var consumeOpts = [
382
+ { value: "None" },
383
+ { value: "application/json" },
384
+ { value: "application/xml" },
385
+ { value: "application/x-www-form-urlencoded" },
386
+ { value: "multipart/form-data" },
387
+ { value: "text/plain" }
388
+ ];
345
389
  function renderApiUnit(apiOperator, containerRef, elementMap) {
346
390
  return function(evt) {
347
- console.log("\u70B9\u51FB\u7684API\u64CD\u4F5C\uFF1A");
348
- console.log("\u65B9\u6CD5:", apiOperator.method);
349
- console.log("URL:", apiOperator.url);
350
- console.log("------------------------");
351
391
  const currentTarget = evt.currentTarget;
352
392
  if (elementMap.has(currentTarget)) {
353
393
  const newElement = elementMap.get(currentTarget);
@@ -378,7 +418,7 @@ function createApiUnit(apiOperator) {
378
418
  const paramSection = createParamSection(apiOperator);
379
419
  const headerSection = createSectionHeader(apiOperator);
380
420
  const authSection = createSectionAuth(apiOperator);
381
- const bodySection = createSectionRequestBody(apiOperator.requestBody);
421
+ const bodySection = createSectionRequestBody(apiOperator);
382
422
  reqContent.append(paramSection, headerSection, authSection, bodySection);
383
423
  apiContainer.appendChild(reqContent);
384
424
  apiContainer.appendChild(responseSection);
@@ -409,7 +449,6 @@ function createReqOperator(apiOperator) {
409
449
  reqUrl.className = "Requrl codigma-apiunit-requrl";
410
450
  reqUrl.value = apiOperator.url;
411
451
  reqUrl.addEventListener("input", (e) => {
412
- console.log("\u5F53\u524D\u503C:", e.target.value);
413
452
  apiOperator.url = e.target.value;
414
453
  });
415
454
  reqOperator.appendChild(reqUrl);
@@ -422,7 +461,6 @@ function createReqOperator(apiOperator) {
422
461
  sendText.textContent = "Send";
423
462
  sendButton.appendChild(sendText);
424
463
  sendButton.addEventListener("click", (e) => {
425
- console.log("\u5F53\u524D\u503C:", e.target.value);
426
464
  const respRef = apiOperator._responseSectionRef || null;
427
465
  sendRequest(apiOperator, respRef);
428
466
  });
@@ -489,17 +527,135 @@ function createSectionAuth(apiOperator) {
489
527
  const authValues = document.createElement("div");
490
528
  authValues.setAttribute("data-layer", "paraKeyValues");
491
529
  authValues.className = "Parakeyvalues codigma-apiunit-parakeyvalues";
492
- let auths = apiOperator.auths || [];
493
- const authTypeRow = createSelectRow(auths, authValues);
494
- if (auths.length > 0) {
495
- let parameters = apiOperator.auths[0].parameters || [];
496
- const authRows = parameters.map((parameter) => createRow(parameter));
497
- authValues.append(authTypeRow, ...authRows);
498
- }
530
+ const authTypeRow = createSelectRow("Authorization Type", auths);
531
+ authTypeRow.children[1].addEventListener("change", function(event) {
532
+ authValues && Array.from(authValues.children).slice(1).forEach((el) => el.remove());
533
+ const auth = auths[event.target.selectedIndex];
534
+ if (auth.value == "No Auth") {
535
+ } else if (auth.value == "Basic Auth") {
536
+ apiOperator.auth = [
537
+ {
538
+ name: "userName",
539
+ value: ""
540
+ },
541
+ {
542
+ name: "password",
543
+ value: ""
544
+ }
545
+ ];
546
+ const authRows = apiOperator.auth.map((parameter) => createRow(parameter));
547
+ authValues.append(...authRows);
548
+ } else if (auth.value == "OAuth 2.0") {
549
+ apiOperator.auth = {};
550
+ renderAuthForm(apiOperator, authValues, authTypeRow);
551
+ }
552
+ });
553
+ authValues.append(authTypeRow);
499
554
  authSection.append(authCnr, authValues);
500
555
  return authSection;
501
556
  }
502
- function createSectionRequestBody(requestBody) {
557
+ function createElement(tag, props = {}, classes = []) {
558
+ const el = document.createElement(tag);
559
+ Object.entries(props).forEach(([key, value]) => el.setAttribute(key, value));
560
+ if (classes.length) el.classList.add(...classes);
561
+ return el;
562
+ }
563
+ function createLabeledInput(apiOperator, labelText, inputId, inputName, modelKey, required = false) {
564
+ const wrapper = createElement("div", {}, ["Keyvalue", "codigma-apiunit-keyvalue"]);
565
+ const label = createElement("label", { for: inputId }, ["type", "codigma-apiunit-send"]);
566
+ label.textContent = labelText + ":";
567
+ const input = createElement("input", {
568
+ type: "text",
569
+ id: inputId,
570
+ name: inputName,
571
+ autocomplete: "off",
572
+ ...required ? { required: "true" } : {}
573
+ }, ["Valuetext", "codigma-apiunit-valuetext"]);
574
+ input.value = apiOperator.auth[modelKey] || "";
575
+ input.addEventListener("input", (e) => {
576
+ apiOperator.auth[modelKey] = e.target.value;
577
+ });
578
+ wrapper.appendChild(label);
579
+ wrapper.appendChild(input);
580
+ return wrapper;
581
+ }
582
+ function createSelect(apiOperator, labelText, selectId, options, modelKey, changeHandler) {
583
+ const wrapper = createElement("div", {}, ["Keyvalue", "codigma-apiunit-keyvalue"]);
584
+ const label = createElement("label", { for: selectId }, ["type", "codigma-apiunit-send"]);
585
+ label.textContent = labelText + ":";
586
+ const select = createElement("select", {
587
+ id: selectId,
588
+ name: selectId
589
+ }, []);
590
+ options.forEach((opt) => {
591
+ const option = createElement("option", { value: opt.value });
592
+ option.textContent = opt.displayName || opt.value;
593
+ select.appendChild(option);
594
+ });
595
+ select.value = apiOperator.auth[modelKey] || options[0]?.value || "";
596
+ select.addEventListener("change", (e) => {
597
+ const val = e.target.value;
598
+ changeHandler(val);
599
+ });
600
+ wrapper.appendChild(label);
601
+ wrapper.appendChild(select);
602
+ return wrapper;
603
+ }
604
+ function renderAuthForm(apiOperator, authValues, authTypeRow) {
605
+ authValues.innerHTML = "";
606
+ authValues.append(authTypeRow);
607
+ authValues.appendChild(createLabeledInput(apiOperator, "Token", "token", "token", "token", true));
608
+ authValues.appendChild(
609
+ createSelect(
610
+ apiOperator,
611
+ "Grant Type",
612
+ "grantType",
613
+ grantTypes,
614
+ "grantType",
615
+ (value) => {
616
+ apiOperator.auth.grantType = value;
617
+ renderAuthForm(apiOperator, authValues, authTypeRow);
618
+ }
619
+ )
620
+ );
621
+ const gt = apiOperator.auth.grantType || "authorization_code";
622
+ if (gt === "authorization_code" || gt === "Implicit") {
623
+ authValues.appendChild(createLabeledInput(apiOperator, "Authorization Endpoint", "authorizationEndpoint", "authorizationEndpoint", "authorizationEndpoint", true));
624
+ authValues.appendChild(createLabeledInput(apiOperator, "Redirect URL", "RedirectURI", "RedirectURI", "redirectURI", true));
625
+ }
626
+ if (gt === "authorization_code" || gt === "client_credentials" || gt === "Resource Owner Password Credentials") {
627
+ authValues.appendChild(createLabeledInput(apiOperator, "Token Endpoint", "TokenEndpoint", "TokenEndpoint", "tokenEndpoint", true));
628
+ }
629
+ authValues.appendChild(createLabeledInput(apiOperator, "Client ID", "ClientID", "ClientID", "clientId", true));
630
+ if (gt === "authorization_code" || gt === "client_credentials" || gt === "Resource Owner Password Credentials") {
631
+ authValues.appendChild(createLabeledInput(apiOperator, "Client Secret", "ClientSecret", "ClientSecret", "clientSecret", true));
632
+ }
633
+ if (gt === "Resource Owner Password Credentials") {
634
+ authValues.appendChild(createLabeledInput(apiOperator, "Username", "Username", "Username", "username", true));
635
+ authValues.appendChild(createLabeledInput(apiOperator, "Password", "Password", "Password", "password", true));
636
+ }
637
+ authValues.appendChild(createLabeledInput(apiOperator, "Scopes", "Scopes", "Scopes", "scopes", true));
638
+ authValues.appendChild(
639
+ createSelect(
640
+ apiOperator,
641
+ "Client Authentication",
642
+ "clientAuthentication",
643
+ clientAuthenticationOpts,
644
+ "clientAuthentication",
645
+ (value) => {
646
+ apiOperator.auth.clientAuthentication = value;
647
+ }
648
+ )
649
+ );
650
+ const buttonWrapper = createElement("div", {}, ["parameter-item"]);
651
+ const generateBtn = createElement("button", {}, ["parameter-button"]);
652
+ generateBtn.type = "button";
653
+ generateBtn.textContent = "Generate Token";
654
+ generateBtn.addEventListener("click", () => generateOAuth2Token(apiOperator));
655
+ buttonWrapper.appendChild(generateBtn);
656
+ authValues.appendChild(buttonWrapper);
657
+ }
658
+ function createSectionRequestBody(apiOperator) {
503
659
  const bodySection = document.createElement("div");
504
660
  bodySection.setAttribute("data-layer", "request-body-section");
505
661
  bodySection.className = "RequestBodySection codigma-apiunit-request-body-section";
@@ -512,13 +668,108 @@ function createSectionRequestBody(requestBody) {
512
668
  bodyText.textContent = "Body";
513
669
  bodyCnr.appendChild(bodyText);
514
670
  bodySection.appendChild(bodyCnr);
515
- const bodyValue = document.createElement("textarea");
516
- bodyValue.setAttribute("data-layer", "bodyTextValue");
517
- bodyValue.className = "Id0CategoryId0NameNamePhotourlsTagsId0NameStatusAvailable codigma-apiunit-parakeyvalues";
518
- bodyValue.value = JSON.stringify(requestBody);
519
- bodySection.appendChild(bodyValue);
671
+ renderConsumeSection(apiOperator, bodySection, bodyCnr);
520
672
  return bodySection;
521
673
  }
674
+ function createConsumeSelect(apiOperator, container, bodyCnr) {
675
+ const wrapper = createElement("div");
676
+ const label = createElement("label");
677
+ label.style.margin = "0 1rem";
678
+ label.textContent = "Content-Type";
679
+ const select = createElement("select");
680
+ select.style.width = "18rem";
681
+ consumeOpts.forEach((opt) => {
682
+ const option = document.createElement("option");
683
+ option.value = opt.value;
684
+ option.textContent = opt.value;
685
+ select.appendChild(option);
686
+ });
687
+ select.value = apiOperator.currentConsume || getCurrentConsume(apiOperator);
688
+ select.addEventListener("change", (e) => {
689
+ const newValue = e.target.value;
690
+ if (apiOperator.currentConsume !== newValue) {
691
+ apiOperator.currentConsume = newValue;
692
+ renderConsumeSection(apiOperator, container, bodyCnr);
693
+ }
694
+ });
695
+ wrapper.appendChild(label);
696
+ wrapper.appendChild(select);
697
+ return wrapper;
698
+ }
699
+ function renderRequestBodyInto(apiOperator, targetDiv) {
700
+ targetDiv.innerHTML = "";
701
+ const ct = apiOperator.currentConsume || getCurrentConsume(apiOperator);
702
+ if (ct === null || ct === "None" || ct === "application/json" || ct === "application/xml" || ct === "text/plain") {
703
+ const mimeType = ct || "None";
704
+ let rawValue = apiOperator.requestBody.content[mimeType];
705
+ if (rawValue == null) {
706
+ rawValue = "";
707
+ apiOperator.requestBody.content[mimeType] = rawValue;
708
+ }
709
+ const textarea = createElement("textarea", {}, []);
710
+ textarea.style.width = "100%";
711
+ textarea.style.height = "200px";
712
+ textarea.style.fontFamily = "monospace";
713
+ textarea.style.fontSize = "14px";
714
+ textarea.placeholder = `Enter ${mimeType} body...`;
715
+ textarea.value = rawValue;
716
+ textarea.addEventListener("input", () => {
717
+ apiOperator.requestBody.content[mimeType] = textarea.value;
718
+ console.log(`Content updated for ${mimeType}:`, textarea.value);
719
+ });
720
+ targetDiv.appendChild(textarea);
721
+ } else if ((ct === "application/x-www-form-urlencoded" || ct === "multipart/form-data") && apiOperator.requestBody.content && Array.isArray(apiOperator.requestBody.content[ct])) {
722
+ const params = apiOperator.requestBody.content[ct];
723
+ params.forEach((param, index) => {
724
+ const item = createElement("div", {}, ["Keyvalue", "codigma-apiunit-keyvalue"]);
725
+ const label = createElement("label", { for: `param-${Date.now()}-${index}` }, ["petId", "codigma-apiunit-send"]);
726
+ label.textContent = `${param.name}:`;
727
+ const input = createElement("input", {
728
+ type: param.uiType || "text",
729
+ // 使用时间戳+索引避免 id 冲突(仅用于 label for)
730
+ id: `param-${Date.now()}-${index}`,
731
+ name: "name"
732
+ }, ["Valuetext", "codigma-apiunit-valuetext"]);
733
+ input.value = param.value || "";
734
+ input.autocomplete = "off";
735
+ input.required = true;
736
+ input.addEventListener("keydown", (e) => {
737
+ setEditStatus(e, true);
738
+ });
739
+ input.addEventListener("input", () => {
740
+ param.value = input.value;
741
+ });
742
+ item.appendChild(label);
743
+ item.appendChild(input);
744
+ targetDiv.appendChild(item);
745
+ });
746
+ }
747
+ }
748
+ function getCurrentConsume(apiOperator) {
749
+ if (!apiOperator.requestBody) {
750
+ apiOperator.requestBody = { content: {} };
751
+ }
752
+ if (!apiOperator.requestBody.content) {
753
+ apiOperator.requestBody.content = {};
754
+ }
755
+ const keys = Object.keys(apiOperator.requestBody.content);
756
+ const ct = apiOperator.currentConsume = keys.length > 0 ? keys[0] : "None";
757
+ return ct;
758
+ }
759
+ function setEditStatus(event, status) {
760
+ console.log("setEditStatus called:", event.key, status);
761
+ }
762
+ function renderConsumeSection(apiOperator, container, bodyCnr) {
763
+ container.innerHTML = "";
764
+ container.appendChild(bodyCnr);
765
+ const wrapperDiv = createElement("div", {}, ["codigma-apiunit-parakeyvalues"]);
766
+ const selectWrapper = createConsumeSelect(apiOperator, container, bodyCnr);
767
+ wrapperDiv.appendChild(selectWrapper);
768
+ const reqBodyContainer = createElement("div", {}, ["codigma-apiunit-request-body-info"]);
769
+ renderRequestBodyInto(apiOperator, reqBodyContainer);
770
+ wrapperDiv.appendChild(reqBodyContainer);
771
+ container.appendChild(wrapperDiv);
772
+ }
522
773
  function createSectionResponse(apiOperator) {
523
774
  const responseSection = document.createElement("div");
524
775
  responseSection.setAttribute("data-layer", "reqresponse");
@@ -553,6 +804,9 @@ function createTimeStatusElement(apiOperator) {
553
804
  updateTimeStatus(timeStatus, apiOperator);
554
805
  return timeStatus;
555
806
  }
807
+ function updateTimeStatus(timeStatus, apiOperator) {
808
+ timeStatus.textContent = `Status: ${apiOperator.response.status || ""} ${apiOperator.response.statusText || ""} Time: ${apiOperator.requestDuration || ""}`;
809
+ }
556
810
  function createRow(parameter) {
557
811
  const petIdRow = document.createElement("div");
558
812
  petIdRow.setAttribute("data-layer", "keyValue");
@@ -566,7 +820,6 @@ function createRow(parameter) {
566
820
  petIdValue.className = "Valuetext codigma-apiunit-valuetext";
567
821
  petIdValue.value = parameter["value"] || "";
568
822
  petIdValue.addEventListener("input", (e) => {
569
- console.log("\u5F53\u524D\u503C:", e.target.value);
570
823
  parameter["value"] = e.target.value;
571
824
  });
572
825
  petIdRow.append(petIdLabel, petIdValue);
@@ -580,31 +833,24 @@ function createInputElement() {
580
833
  inputText.setAttribute("autocomplete", "off");
581
834
  return inputText;
582
835
  }
583
- function createSelectRow(auths, authValues) {
836
+ function createSelectRow(name, args) {
584
837
  const container = document.createElement("div");
585
838
  container.setAttribute("data-layer", "keyValue");
586
839
  container.className = "Keyvalue codigma-apiunit-keyvalue";
587
840
  const typeLabel = document.createElement("div");
588
- typeLabel.setAttribute("data-layer", "type");
841
+ typeLabel.setAttribute("data-layer", name);
589
842
  typeLabel.className = "type codigma-apiunit-send";
590
- typeLabel.textContent = "Type:";
843
+ typeLabel.textContent = name + ":";
591
844
  const selectElement = document.createElement("select");
592
845
  selectElement.name = "text-select";
593
846
  selectElement.label = "text-select";
594
847
  selectElement.setAttribute("data-layer", "valueText");
595
- auths.forEach((auth) => {
848
+ args.forEach((auth) => {
596
849
  const option1 = document.createElement("option");
597
- option1.value = auth["type"];
598
- option1.textContent = auth["type"];
850
+ option1.value = auth["value"];
851
+ option1.textContent = auth["displayName"] != null || auth["label"] != null ? auth["displayName"] || auth["label"] : auth["value"];
599
852
  selectElement.appendChild(option1);
600
853
  });
601
- selectElement.addEventListener("change", function(event) {
602
- authValues && Array.from(authValues.children).slice(1).forEach((el) => el.remove());
603
- const auth = auths[event.target.selectedIndex];
604
- let parameters = auth.parameters || [];
605
- const authRows = parameters.map((parameter) => createRow(parameter));
606
- authValues.append(...authRows);
607
- });
608
854
  container.appendChild(typeLabel);
609
855
  container.appendChild(selectElement);
610
856
  return container;
@@ -615,58 +861,153 @@ function isPathOrQueryParam(param) {
615
861
  function isHeaderParam(param) {
616
862
  return param.in === "header";
617
863
  }
618
- function sendRequest(apiOperator, responseSectionRef) {
619
- if (!responseSectionRef) {
620
- console.error("sendRequest: missing responseSectionRef. Aborting request to avoid runtime errors.");
621
- return;
864
+ async function generateOAuth2Token(apiInfo) {
865
+ const accessToken = await getAccessToken(apiInfo);
866
+ apiInfo.auth.token = accessToken;
867
+ }
868
+ async function getAccessToken(apiInfo) {
869
+ const auth = apiInfo.auth;
870
+ if (auth == null) {
871
+ throw new Error("OAuth2.0\u8BA4\u8BC1\u4FE1\u606F\u672A\u914D\u7F6E");
872
+ }
873
+ const CLIENT_ID = auth.clientId;
874
+ const CLIENT_SECRET = auth.clientSecret;
875
+ const SCOPE = auth.scopes;
876
+ if (apiInfo.auth.grantType == "client_credentials") {
877
+ try {
878
+ console.log("\u6B63\u5728\u83B7\u53D6\u8BBF\u95EE\u4EE4\u724C...");
879
+ const headerParams = {
880
+ "Content-Type": "application/x-www-form-urlencoded"
881
+ };
882
+ const bodyParams = new URLSearchParams();
883
+ bodyParams.append("grant_type", "client_credentials");
884
+ if (SCOPE) {
885
+ bodyParams.append("scope", SCOPE);
886
+ }
887
+ if (apiInfo.auth.clientAuthentication == "Body") {
888
+ bodyParams.append("client_id", CLIENT_ID);
889
+ bodyParams.append("client_secret", CLIENT_SECRET);
890
+ } else {
891
+ headerParams["Authorization"] = "Basic " + btoa(CLIENT_ID + ":" + CLIENT_SECRET);
892
+ }
893
+ const response = await fetch(auth.tokenEndpoint, {
894
+ method: "POST",
895
+ headers: headerParams,
896
+ body: bodyParams.toString()
897
+ });
898
+ if (!response.ok) {
899
+ const errorData = await response.json().catch(() => ({}));
900
+ throw new Error(`\u83B7\u53D6\u4EE4\u724C\u5931\u8D25: ${response.status} ${response.statusText}. ${JSON.stringify(errorData)}`);
901
+ }
902
+ const tokenData = await response.json();
903
+ console.log("\u4EE4\u724C\u83B7\u53D6\u6210\u529F:", tokenData);
904
+ return tokenData.access_token;
905
+ } catch (error) {
906
+ console.error("\u83B7\u53D6\u8BBF\u95EE\u4EE4\u724C\u65F6\u51FA\u9519:", error);
907
+ throw error;
908
+ }
909
+ } else if (apiInfo.auth.grantType == "Resource Owner Password Credentials") {
910
+ } else if (apiInfo.auth.grantType == "authorization_code") {
911
+ let getUrlParams2 = function() {
912
+ const params = new URLSearchParams(window.location.search);
913
+ return Object.fromEntries(params.entries());
914
+ }, redirectToAuth2 = function() {
915
+ const state = Math.random().toString(36).substring(2);
916
+ const nonce = Math.random().toString(36).substring(2);
917
+ const authUrl = new URL(config.authUrl);
918
+ authUrl.searchParams.append("client_id", config.clientId);
919
+ authUrl.searchParams.append("redirect_uri", config.redirectUri);
920
+ authUrl.searchParams.append("response_type", "code");
921
+ authUrl.searchParams.append("scope", config.scope);
922
+ authUrl.searchParams.append("state", state);
923
+ authUrl.searchParams.append("nonce", nonce);
924
+ authUrl.searchParams.append("access_type", "offline");
925
+ const newTab = window.open(authUrl.toString(), "_blank");
926
+ };
927
+ var getUrlParams = getUrlParams2, redirectToAuth = redirectToAuth2;
928
+ const config = {
929
+ clientId: apiInfo.auth.clientId,
930
+ // 替换为你的 client_id
931
+ clientSecret: apiInfo.auth.clientSecret,
932
+ // 替换为你的 client_secret
933
+ redirectUri: apiInfo.auth.redirectURI,
934
+ // 必须与注册的 redirect_uri 一致
935
+ authUrl: apiInfo.auth.authorizationEndpoint,
936
+ tokenUrl: apiInfo.auth.tokenEndpoint,
937
+ scope: apiInfo.auth.scopes
938
+ // 可选: 'openid profile email' 如果服务支持
939
+ };
940
+ redirectToAuth2();
941
+ } else if (apiInfo.auth.grantType == "Implicit") {
942
+ } else {
622
943
  }
623
- let reuqestUrl = getRequestUrl(apiOperator);
624
- const result = checkIfParameter(apiOperator);
625
- let header = result.hasRequestBody ? "application/json" : result.hasRequestFormData ? "application/x-www-form-urlencoded" : "application/json";
944
+ }
945
+ function getBodyEditorContent(apiOperator) {
946
+ const ct = apiOperator.currentConsume || "None";
947
+ return apiOperator.requestBody.content[ct];
948
+ }
949
+ var gotResponse = false;
950
+ var ifSendingRequest = false;
951
+ var requestDuration = "0";
952
+ var responseObj = {};
953
+ function sendRequest(apiOperator, responseSectionRef) {
954
+ const apiInfo = apiOperator;
955
+ let reuqestUrl = getRequestUrl(apiInfo);
956
+ let header = apiInfo["parameterHasFormDataVer2"] ? "application/x-www-form-urlencoded" : apiInfo["parameterHasBody"] ? apiInfo["currentConsume"] : "application/json";
626
957
  let headers = {
627
958
  "Content-Type": header
628
959
  };
629
- if (apiOperator.custom) {
630
- for (let index = 0; index < apiOperator.customHeaderparameters.length; index++) {
631
- const paras = apiOperator.customHeaderparameters[index];
632
- if (paras.name != "" && paras.value != "" && paras.name != null && paras.value != null) {
633
- headers[paras.name] = paras.value;
960
+ const headerParas = getHeadersParams(apiInfo, apiInfo.rawApiInfo.parameters || []);
961
+ Object.assign(headers, headerParas);
962
+ addAuthHeader(apiInfo, headers);
963
+ let body;
964
+ if (apiInfo.method.toUpperCase() == "POST" || apiInfo.method.toUpperCase() == "PUT") {
965
+ if (apiInfo["currentConsume"] == "application/json" && apiInfo.requestBody != null) {
966
+ body = getBodyEditorContent(apiOperator);
967
+ } else if (apiInfo["parameterHasFormDataVer2"]) {
968
+ body = getRequestFormData(apiInfo.rawApiInfo);
969
+ } else if (apiInfo["currentConsume"] == "application/x-www-form-urlencoded") {
970
+ for (const key of apiInfo["requestBody"]["content"][apiInfo["currentConsume"]]) {
971
+ if (body == null || body == "") {
972
+ body = key.name + "=" + key.value;
973
+ } else {
974
+ body = body + "&" + key.name + "=" + key.value;
975
+ }
634
976
  }
977
+ } else {
978
+ body = "";
635
979
  }
980
+ } else {
981
+ body = "";
636
982
  }
637
- let body = result.hasRequestBody ? apiOperator.requestBody : result.hasRequestFormData ? getRequestFormData(apiOperator.rawApiInfo) : null;
638
- if (apiOperator.custom) {
639
- if (apiOperator.method.toUpperCase() == "POST" || apiOperator.method.toUpperCase() == "PUT") {
640
- body = apiOperator.requestBody;
641
- }
642
- }
643
- apiOperator.ifSendingRequest = true;
983
+ ifSendingRequest = true;
644
984
  const startTime = Date.now();
645
985
  apiOperator.controller = new AbortController();
646
986
  const signal = apiOperator.controller.signal;
647
987
  const overlayLayerContainer = createRequestOverlayLayer(apiOperator, responseSectionRef);
648
988
  fetch(reuqestUrl, {
649
- method: apiOperator.method.toUpperCase(),
989
+ method: apiInfo.method.toUpperCase(),
650
990
  headers,
651
- body: body != null ? JSON.stringify(body) : null,
991
+ body,
652
992
  signal
653
993
  }).then((response) => {
654
994
  if (!response.ok) {
655
- apiOperator.response = {
995
+ responseObj = {
656
996
  status: response.status,
657
- statusText: response.statusText
997
+ statusText: response.statusText,
998
+ body: ""
658
999
  };
659
1000
  const endTime2 = Date.now();
660
- apiOperator.requestDuration = formatDuration(endTime2 - startTime);
661
- apiOperator.ifSendingRequest = false;
1001
+ requestDuration = formatDuration(endTime2 - startTime);
1002
+ ifSendingRequest = false;
662
1003
  throw new Error("Network response was not ok.");
663
1004
  }
664
1005
  const endTime = Date.now();
665
- apiOperator.requestDuration = formatDuration(endTime - startTime);
1006
+ requestDuration = formatDuration(endTime - startTime);
666
1007
  const responsebodyElement = responseSectionRef.querySelector('[data-layer="responsebody"]');
667
1008
  responsebodyElement.removeChild(overlayLayerContainer);
668
- apiOperator.ifSendingRequest = false;
669
- apiOperator.response = {
1009
+ ifSendingRequest = false;
1010
+ responseObj = {
670
1011
  status: response.status,
671
1012
  statusText: response.statusText
672
1013
  };
@@ -681,22 +1022,20 @@ function sendRequest(apiOperator, responseSectionRef) {
681
1022
  return responseClone.text();
682
1023
  });
683
1024
  }).then((data) => {
684
- apiOperator.gotResponse = true;
1025
+ gotResponse = true;
685
1026
  const responsebodyElement = responseSectionRef.querySelector('[data-layer="responsebody"]');
686
1027
  if (typeof data === "object") {
687
1028
  console.log("Received JSON:", data);
688
- responsebodyElement.textContent = JSON.stringify(data, null, 4);
1029
+ responseObj.body = JSON.stringify(data, null, 4);
689
1030
  } else {
690
1031
  console.log("Received text:", data);
691
- responsebodyElement.textContent = data;
1032
+ responseObj.body = data;
692
1033
  }
1034
+ responsebodyElement.textContent = responseObj.body;
693
1035
  }).catch((error) => {
694
1036
  console.error("There has been a problem with your fetch operation:", error);
695
1037
  });
696
1038
  }
697
- function updateTimeStatus(timeStatus, apiOperator) {
698
- timeStatus.textContent = `Status: ${apiOperator.response.status || ""} ${apiOperator.response.statusText || ""} Time: ${apiOperator.requestDuration || ""}`;
699
- }
700
1039
  function createRequestOverlayLayer(apiOperator, responseSectionRef) {
701
1040
  const container = document.createElement("div");
702
1041
  Object.assign(container.style, {
@@ -739,28 +1078,6 @@ function createRequestOverlayLayer(apiOperator, responseSectionRef) {
739
1078
  });
740
1079
  return container;
741
1080
  }
742
- function checkIfParameter(apiOperator) {
743
- let hasRequestBody = false;
744
- let hasRequestFormData = false;
745
- const parameters = apiOperator.rawApiInfo.parameters;
746
- if (parameters) {
747
- for (let index = 0; index < parameters.length; index++) {
748
- const parameter = parameters[index];
749
- if (parameter.in == "query" || parameter.in == "path") {
750
- } else if (parameter.in == "body") {
751
- hasRequestBody = true;
752
- parameter.name = parameter.name.charAt(0).toUpperCase() + parameter.name.slice(1);
753
- } else if (parameter.in == "formData") {
754
- hasRequestFormData = true;
755
- }
756
- }
757
- }
758
- const requestBody = apiOperator.rawApiInfo.requestBody;
759
- if (requestBody) {
760
- hasRequestBody = true;
761
- }
762
- return { hasRequestBody, hasRequestFormData };
763
- }
764
1081
  function formatDuration(milliseconds) {
765
1082
  let totalSeconds = Math.floor(milliseconds / 1e3);
766
1083
  let seconds = totalSeconds % 60;
@@ -773,9 +1090,9 @@ function formatDuration(milliseconds) {
773
1090
  seconds = seconds.toString().padStart(2, "0");
774
1091
  return `${hours}h${minutes}m${seconds}s${millisecondsPart}ms`;
775
1092
  }
776
- function getRequestUrl(apiOperator) {
777
- let reuqestUrl = apiOperator.url;
778
- const requestParameters = apiOperator.rawApiInfo.parameters || [];
1093
+ function getRequestUrl(apiInfo) {
1094
+ let reuqestUrl = apiInfo.url;
1095
+ const requestParameters = apiInfo.rawApiInfo.parameters || [];
779
1096
  if (requestParameters == null) {
780
1097
  return reuqestUrl;
781
1098
  }
@@ -784,11 +1101,45 @@ function getRequestUrl(apiOperator) {
784
1101
  reuqestUrl = reuqestUrl.replace("{" + element.name + "}", element.value);
785
1102
  }
786
1103
  }
787
- let queryParams = getQueryParams(apiOperator, requestParameters);
1104
+ let queryParams = getQueryParams(apiInfo, requestParameters);
788
1105
  reuqestUrl = queryParams.length > 0 ? reuqestUrl + "?" + queryParams.join("&") : reuqestUrl;
789
1106
  return reuqestUrl;
790
1107
  }
791
- function getQueryParams(apiOperator, requestParameters) {
1108
+ function addAuthHeader(apiInfo, headers) {
1109
+ const env = isBrowserEnvironment();
1110
+ if (apiInfo.auth.authType == "Basic Auth" && apiInfo.auth != null) {
1111
+ if (env) {
1112
+ const credentials = btoa(`${apiInfo.auth.username}:${apiInfo.auth.passWord}`);
1113
+ headers["Authorization"] = `Basic ${credentials}`;
1114
+ } else {
1115
+ const buffer = Buffer.from(`${apiInfo.auth.username}:${apiInfo.auth.passWord}`);
1116
+ const credentials = buffer.toString("base64");
1117
+ headers["Authorization"] = `Basic ${credentials}`;
1118
+ }
1119
+ } else if (apiInfo.auth.authType == "OAuth 2.0" && apiInfo.auth != null) {
1120
+ if (apiInfo.auth.token != null || apiInfo.auth.token != "") {
1121
+ headers["Authorization"] = `Bearer ${apiInfo.auth.token}`;
1122
+ }
1123
+ }
1124
+ }
1125
+ function getHeadersParams(apiInfo, requestParameters) {
1126
+ let headersParams = [];
1127
+ for (const element of requestParameters) {
1128
+ if (element.in == "header") {
1129
+ headersParams[element.name] = element.value;
1130
+ }
1131
+ }
1132
+ if (apiInfo.customHeaderparameters) {
1133
+ for (let index = 0; index < apiInfo.customHeaderparameters.length; index++) {
1134
+ const paras = apiInfo.customHeaderparameters[index];
1135
+ if (paras.name != "" && paras.value != "" && paras.name != null && paras.value != null) {
1136
+ headersParams[paras.name] = paras.value;
1137
+ }
1138
+ }
1139
+ }
1140
+ return headersParams;
1141
+ }
1142
+ function getQueryParams(apiInfo, requestParameters) {
792
1143
  let queryParams = [];
793
1144
  for (const element of requestParameters) {
794
1145
  if (element.in == "query") {
@@ -803,9 +1154,9 @@ function getQueryParams(apiOperator, requestParameters) {
803
1154
  }
804
1155
  }
805
1156
  }
806
- if (apiOperator.custom) {
807
- for (let index = 0; index < apiOperator.customQueryparameters.length; index++) {
808
- const paras = apiOperator.customQueryparameters[index];
1157
+ if (apiInfo.customQueryparameters) {
1158
+ for (let index = 0; index < apiInfo.customQueryparameters.length; index++) {
1159
+ const paras = apiInfo.customQueryparameters[index];
809
1160
  if (paras.name != "" && paras.value != "" && paras.name != null && paras.value != null) {
810
1161
  queryParams.push(paras.name + "=" + paras.value);
811
1162
  }
@@ -832,6 +1183,15 @@ function getRequestFormData(rawApiInfo) {
832
1183
  }
833
1184
  return formData;
834
1185
  }
1186
+ function isBrowserEnvironment() {
1187
+ if (typeof window !== "undefined" && typeof document !== "undefined") {
1188
+ return true;
1189
+ } else if (typeof process !== "undefined" && process.versions && process.versions.node) {
1190
+ return false;
1191
+ } else {
1192
+ return false;
1193
+ }
1194
+ }
835
1195
  function createSvg() {
836
1196
  const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
837
1197
  svg.setAttribute("width", "21");
@@ -850,18 +1210,16 @@ function createSvg() {
850
1210
  }
851
1211
  function parseParaModel(parameterObj, dataDef) {
852
1212
  let bodyModel;
853
- if (parameterObj && parameterObj.schema) {
854
- if (parameterObj.schema["$ref"]) {
855
- bodyModel = parseModel(parameterObj.schema["$ref"], dataDef);
856
- } else if (parameterObj.schema["type"] == "array") {
857
- const itemObj = parameterObj.schema["items"];
858
- if (itemObj["$ref"]) {
859
- bodyModel = parseModel(itemObj["$ref"], dataDef);
860
- } else if (itemObj["type"]) {
861
- bodyModel = parseElement(itemObj);
862
- }
863
- bodyModel = [bodyModel];
1213
+ if (parameterObj.schema["$ref"]) {
1214
+ bodyModel = parseModel(parameterObj.schema["$ref"], dataDef);
1215
+ } else if (parameterObj.schema["type"] == "array") {
1216
+ const itemObj = parameterObj.schema["items"];
1217
+ if (itemObj["$ref"]) {
1218
+ bodyModel = parseModel(itemObj["$ref"], dataDef);
1219
+ } else if (itemObj["type"]) {
1220
+ bodyModel = parseElement(itemObj);
864
1221
  }
1222
+ bodyModel = [bodyModel];
865
1223
  }
866
1224
  return bodyModel;
867
1225
  }
@@ -892,10 +1250,66 @@ function parseModel(modelDef, apiDef) {
892
1250
  }
893
1251
  return model;
894
1252
  }
1253
+ function parseFormDataModel(modelDef, apiDef) {
1254
+ const model = [];
1255
+ const bodyName = modelDef.substring(modelDef.lastIndexOf("/") + 1);
1256
+ const def = apiDef[bodyName];
1257
+ const props = def["properties"];
1258
+ if (props) {
1259
+ for (const key in props) {
1260
+ if (Object.prototype.hasOwnProperty.call(props, key)) {
1261
+ const element = props[key];
1262
+ let modelEle;
1263
+ if (element.hasOwnProperty("items") && element["type"] == "array") {
1264
+ if (element["items"]["$ref"]) {
1265
+ modelEle = [parseModel(element["items"]["$ref"], apiDef)];
1266
+ } else if (element["items"]["type"]) {
1267
+ modelEle = [parseElement(element["items"])];
1268
+ }
1269
+ if (modelEle) {
1270
+ model.push({
1271
+ type: "string",
1272
+ uiType: "text",
1273
+ name: key,
1274
+ value: JSON.stringify(modelEle)
1275
+ });
1276
+ }
1277
+ } else if (element["type"]) {
1278
+ model.push({
1279
+ type: element["type"],
1280
+ uiType: element["type"] == "integer" || element["type"] == "number" ? "number" : "text",
1281
+ name: key,
1282
+ value: parseElement(element)
1283
+ });
1284
+ } else if (element["$ref"]) {
1285
+ const bodyModel = parseModel(element["$ref"], apiDef);
1286
+ model.push({
1287
+ type: "string",
1288
+ uiType: "text",
1289
+ name: key,
1290
+ value: JSON.stringify(bodyModel)
1291
+ });
1292
+ }
1293
+ }
1294
+ }
1295
+ }
1296
+ return model;
1297
+ }
1298
+ function parseFormDataParaModel(parameterObj, dataDef) {
1299
+ let bodyModel = [];
1300
+ if (parameterObj.schema["$ref"]) {
1301
+ bodyModel = parseFormDataModel(parameterObj.schema["$ref"], dataDef);
1302
+ }
1303
+ return bodyModel;
1304
+ }
895
1305
  function parseElement(element) {
896
1306
  let elementValue;
897
1307
  if (element["type"].includes("integer")) {
898
- elementValue = 0;
1308
+ if (element["enum"]) {
1309
+ elementValue = element["enum"][0];
1310
+ } else {
1311
+ elementValue = 0;
1312
+ }
899
1313
  } else if (element["type"].includes("boolean")) {
900
1314
  elementValue = false;
901
1315
  } else if (element["type"].includes("string")) {
@@ -905,11 +1319,24 @@ function parseElement(element) {
905
1319
  elementValue = "";
906
1320
  }
907
1321
  }
1322
+ if (element["default"]) {
1323
+ elementValue = element["default"];
1324
+ }
908
1325
  if (element["example"]) {
909
1326
  elementValue = element["example"];
910
1327
  }
911
1328
  return elementValue;
912
1329
  }
1330
+ function parseElementType(element) {
1331
+ if (element["type"].includes("integer")) {
1332
+ return "integer";
1333
+ } else if (element["type"].includes("boolean")) {
1334
+ return "boolean";
1335
+ } else if (element["type"].includes("string")) {
1336
+ return "string";
1337
+ }
1338
+ return "string";
1339
+ }
913
1340
  var HTTP_METHODS = ["get", "put", "post", "delete", "options", "head", "patch", "trace"];
914
1341
  function isHttpMethod(method) {
915
1342
  return HTTP_METHODS.includes(method);
@@ -938,48 +1365,90 @@ function parseOpenAPI(openapiSpec) {
938
1365
  const apiOperator = {
939
1366
  method: method.toUpperCase(),
940
1367
  url: path,
941
- rawApiInfo: null,
1368
+ rawApiInfo: operation,
942
1369
  requestBody: null,
943
1370
  response: {},
944
- auths: [
945
- {
946
- type: "No Auth"
947
- },
948
- {
949
- type: "Basic Auth",
950
- parameters: [
951
- {
952
- name: "userName",
953
- value: ""
954
- },
955
- {
956
- name: "password",
957
- value: ""
958
- }
959
- ]
960
- }
961
- ]
1371
+ auth: {}
962
1372
  };
963
1373
  if (operation) {
964
- if (operation.parameters) {
965
- const parameter = operation.parameters.filter((val) => val.in == "body");
966
- if (parameter && parameter.length > 0) {
1374
+ if (apiOperator.rawApiInfo.parameters) {
1375
+ const parameterBody = apiOperator.rawApiInfo.parameters.filter((val) => val.in == "body");
1376
+ if (parameterBody && parameterBody.length > 0) {
1377
+ apiOperator["requestBody"] = {
1378
+ content: {}
1379
+ };
1380
+ apiOperator["consumes"] = apiOperator.rawApiInfo["consumes"];
1381
+ const currentConsume = apiOperator.rawApiInfo["consumes"].length > 0 ? apiOperator.rawApiInfo["consumes"][0] : "application/json";
1382
+ apiOperator["currentConsume"] = currentConsume;
1383
+ let requestBody = parseParaModel(parameterBody[0], openapiSpec["definitions"]);
1384
+ apiOperator["requestBody"]["content"][currentConsume] = JSON.stringify(requestBody, null, 4);
1385
+ apiOperator["parameterHasBody"] = true;
1386
+ } else {
1387
+ for (const parameter of apiOperator.rawApiInfo.parameters) {
1388
+ if (parameter.in == "query" || parameter.in == "header" || parameter.in == "path" || parameter.in == "formData") {
1389
+ if (parameter.type == "integer" || parameter.schema != null && parameter.schema.type == "integer" || parameter.type == "number" || parameter.schema != null && parameter.schema.type == "number") {
1390
+ parameter.uiType = "number";
1391
+ }
1392
+ if (parameter.type == "string" || parameter.schema != null && parameter.schema.type == "string") {
1393
+ parameter.uiType = "text";
1394
+ }
1395
+ if (parameter.type == "boolean" || parameter.schema != null && parameter.schema.type == "boolean") {
1396
+ parameter.uiType = "text";
1397
+ }
1398
+ }
1399
+ }
1400
+ const parameterFormData = apiOperator.rawApiInfo.parameters.filter((val) => val.in == "formData");
1401
+ if (parameterFormData && parameterFormData.length > 0) {
1402
+ apiOperator["parameterHasFormDataVer2"] = true;
1403
+ }
1404
+ for (const param of apiOperator.rawApiInfo.parameters) {
1405
+ const paramSchema = param.schema;
1406
+ if (paramSchema && paramSchema["$ref"]) {
1407
+ const bodyName = paramSchema["$ref"].substring(paramSchema["$ref"].lastIndexOf("/") + 1);
1408
+ if (openapiSpec && openapiSpec["components"] != null && openapiSpec["components"]["schemas"] != null) {
1409
+ const def = openapiSpec["components"] != null ? openapiSpec["components"]["schemas"][bodyName] : { type: "" };
1410
+ param.type = parseElementType(def);
1411
+ param.uiType = param.type == "integer" || param.type == "number" ? "number" : "text";
1412
+ param.value = parseElement(def);
1413
+ }
1414
+ }
1415
+ }
967
1416
  }
968
1417
  }
969
- if (operation.requestBody) {
970
- const requestBodyObject = operation.requestBody;
971
- const content = requestBodyObject.content;
1418
+ if (apiOperator.rawApiInfo.requestBody) {
1419
+ const content = apiOperator.rawApiInfo.requestBody.content;
1420
+ apiOperator["requestBody"] = {
1421
+ content: {}
1422
+ };
972
1423
  for (const key in content) {
973
1424
  if (Object.prototype.hasOwnProperty.call(content, key)) {
974
1425
  const element = content[key];
1426
+ apiOperator["consumes"]?.push(key);
975
1427
  if (element) {
976
- let requestBody = parseParaModel(element, openapiSpec["components"]["schemas"]);
977
- apiOperator.requestBody = requestBody;
1428
+ if (element.schema == void 0) {
1429
+ console.log("pathKey is:", path);
1430
+ console.log("key is:", key);
1431
+ console.log("content is:", content);
1432
+ console.log("Unsupported requestBody schema format:", element);
1433
+ continue;
1434
+ }
1435
+ if (key != "application/x-www-form-urlencoded" && key != "multipart/form-data") {
1436
+ let requestBody = parseParaModel(element, openapiSpec["components"]["schemas"]);
1437
+ apiOperator["requestBody"]["content"][key] = JSON.stringify(requestBody, null, 4);
1438
+ } else {
1439
+ let requestFormDataBody = parseFormDataParaModel(element, openapiSpec["components"]["schemas"]);
1440
+ apiOperator["requestBody"]["content"][key] = requestFormDataBody;
1441
+ }
1442
+ apiOperator["parameterHasBody"] = true;
978
1443
  }
979
1444
  }
980
1445
  }
1446
+ if (apiOperator.consumes) {
1447
+ if (apiOperator.consumes.length > 0) {
1448
+ apiOperator["currentConsume"] = apiOperator["consumes"][0];
1449
+ }
1450
+ }
981
1451
  }
982
- apiOperator.rawApiInfo = operation;
983
1452
  apiOperatorList.push(apiOperator);
984
1453
  }
985
1454
  });