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.cjs CHANGED
@@ -31,7 +31,6 @@ var GLOBAL_STYLES = `.codigma-apioperatorlist {
31
31
  display: inline-flex;
32
32
  flex-direction: column;
33
33
  gap: 5px;
34
- height: 100%;
35
34
  justify-content: flex-start;
36
35
  width: 100%
37
36
  }
@@ -88,7 +87,6 @@ var GLOBAL_STYLES = `.codigma-apioperatorlist {
88
87
  display: inline-flex;
89
88
  flex-direction: column;
90
89
  gap: 8px;
91
- height: 100%;
92
90
  justify-content: flex-start;
93
91
  width: 100%
94
92
  }
@@ -214,10 +212,12 @@ var GLOBAL_STYLES = `.codigma-apioperatorlist {
214
212
  align-items: center;
215
213
  align-self: stretch;
216
214
  display: inline-flex;
217
- height: 114px;
218
215
  justify-content: flex-start;
219
216
  padding-right: 5px
220
217
  }
218
+ .codigma-apiunit-request-body-info {
219
+ align-self: stretch;
220
+ }
221
221
  .codigma-apiunit-parakeyvalues {
222
222
  align-items: flex-start;
223
223
  align-self: stretch;
@@ -277,9 +277,11 @@ var GLOBAL_STYLES = `.codigma-apioperatorlist {
277
277
  }`;
278
278
 
279
279
  // src/api-render-ui.ts
280
- var ApiRenderer = class {
280
+ var ApiRenderer = class _ApiRenderer {
281
281
  options;
282
282
  container;
283
+ // 静态标志:记录是否已注入全局样式
284
+ static globalStyleInjected = false;
283
285
  constructor(options) {
284
286
  this.options = Object.assign({
285
287
  mountPoint: document?.body,
@@ -291,9 +293,12 @@ var ApiRenderer = class {
291
293
  }
292
294
  render(apiSpec, renderUnit = false) {
293
295
  const appendInlineStyle = (text) => {
294
- const styleEl = document.createElement("style");
295
- styleEl.textContent = text;
296
- document.head.appendChild(styleEl);
296
+ if (!_ApiRenderer.globalStyleInjected) {
297
+ const styleEl = document.createElement("style");
298
+ styleEl.textContent = text;
299
+ document.head.appendChild(styleEl);
300
+ _ApiRenderer.globalStyleInjected = true;
301
+ }
297
302
  };
298
303
  appendInlineStyle(GLOBAL_STYLES);
299
304
  const elementMap = /* @__PURE__ */ new Map();
@@ -368,12 +373,47 @@ var ApiRenderer = class {
368
373
  mountElement.appendChild(this.container);
369
374
  }
370
375
  };
376
+ var auths = [
377
+ {
378
+ value: "No Auth"
379
+ },
380
+ {
381
+ value: "Basic Auth",
382
+ parameters: [
383
+ {
384
+ name: "userName",
385
+ value: ""
386
+ },
387
+ {
388
+ name: "password",
389
+ value: ""
390
+ }
391
+ ]
392
+ },
393
+ {
394
+ value: "OAuth 2.0"
395
+ }
396
+ ];
397
+ var grantTypes = [
398
+ { value: "authorization_code" },
399
+ { value: "Implicit" },
400
+ { value: "Resource Owner Password Credentials" },
401
+ { value: "client_credentials" }
402
+ ];
403
+ var clientAuthenticationOpts = [
404
+ { value: "Headers", displayName: "Send credentials in headers" },
405
+ { value: "Body", displayName: "Send credentials in body" }
406
+ ];
407
+ var consumeOpts = [
408
+ { value: "None" },
409
+ { value: "application/json" },
410
+ { value: "application/xml" },
411
+ { value: "application/x-www-form-urlencoded" },
412
+ { value: "multipart/form-data" },
413
+ { value: "text/plain" }
414
+ ];
371
415
  function renderApiUnit(apiOperator, containerRef, elementMap) {
372
416
  return function(evt) {
373
- console.log("\u70B9\u51FB\u7684API\u64CD\u4F5C\uFF1A");
374
- console.log("\u65B9\u6CD5:", apiOperator.method);
375
- console.log("URL:", apiOperator.url);
376
- console.log("------------------------");
377
417
  const currentTarget = evt.currentTarget;
378
418
  if (elementMap.has(currentTarget)) {
379
419
  const newElement = elementMap.get(currentTarget);
@@ -404,7 +444,7 @@ function createApiUnit(apiOperator) {
404
444
  const paramSection = createParamSection(apiOperator);
405
445
  const headerSection = createSectionHeader(apiOperator);
406
446
  const authSection = createSectionAuth(apiOperator);
407
- const bodySection = createSectionRequestBody(apiOperator.requestBody);
447
+ const bodySection = createSectionRequestBody(apiOperator);
408
448
  reqContent.append(paramSection, headerSection, authSection, bodySection);
409
449
  apiContainer.appendChild(reqContent);
410
450
  apiContainer.appendChild(responseSection);
@@ -435,7 +475,6 @@ function createReqOperator(apiOperator) {
435
475
  reqUrl.className = "Requrl codigma-apiunit-requrl";
436
476
  reqUrl.value = apiOperator.url;
437
477
  reqUrl.addEventListener("input", (e) => {
438
- console.log("\u5F53\u524D\u503C:", e.target.value);
439
478
  apiOperator.url = e.target.value;
440
479
  });
441
480
  reqOperator.appendChild(reqUrl);
@@ -448,7 +487,6 @@ function createReqOperator(apiOperator) {
448
487
  sendText.textContent = "Send";
449
488
  sendButton.appendChild(sendText);
450
489
  sendButton.addEventListener("click", (e) => {
451
- console.log("\u5F53\u524D\u503C:", e.target.value);
452
490
  const respRef = apiOperator._responseSectionRef || null;
453
491
  sendRequest(apiOperator, respRef);
454
492
  });
@@ -515,17 +553,135 @@ function createSectionAuth(apiOperator) {
515
553
  const authValues = document.createElement("div");
516
554
  authValues.setAttribute("data-layer", "paraKeyValues");
517
555
  authValues.className = "Parakeyvalues codigma-apiunit-parakeyvalues";
518
- let auths = apiOperator.auths || [];
519
- const authTypeRow = createSelectRow(auths, authValues);
520
- if (auths.length > 0) {
521
- let parameters = apiOperator.auths[0].parameters || [];
522
- const authRows = parameters.map((parameter) => createRow(parameter));
523
- authValues.append(authTypeRow, ...authRows);
524
- }
556
+ const authTypeRow = createSelectRow("Authorization Type", auths);
557
+ authTypeRow.children[1].addEventListener("change", function(event) {
558
+ authValues && Array.from(authValues.children).slice(1).forEach((el) => el.remove());
559
+ const auth = auths[event.target.selectedIndex];
560
+ if (auth.value == "No Auth") {
561
+ } else if (auth.value == "Basic Auth") {
562
+ apiOperator.auth = [
563
+ {
564
+ name: "userName",
565
+ value: ""
566
+ },
567
+ {
568
+ name: "password",
569
+ value: ""
570
+ }
571
+ ];
572
+ const authRows = apiOperator.auth.map((parameter) => createRow(parameter));
573
+ authValues.append(...authRows);
574
+ } else if (auth.value == "OAuth 2.0") {
575
+ apiOperator.auth = {};
576
+ renderAuthForm(apiOperator, authValues, authTypeRow);
577
+ }
578
+ });
579
+ authValues.append(authTypeRow);
525
580
  authSection.append(authCnr, authValues);
526
581
  return authSection;
527
582
  }
528
- function createSectionRequestBody(requestBody) {
583
+ function createElement(tag, props = {}, classes = []) {
584
+ const el = document.createElement(tag);
585
+ Object.entries(props).forEach(([key, value]) => el.setAttribute(key, value));
586
+ if (classes.length) el.classList.add(...classes);
587
+ return el;
588
+ }
589
+ function createLabeledInput(apiOperator, labelText, inputId, inputName, modelKey, required = false) {
590
+ const wrapper = createElement("div", {}, ["Keyvalue", "codigma-apiunit-keyvalue"]);
591
+ const label = createElement("label", { for: inputId }, ["type", "codigma-apiunit-send"]);
592
+ label.textContent = labelText + ":";
593
+ const input = createElement("input", {
594
+ type: "text",
595
+ id: inputId,
596
+ name: inputName,
597
+ autocomplete: "off",
598
+ ...required ? { required: "true" } : {}
599
+ }, ["Valuetext", "codigma-apiunit-valuetext"]);
600
+ input.value = apiOperator.auth[modelKey] || "";
601
+ input.addEventListener("input", (e) => {
602
+ apiOperator.auth[modelKey] = e.target.value;
603
+ });
604
+ wrapper.appendChild(label);
605
+ wrapper.appendChild(input);
606
+ return wrapper;
607
+ }
608
+ function createSelect(apiOperator, labelText, selectId, options, modelKey, changeHandler) {
609
+ const wrapper = createElement("div", {}, ["Keyvalue", "codigma-apiunit-keyvalue"]);
610
+ const label = createElement("label", { for: selectId }, ["type", "codigma-apiunit-send"]);
611
+ label.textContent = labelText + ":";
612
+ const select = createElement("select", {
613
+ id: selectId,
614
+ name: selectId
615
+ }, []);
616
+ options.forEach((opt) => {
617
+ const option = createElement("option", { value: opt.value });
618
+ option.textContent = opt.displayName || opt.value;
619
+ select.appendChild(option);
620
+ });
621
+ select.value = apiOperator.auth[modelKey] || options[0]?.value || "";
622
+ select.addEventListener("change", (e) => {
623
+ const val = e.target.value;
624
+ changeHandler(val);
625
+ });
626
+ wrapper.appendChild(label);
627
+ wrapper.appendChild(select);
628
+ return wrapper;
629
+ }
630
+ function renderAuthForm(apiOperator, authValues, authTypeRow) {
631
+ authValues.innerHTML = "";
632
+ authValues.append(authTypeRow);
633
+ authValues.appendChild(createLabeledInput(apiOperator, "Token", "token", "token", "token", true));
634
+ authValues.appendChild(
635
+ createSelect(
636
+ apiOperator,
637
+ "Grant Type",
638
+ "grantType",
639
+ grantTypes,
640
+ "grantType",
641
+ (value) => {
642
+ apiOperator.auth.grantType = value;
643
+ renderAuthForm(apiOperator, authValues, authTypeRow);
644
+ }
645
+ )
646
+ );
647
+ const gt = apiOperator.auth.grantType || "authorization_code";
648
+ if (gt === "authorization_code" || gt === "Implicit") {
649
+ authValues.appendChild(createLabeledInput(apiOperator, "Authorization Endpoint", "authorizationEndpoint", "authorizationEndpoint", "authorizationEndpoint", true));
650
+ authValues.appendChild(createLabeledInput(apiOperator, "Redirect URL", "RedirectURI", "RedirectURI", "redirectURI", true));
651
+ }
652
+ if (gt === "authorization_code" || gt === "client_credentials" || gt === "Resource Owner Password Credentials") {
653
+ authValues.appendChild(createLabeledInput(apiOperator, "Token Endpoint", "TokenEndpoint", "TokenEndpoint", "tokenEndpoint", true));
654
+ }
655
+ authValues.appendChild(createLabeledInput(apiOperator, "Client ID", "ClientID", "ClientID", "clientId", true));
656
+ if (gt === "authorization_code" || gt === "client_credentials" || gt === "Resource Owner Password Credentials") {
657
+ authValues.appendChild(createLabeledInput(apiOperator, "Client Secret", "ClientSecret", "ClientSecret", "clientSecret", true));
658
+ }
659
+ if (gt === "Resource Owner Password Credentials") {
660
+ authValues.appendChild(createLabeledInput(apiOperator, "Username", "Username", "Username", "username", true));
661
+ authValues.appendChild(createLabeledInput(apiOperator, "Password", "Password", "Password", "password", true));
662
+ }
663
+ authValues.appendChild(createLabeledInput(apiOperator, "Scopes", "Scopes", "Scopes", "scopes", true));
664
+ authValues.appendChild(
665
+ createSelect(
666
+ apiOperator,
667
+ "Client Authentication",
668
+ "clientAuthentication",
669
+ clientAuthenticationOpts,
670
+ "clientAuthentication",
671
+ (value) => {
672
+ apiOperator.auth.clientAuthentication = value;
673
+ }
674
+ )
675
+ );
676
+ const buttonWrapper = createElement("div", {}, ["parameter-item"]);
677
+ const generateBtn = createElement("button", {}, ["parameter-button"]);
678
+ generateBtn.type = "button";
679
+ generateBtn.textContent = "Generate Token";
680
+ generateBtn.addEventListener("click", () => generateOAuth2Token(apiOperator));
681
+ buttonWrapper.appendChild(generateBtn);
682
+ authValues.appendChild(buttonWrapper);
683
+ }
684
+ function createSectionRequestBody(apiOperator) {
529
685
  const bodySection = document.createElement("div");
530
686
  bodySection.setAttribute("data-layer", "request-body-section");
531
687
  bodySection.className = "RequestBodySection codigma-apiunit-request-body-section";
@@ -538,13 +694,108 @@ function createSectionRequestBody(requestBody) {
538
694
  bodyText.textContent = "Body";
539
695
  bodyCnr.appendChild(bodyText);
540
696
  bodySection.appendChild(bodyCnr);
541
- const bodyValue = document.createElement("textarea");
542
- bodyValue.setAttribute("data-layer", "bodyTextValue");
543
- bodyValue.className = "Id0CategoryId0NameNamePhotourlsTagsId0NameStatusAvailable codigma-apiunit-parakeyvalues";
544
- bodyValue.value = JSON.stringify(requestBody);
545
- bodySection.appendChild(bodyValue);
697
+ renderConsumeSection(apiOperator, bodySection, bodyCnr);
546
698
  return bodySection;
547
699
  }
700
+ function createConsumeSelect(apiOperator, container, bodyCnr) {
701
+ const wrapper = createElement("div");
702
+ const label = createElement("label");
703
+ label.style.margin = "0 1rem";
704
+ label.textContent = "Content-Type";
705
+ const select = createElement("select");
706
+ select.style.width = "18rem";
707
+ consumeOpts.forEach((opt) => {
708
+ const option = document.createElement("option");
709
+ option.value = opt.value;
710
+ option.textContent = opt.value;
711
+ select.appendChild(option);
712
+ });
713
+ select.value = apiOperator.currentConsume || getCurrentConsume(apiOperator);
714
+ select.addEventListener("change", (e) => {
715
+ const newValue = e.target.value;
716
+ if (apiOperator.currentConsume !== newValue) {
717
+ apiOperator.currentConsume = newValue;
718
+ renderConsumeSection(apiOperator, container, bodyCnr);
719
+ }
720
+ });
721
+ wrapper.appendChild(label);
722
+ wrapper.appendChild(select);
723
+ return wrapper;
724
+ }
725
+ function renderRequestBodyInto(apiOperator, targetDiv) {
726
+ targetDiv.innerHTML = "";
727
+ const ct = apiOperator.currentConsume || getCurrentConsume(apiOperator);
728
+ if (ct === null || ct === "None" || ct === "application/json" || ct === "application/xml" || ct === "text/plain") {
729
+ const mimeType = ct || "None";
730
+ let rawValue = apiOperator.requestBody.content[mimeType];
731
+ if (rawValue == null) {
732
+ rawValue = "";
733
+ apiOperator.requestBody.content[mimeType] = rawValue;
734
+ }
735
+ const textarea = createElement("textarea", {}, []);
736
+ textarea.style.width = "100%";
737
+ textarea.style.height = "200px";
738
+ textarea.style.fontFamily = "monospace";
739
+ textarea.style.fontSize = "14px";
740
+ textarea.placeholder = `Enter ${mimeType} body...`;
741
+ textarea.value = rawValue;
742
+ textarea.addEventListener("input", () => {
743
+ apiOperator.requestBody.content[mimeType] = textarea.value;
744
+ console.log(`Content updated for ${mimeType}:`, textarea.value);
745
+ });
746
+ targetDiv.appendChild(textarea);
747
+ } else if ((ct === "application/x-www-form-urlencoded" || ct === "multipart/form-data") && apiOperator.requestBody.content && Array.isArray(apiOperator.requestBody.content[ct])) {
748
+ const params = apiOperator.requestBody.content[ct];
749
+ params.forEach((param, index) => {
750
+ const item = createElement("div", {}, ["Keyvalue", "codigma-apiunit-keyvalue"]);
751
+ const label = createElement("label", { for: `param-${Date.now()}-${index}` }, ["petId", "codigma-apiunit-send"]);
752
+ label.textContent = `${param.name}:`;
753
+ const input = createElement("input", {
754
+ type: param.uiType || "text",
755
+ // 使用时间戳+索引避免 id 冲突(仅用于 label for)
756
+ id: `param-${Date.now()}-${index}`,
757
+ name: "name"
758
+ }, ["Valuetext", "codigma-apiunit-valuetext"]);
759
+ input.value = param.value || "";
760
+ input.autocomplete = "off";
761
+ input.required = true;
762
+ input.addEventListener("keydown", (e) => {
763
+ setEditStatus(e, true);
764
+ });
765
+ input.addEventListener("input", () => {
766
+ param.value = input.value;
767
+ });
768
+ item.appendChild(label);
769
+ item.appendChild(input);
770
+ targetDiv.appendChild(item);
771
+ });
772
+ }
773
+ }
774
+ function getCurrentConsume(apiOperator) {
775
+ if (!apiOperator.requestBody) {
776
+ apiOperator.requestBody = { content: {} };
777
+ }
778
+ if (!apiOperator.requestBody.content) {
779
+ apiOperator.requestBody.content = {};
780
+ }
781
+ const keys = Object.keys(apiOperator.requestBody.content);
782
+ const ct = apiOperator.currentConsume = keys.length > 0 ? keys[0] : "None";
783
+ return ct;
784
+ }
785
+ function setEditStatus(event, status) {
786
+ console.log("setEditStatus called:", event.key, status);
787
+ }
788
+ function renderConsumeSection(apiOperator, container, bodyCnr) {
789
+ container.innerHTML = "";
790
+ container.appendChild(bodyCnr);
791
+ const wrapperDiv = createElement("div", {}, ["codigma-apiunit-parakeyvalues"]);
792
+ const selectWrapper = createConsumeSelect(apiOperator, container, bodyCnr);
793
+ wrapperDiv.appendChild(selectWrapper);
794
+ const reqBodyContainer = createElement("div", {}, ["codigma-apiunit-request-body-info"]);
795
+ renderRequestBodyInto(apiOperator, reqBodyContainer);
796
+ wrapperDiv.appendChild(reqBodyContainer);
797
+ container.appendChild(wrapperDiv);
798
+ }
548
799
  function createSectionResponse(apiOperator) {
549
800
  const responseSection = document.createElement("div");
550
801
  responseSection.setAttribute("data-layer", "reqresponse");
@@ -579,6 +830,9 @@ function createTimeStatusElement(apiOperator) {
579
830
  updateTimeStatus(timeStatus, apiOperator);
580
831
  return timeStatus;
581
832
  }
833
+ function updateTimeStatus(timeStatus, apiOperator) {
834
+ timeStatus.textContent = `Status: ${apiOperator.response.status || ""} ${apiOperator.response.statusText || ""} Time: ${apiOperator.requestDuration || ""}`;
835
+ }
582
836
  function createRow(parameter) {
583
837
  const petIdRow = document.createElement("div");
584
838
  petIdRow.setAttribute("data-layer", "keyValue");
@@ -592,7 +846,6 @@ function createRow(parameter) {
592
846
  petIdValue.className = "Valuetext codigma-apiunit-valuetext";
593
847
  petIdValue.value = parameter["value"] || "";
594
848
  petIdValue.addEventListener("input", (e) => {
595
- console.log("\u5F53\u524D\u503C:", e.target.value);
596
849
  parameter["value"] = e.target.value;
597
850
  });
598
851
  petIdRow.append(petIdLabel, petIdValue);
@@ -606,31 +859,24 @@ function createInputElement() {
606
859
  inputText.setAttribute("autocomplete", "off");
607
860
  return inputText;
608
861
  }
609
- function createSelectRow(auths, authValues) {
862
+ function createSelectRow(name, args) {
610
863
  const container = document.createElement("div");
611
864
  container.setAttribute("data-layer", "keyValue");
612
865
  container.className = "Keyvalue codigma-apiunit-keyvalue";
613
866
  const typeLabel = document.createElement("div");
614
- typeLabel.setAttribute("data-layer", "type");
867
+ typeLabel.setAttribute("data-layer", name);
615
868
  typeLabel.className = "type codigma-apiunit-send";
616
- typeLabel.textContent = "Type:";
869
+ typeLabel.textContent = name + ":";
617
870
  const selectElement = document.createElement("select");
618
871
  selectElement.name = "text-select";
619
872
  selectElement.label = "text-select";
620
873
  selectElement.setAttribute("data-layer", "valueText");
621
- auths.forEach((auth) => {
874
+ args.forEach((auth) => {
622
875
  const option1 = document.createElement("option");
623
- option1.value = auth["type"];
624
- option1.textContent = auth["type"];
876
+ option1.value = auth["value"];
877
+ option1.textContent = auth["displayName"] != null || auth["label"] != null ? auth["displayName"] || auth["label"] : auth["value"];
625
878
  selectElement.appendChild(option1);
626
879
  });
627
- selectElement.addEventListener("change", function(event) {
628
- authValues && Array.from(authValues.children).slice(1).forEach((el) => el.remove());
629
- const auth = auths[event.target.selectedIndex];
630
- let parameters = auth.parameters || [];
631
- const authRows = parameters.map((parameter) => createRow(parameter));
632
- authValues.append(...authRows);
633
- });
634
880
  container.appendChild(typeLabel);
635
881
  container.appendChild(selectElement);
636
882
  return container;
@@ -641,58 +887,153 @@ function isPathOrQueryParam(param) {
641
887
  function isHeaderParam(param) {
642
888
  return param.in === "header";
643
889
  }
644
- function sendRequest(apiOperator, responseSectionRef) {
645
- if (!responseSectionRef) {
646
- console.error("sendRequest: missing responseSectionRef. Aborting request to avoid runtime errors.");
647
- return;
890
+ async function generateOAuth2Token(apiInfo) {
891
+ const accessToken = await getAccessToken(apiInfo);
892
+ apiInfo.auth.token = accessToken;
893
+ }
894
+ async function getAccessToken(apiInfo) {
895
+ const auth = apiInfo.auth;
896
+ if (auth == null) {
897
+ throw new Error("OAuth2.0\u8BA4\u8BC1\u4FE1\u606F\u672A\u914D\u7F6E");
898
+ }
899
+ const CLIENT_ID = auth.clientId;
900
+ const CLIENT_SECRET = auth.clientSecret;
901
+ const SCOPE = auth.scopes;
902
+ if (apiInfo.auth.grantType == "client_credentials") {
903
+ try {
904
+ console.log("\u6B63\u5728\u83B7\u53D6\u8BBF\u95EE\u4EE4\u724C...");
905
+ const headerParams = {
906
+ "Content-Type": "application/x-www-form-urlencoded"
907
+ };
908
+ const bodyParams = new URLSearchParams();
909
+ bodyParams.append("grant_type", "client_credentials");
910
+ if (SCOPE) {
911
+ bodyParams.append("scope", SCOPE);
912
+ }
913
+ if (apiInfo.auth.clientAuthentication == "Body") {
914
+ bodyParams.append("client_id", CLIENT_ID);
915
+ bodyParams.append("client_secret", CLIENT_SECRET);
916
+ } else {
917
+ headerParams["Authorization"] = "Basic " + btoa(CLIENT_ID + ":" + CLIENT_SECRET);
918
+ }
919
+ const response = await fetch(auth.tokenEndpoint, {
920
+ method: "POST",
921
+ headers: headerParams,
922
+ body: bodyParams.toString()
923
+ });
924
+ if (!response.ok) {
925
+ const errorData = await response.json().catch(() => ({}));
926
+ throw new Error(`\u83B7\u53D6\u4EE4\u724C\u5931\u8D25: ${response.status} ${response.statusText}. ${JSON.stringify(errorData)}`);
927
+ }
928
+ const tokenData = await response.json();
929
+ console.log("\u4EE4\u724C\u83B7\u53D6\u6210\u529F:", tokenData);
930
+ return tokenData.access_token;
931
+ } catch (error) {
932
+ console.error("\u83B7\u53D6\u8BBF\u95EE\u4EE4\u724C\u65F6\u51FA\u9519:", error);
933
+ throw error;
934
+ }
935
+ } else if (apiInfo.auth.grantType == "Resource Owner Password Credentials") {
936
+ } else if (apiInfo.auth.grantType == "authorization_code") {
937
+ let getUrlParams2 = function() {
938
+ const params = new URLSearchParams(window.location.search);
939
+ return Object.fromEntries(params.entries());
940
+ }, redirectToAuth2 = function() {
941
+ const state = Math.random().toString(36).substring(2);
942
+ const nonce = Math.random().toString(36).substring(2);
943
+ const authUrl = new URL(config.authUrl);
944
+ authUrl.searchParams.append("client_id", config.clientId);
945
+ authUrl.searchParams.append("redirect_uri", config.redirectUri);
946
+ authUrl.searchParams.append("response_type", "code");
947
+ authUrl.searchParams.append("scope", config.scope);
948
+ authUrl.searchParams.append("state", state);
949
+ authUrl.searchParams.append("nonce", nonce);
950
+ authUrl.searchParams.append("access_type", "offline");
951
+ const newTab = window.open(authUrl.toString(), "_blank");
952
+ };
953
+ var getUrlParams = getUrlParams2, redirectToAuth = redirectToAuth2;
954
+ const config = {
955
+ clientId: apiInfo.auth.clientId,
956
+ // 替换为你的 client_id
957
+ clientSecret: apiInfo.auth.clientSecret,
958
+ // 替换为你的 client_secret
959
+ redirectUri: apiInfo.auth.redirectURI,
960
+ // 必须与注册的 redirect_uri 一致
961
+ authUrl: apiInfo.auth.authorizationEndpoint,
962
+ tokenUrl: apiInfo.auth.tokenEndpoint,
963
+ scope: apiInfo.auth.scopes
964
+ // 可选: 'openid profile email' 如果服务支持
965
+ };
966
+ redirectToAuth2();
967
+ } else if (apiInfo.auth.grantType == "Implicit") {
968
+ } else {
648
969
  }
649
- let reuqestUrl = getRequestUrl(apiOperator);
650
- const result = checkIfParameter(apiOperator);
651
- let header = result.hasRequestBody ? "application/json" : result.hasRequestFormData ? "application/x-www-form-urlencoded" : "application/json";
970
+ }
971
+ function getBodyEditorContent(apiOperator) {
972
+ const ct = apiOperator.currentConsume || "None";
973
+ return apiOperator.requestBody.content[ct];
974
+ }
975
+ var gotResponse = false;
976
+ var ifSendingRequest = false;
977
+ var requestDuration = "0";
978
+ var responseObj = {};
979
+ function sendRequest(apiOperator, responseSectionRef) {
980
+ const apiInfo = apiOperator;
981
+ let reuqestUrl = getRequestUrl(apiInfo);
982
+ let header = apiInfo["parameterHasFormDataVer2"] ? "application/x-www-form-urlencoded" : apiInfo["parameterHasBody"] ? apiInfo["currentConsume"] : "application/json";
652
983
  let headers = {
653
984
  "Content-Type": header
654
985
  };
655
- if (apiOperator.custom) {
656
- for (let index = 0; index < apiOperator.customHeaderparameters.length; index++) {
657
- const paras = apiOperator.customHeaderparameters[index];
658
- if (paras.name != "" && paras.value != "" && paras.name != null && paras.value != null) {
659
- headers[paras.name] = paras.value;
986
+ const headerParas = getHeadersParams(apiInfo, apiInfo.rawApiInfo.parameters || []);
987
+ Object.assign(headers, headerParas);
988
+ addAuthHeader(apiInfo, headers);
989
+ let body;
990
+ if (apiInfo.method.toUpperCase() == "POST" || apiInfo.method.toUpperCase() == "PUT") {
991
+ if (apiInfo["currentConsume"] == "application/json" && apiInfo.requestBody != null) {
992
+ body = getBodyEditorContent(apiOperator);
993
+ } else if (apiInfo["parameterHasFormDataVer2"]) {
994
+ body = getRequestFormData(apiInfo.rawApiInfo);
995
+ } else if (apiInfo["currentConsume"] == "application/x-www-form-urlencoded") {
996
+ for (const key of apiInfo["requestBody"]["content"][apiInfo["currentConsume"]]) {
997
+ if (body == null || body == "") {
998
+ body = key.name + "=" + key.value;
999
+ } else {
1000
+ body = body + "&" + key.name + "=" + key.value;
1001
+ }
660
1002
  }
1003
+ } else {
1004
+ body = "";
661
1005
  }
1006
+ } else {
1007
+ body = "";
662
1008
  }
663
- let body = result.hasRequestBody ? apiOperator.requestBody : result.hasRequestFormData ? getRequestFormData(apiOperator.rawApiInfo) : null;
664
- if (apiOperator.custom) {
665
- if (apiOperator.method.toUpperCase() == "POST" || apiOperator.method.toUpperCase() == "PUT") {
666
- body = apiOperator.requestBody;
667
- }
668
- }
669
- apiOperator.ifSendingRequest = true;
1009
+ ifSendingRequest = true;
670
1010
  const startTime = Date.now();
671
1011
  apiOperator.controller = new AbortController();
672
1012
  const signal = apiOperator.controller.signal;
673
1013
  const overlayLayerContainer = createRequestOverlayLayer(apiOperator, responseSectionRef);
674
1014
  fetch(reuqestUrl, {
675
- method: apiOperator.method.toUpperCase(),
1015
+ method: apiInfo.method.toUpperCase(),
676
1016
  headers,
677
- body: body != null ? JSON.stringify(body) : null,
1017
+ body,
678
1018
  signal
679
1019
  }).then((response) => {
680
1020
  if (!response.ok) {
681
- apiOperator.response = {
1021
+ responseObj = {
682
1022
  status: response.status,
683
- statusText: response.statusText
1023
+ statusText: response.statusText,
1024
+ body: ""
684
1025
  };
685
1026
  const endTime2 = Date.now();
686
- apiOperator.requestDuration = formatDuration(endTime2 - startTime);
687
- apiOperator.ifSendingRequest = false;
1027
+ requestDuration = formatDuration(endTime2 - startTime);
1028
+ ifSendingRequest = false;
688
1029
  throw new Error("Network response was not ok.");
689
1030
  }
690
1031
  const endTime = Date.now();
691
- apiOperator.requestDuration = formatDuration(endTime - startTime);
1032
+ requestDuration = formatDuration(endTime - startTime);
692
1033
  const responsebodyElement = responseSectionRef.querySelector('[data-layer="responsebody"]');
693
1034
  responsebodyElement.removeChild(overlayLayerContainer);
694
- apiOperator.ifSendingRequest = false;
695
- apiOperator.response = {
1035
+ ifSendingRequest = false;
1036
+ responseObj = {
696
1037
  status: response.status,
697
1038
  statusText: response.statusText
698
1039
  };
@@ -707,22 +1048,20 @@ function sendRequest(apiOperator, responseSectionRef) {
707
1048
  return responseClone.text();
708
1049
  });
709
1050
  }).then((data) => {
710
- apiOperator.gotResponse = true;
1051
+ gotResponse = true;
711
1052
  const responsebodyElement = responseSectionRef.querySelector('[data-layer="responsebody"]');
712
1053
  if (typeof data === "object") {
713
1054
  console.log("Received JSON:", data);
714
- responsebodyElement.textContent = JSON.stringify(data, null, 4);
1055
+ responseObj.body = JSON.stringify(data, null, 4);
715
1056
  } else {
716
1057
  console.log("Received text:", data);
717
- responsebodyElement.textContent = data;
1058
+ responseObj.body = data;
718
1059
  }
1060
+ responsebodyElement.textContent = responseObj.body;
719
1061
  }).catch((error) => {
720
1062
  console.error("There has been a problem with your fetch operation:", error);
721
1063
  });
722
1064
  }
723
- function updateTimeStatus(timeStatus, apiOperator) {
724
- timeStatus.textContent = `Status: ${apiOperator.response.status || ""} ${apiOperator.response.statusText || ""} Time: ${apiOperator.requestDuration || ""}`;
725
- }
726
1065
  function createRequestOverlayLayer(apiOperator, responseSectionRef) {
727
1066
  const container = document.createElement("div");
728
1067
  Object.assign(container.style, {
@@ -765,28 +1104,6 @@ function createRequestOverlayLayer(apiOperator, responseSectionRef) {
765
1104
  });
766
1105
  return container;
767
1106
  }
768
- function checkIfParameter(apiOperator) {
769
- let hasRequestBody = false;
770
- let hasRequestFormData = false;
771
- const parameters = apiOperator.rawApiInfo.parameters;
772
- if (parameters) {
773
- for (let index = 0; index < parameters.length; index++) {
774
- const parameter = parameters[index];
775
- if (parameter.in == "query" || parameter.in == "path") {
776
- } else if (parameter.in == "body") {
777
- hasRequestBody = true;
778
- parameter.name = parameter.name.charAt(0).toUpperCase() + parameter.name.slice(1);
779
- } else if (parameter.in == "formData") {
780
- hasRequestFormData = true;
781
- }
782
- }
783
- }
784
- const requestBody = apiOperator.rawApiInfo.requestBody;
785
- if (requestBody) {
786
- hasRequestBody = true;
787
- }
788
- return { hasRequestBody, hasRequestFormData };
789
- }
790
1107
  function formatDuration(milliseconds) {
791
1108
  let totalSeconds = Math.floor(milliseconds / 1e3);
792
1109
  let seconds = totalSeconds % 60;
@@ -799,9 +1116,9 @@ function formatDuration(milliseconds) {
799
1116
  seconds = seconds.toString().padStart(2, "0");
800
1117
  return `${hours}h${minutes}m${seconds}s${millisecondsPart}ms`;
801
1118
  }
802
- function getRequestUrl(apiOperator) {
803
- let reuqestUrl = apiOperator.url;
804
- const requestParameters = apiOperator.rawApiInfo.parameters || [];
1119
+ function getRequestUrl(apiInfo) {
1120
+ let reuqestUrl = apiInfo.url;
1121
+ const requestParameters = apiInfo.rawApiInfo.parameters || [];
805
1122
  if (requestParameters == null) {
806
1123
  return reuqestUrl;
807
1124
  }
@@ -810,11 +1127,45 @@ function getRequestUrl(apiOperator) {
810
1127
  reuqestUrl = reuqestUrl.replace("{" + element.name + "}", element.value);
811
1128
  }
812
1129
  }
813
- let queryParams = getQueryParams(apiOperator, requestParameters);
1130
+ let queryParams = getQueryParams(apiInfo, requestParameters);
814
1131
  reuqestUrl = queryParams.length > 0 ? reuqestUrl + "?" + queryParams.join("&") : reuqestUrl;
815
1132
  return reuqestUrl;
816
1133
  }
817
- function getQueryParams(apiOperator, requestParameters) {
1134
+ function addAuthHeader(apiInfo, headers) {
1135
+ const env = isBrowserEnvironment();
1136
+ if (apiInfo.auth.authType == "Basic Auth" && apiInfo.auth != null) {
1137
+ if (env) {
1138
+ const credentials = btoa(`${apiInfo.auth.username}:${apiInfo.auth.passWord}`);
1139
+ headers["Authorization"] = `Basic ${credentials}`;
1140
+ } else {
1141
+ const buffer = Buffer.from(`${apiInfo.auth.username}:${apiInfo.auth.passWord}`);
1142
+ const credentials = buffer.toString("base64");
1143
+ headers["Authorization"] = `Basic ${credentials}`;
1144
+ }
1145
+ } else if (apiInfo.auth.authType == "OAuth 2.0" && apiInfo.auth != null) {
1146
+ if (apiInfo.auth.token != null || apiInfo.auth.token != "") {
1147
+ headers["Authorization"] = `Bearer ${apiInfo.auth.token}`;
1148
+ }
1149
+ }
1150
+ }
1151
+ function getHeadersParams(apiInfo, requestParameters) {
1152
+ let headersParams = [];
1153
+ for (const element of requestParameters) {
1154
+ if (element.in == "header") {
1155
+ headersParams[element.name] = element.value;
1156
+ }
1157
+ }
1158
+ if (apiInfo.customHeaderparameters) {
1159
+ for (let index = 0; index < apiInfo.customHeaderparameters.length; index++) {
1160
+ const paras = apiInfo.customHeaderparameters[index];
1161
+ if (paras.name != "" && paras.value != "" && paras.name != null && paras.value != null) {
1162
+ headersParams[paras.name] = paras.value;
1163
+ }
1164
+ }
1165
+ }
1166
+ return headersParams;
1167
+ }
1168
+ function getQueryParams(apiInfo, requestParameters) {
818
1169
  let queryParams = [];
819
1170
  for (const element of requestParameters) {
820
1171
  if (element.in == "query") {
@@ -829,9 +1180,9 @@ function getQueryParams(apiOperator, requestParameters) {
829
1180
  }
830
1181
  }
831
1182
  }
832
- if (apiOperator.custom) {
833
- for (let index = 0; index < apiOperator.customQueryparameters.length; index++) {
834
- const paras = apiOperator.customQueryparameters[index];
1183
+ if (apiInfo.customQueryparameters) {
1184
+ for (let index = 0; index < apiInfo.customQueryparameters.length; index++) {
1185
+ const paras = apiInfo.customQueryparameters[index];
835
1186
  if (paras.name != "" && paras.value != "" && paras.name != null && paras.value != null) {
836
1187
  queryParams.push(paras.name + "=" + paras.value);
837
1188
  }
@@ -858,6 +1209,15 @@ function getRequestFormData(rawApiInfo) {
858
1209
  }
859
1210
  return formData;
860
1211
  }
1212
+ function isBrowserEnvironment() {
1213
+ if (typeof window !== "undefined" && typeof document !== "undefined") {
1214
+ return true;
1215
+ } else if (typeof process !== "undefined" && process.versions && process.versions.node) {
1216
+ return false;
1217
+ } else {
1218
+ return false;
1219
+ }
1220
+ }
861
1221
  function createSvg() {
862
1222
  const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
863
1223
  svg.setAttribute("width", "21");
@@ -876,18 +1236,16 @@ function createSvg() {
876
1236
  }
877
1237
  function parseParaModel(parameterObj, dataDef) {
878
1238
  let bodyModel;
879
- if (parameterObj && parameterObj.schema) {
880
- if (parameterObj.schema["$ref"]) {
881
- bodyModel = parseModel(parameterObj.schema["$ref"], dataDef);
882
- } else if (parameterObj.schema["type"] == "array") {
883
- const itemObj = parameterObj.schema["items"];
884
- if (itemObj["$ref"]) {
885
- bodyModel = parseModel(itemObj["$ref"], dataDef);
886
- } else if (itemObj["type"]) {
887
- bodyModel = parseElement(itemObj);
888
- }
889
- bodyModel = [bodyModel];
1239
+ if (parameterObj.schema["$ref"]) {
1240
+ bodyModel = parseModel(parameterObj.schema["$ref"], dataDef);
1241
+ } else if (parameterObj.schema["type"] == "array") {
1242
+ const itemObj = parameterObj.schema["items"];
1243
+ if (itemObj["$ref"]) {
1244
+ bodyModel = parseModel(itemObj["$ref"], dataDef);
1245
+ } else if (itemObj["type"]) {
1246
+ bodyModel = parseElement(itemObj);
890
1247
  }
1248
+ bodyModel = [bodyModel];
891
1249
  }
892
1250
  return bodyModel;
893
1251
  }
@@ -918,10 +1276,66 @@ function parseModel(modelDef, apiDef) {
918
1276
  }
919
1277
  return model;
920
1278
  }
1279
+ function parseFormDataModel(modelDef, apiDef) {
1280
+ const model = [];
1281
+ const bodyName = modelDef.substring(modelDef.lastIndexOf("/") + 1);
1282
+ const def = apiDef[bodyName];
1283
+ const props = def["properties"];
1284
+ if (props) {
1285
+ for (const key in props) {
1286
+ if (Object.prototype.hasOwnProperty.call(props, key)) {
1287
+ const element = props[key];
1288
+ let modelEle;
1289
+ if (element.hasOwnProperty("items") && element["type"] == "array") {
1290
+ if (element["items"]["$ref"]) {
1291
+ modelEle = [parseModel(element["items"]["$ref"], apiDef)];
1292
+ } else if (element["items"]["type"]) {
1293
+ modelEle = [parseElement(element["items"])];
1294
+ }
1295
+ if (modelEle) {
1296
+ model.push({
1297
+ type: "string",
1298
+ uiType: "text",
1299
+ name: key,
1300
+ value: JSON.stringify(modelEle)
1301
+ });
1302
+ }
1303
+ } else if (element["type"]) {
1304
+ model.push({
1305
+ type: element["type"],
1306
+ uiType: element["type"] == "integer" || element["type"] == "number" ? "number" : "text",
1307
+ name: key,
1308
+ value: parseElement(element)
1309
+ });
1310
+ } else if (element["$ref"]) {
1311
+ const bodyModel = parseModel(element["$ref"], apiDef);
1312
+ model.push({
1313
+ type: "string",
1314
+ uiType: "text",
1315
+ name: key,
1316
+ value: JSON.stringify(bodyModel)
1317
+ });
1318
+ }
1319
+ }
1320
+ }
1321
+ }
1322
+ return model;
1323
+ }
1324
+ function parseFormDataParaModel(parameterObj, dataDef) {
1325
+ let bodyModel = [];
1326
+ if (parameterObj.schema["$ref"]) {
1327
+ bodyModel = parseFormDataModel(parameterObj.schema["$ref"], dataDef);
1328
+ }
1329
+ return bodyModel;
1330
+ }
921
1331
  function parseElement(element) {
922
1332
  let elementValue;
923
1333
  if (element["type"].includes("integer")) {
924
- elementValue = 0;
1334
+ if (element["enum"]) {
1335
+ elementValue = element["enum"][0];
1336
+ } else {
1337
+ elementValue = 0;
1338
+ }
925
1339
  } else if (element["type"].includes("boolean")) {
926
1340
  elementValue = false;
927
1341
  } else if (element["type"].includes("string")) {
@@ -931,11 +1345,24 @@ function parseElement(element) {
931
1345
  elementValue = "";
932
1346
  }
933
1347
  }
1348
+ if (element["default"]) {
1349
+ elementValue = element["default"];
1350
+ }
934
1351
  if (element["example"]) {
935
1352
  elementValue = element["example"];
936
1353
  }
937
1354
  return elementValue;
938
1355
  }
1356
+ function parseElementType(element) {
1357
+ if (element["type"].includes("integer")) {
1358
+ return "integer";
1359
+ } else if (element["type"].includes("boolean")) {
1360
+ return "boolean";
1361
+ } else if (element["type"].includes("string")) {
1362
+ return "string";
1363
+ }
1364
+ return "string";
1365
+ }
939
1366
  var HTTP_METHODS = ["get", "put", "post", "delete", "options", "head", "patch", "trace"];
940
1367
  function isHttpMethod(method) {
941
1368
  return HTTP_METHODS.includes(method);
@@ -964,48 +1391,90 @@ function parseOpenAPI(openapiSpec) {
964
1391
  const apiOperator = {
965
1392
  method: method.toUpperCase(),
966
1393
  url: path,
967
- rawApiInfo: null,
1394
+ rawApiInfo: operation,
968
1395
  requestBody: null,
969
1396
  response: {},
970
- auths: [
971
- {
972
- type: "No Auth"
973
- },
974
- {
975
- type: "Basic Auth",
976
- parameters: [
977
- {
978
- name: "userName",
979
- value: ""
980
- },
981
- {
982
- name: "password",
983
- value: ""
984
- }
985
- ]
986
- }
987
- ]
1397
+ auth: {}
988
1398
  };
989
1399
  if (operation) {
990
- if (operation.parameters) {
991
- const parameter = operation.parameters.filter((val) => val.in == "body");
992
- if (parameter && parameter.length > 0) {
1400
+ if (apiOperator.rawApiInfo.parameters) {
1401
+ const parameterBody = apiOperator.rawApiInfo.parameters.filter((val) => val.in == "body");
1402
+ if (parameterBody && parameterBody.length > 0) {
1403
+ apiOperator["requestBody"] = {
1404
+ content: {}
1405
+ };
1406
+ apiOperator["consumes"] = apiOperator.rawApiInfo["consumes"];
1407
+ const currentConsume = apiOperator.rawApiInfo["consumes"].length > 0 ? apiOperator.rawApiInfo["consumes"][0] : "application/json";
1408
+ apiOperator["currentConsume"] = currentConsume;
1409
+ let requestBody = parseParaModel(parameterBody[0], openapiSpec["definitions"]);
1410
+ apiOperator["requestBody"]["content"][currentConsume] = JSON.stringify(requestBody, null, 4);
1411
+ apiOperator["parameterHasBody"] = true;
1412
+ } else {
1413
+ for (const parameter of apiOperator.rawApiInfo.parameters) {
1414
+ if (parameter.in == "query" || parameter.in == "header" || parameter.in == "path" || parameter.in == "formData") {
1415
+ if (parameter.type == "integer" || parameter.schema != null && parameter.schema.type == "integer" || parameter.type == "number" || parameter.schema != null && parameter.schema.type == "number") {
1416
+ parameter.uiType = "number";
1417
+ }
1418
+ if (parameter.type == "string" || parameter.schema != null && parameter.schema.type == "string") {
1419
+ parameter.uiType = "text";
1420
+ }
1421
+ if (parameter.type == "boolean" || parameter.schema != null && parameter.schema.type == "boolean") {
1422
+ parameter.uiType = "text";
1423
+ }
1424
+ }
1425
+ }
1426
+ const parameterFormData = apiOperator.rawApiInfo.parameters.filter((val) => val.in == "formData");
1427
+ if (parameterFormData && parameterFormData.length > 0) {
1428
+ apiOperator["parameterHasFormDataVer2"] = true;
1429
+ }
1430
+ for (const param of apiOperator.rawApiInfo.parameters) {
1431
+ const paramSchema = param.schema;
1432
+ if (paramSchema && paramSchema["$ref"]) {
1433
+ const bodyName = paramSchema["$ref"].substring(paramSchema["$ref"].lastIndexOf("/") + 1);
1434
+ if (openapiSpec && openapiSpec["components"] != null && openapiSpec["components"]["schemas"] != null) {
1435
+ const def = openapiSpec["components"] != null ? openapiSpec["components"]["schemas"][bodyName] : { type: "" };
1436
+ param.type = parseElementType(def);
1437
+ param.uiType = param.type == "integer" || param.type == "number" ? "number" : "text";
1438
+ param.value = parseElement(def);
1439
+ }
1440
+ }
1441
+ }
993
1442
  }
994
1443
  }
995
- if (operation.requestBody) {
996
- const requestBodyObject = operation.requestBody;
997
- const content = requestBodyObject.content;
1444
+ if (apiOperator.rawApiInfo.requestBody) {
1445
+ const content = apiOperator.rawApiInfo.requestBody.content;
1446
+ apiOperator["requestBody"] = {
1447
+ content: {}
1448
+ };
998
1449
  for (const key in content) {
999
1450
  if (Object.prototype.hasOwnProperty.call(content, key)) {
1000
1451
  const element = content[key];
1452
+ apiOperator["consumes"]?.push(key);
1001
1453
  if (element) {
1002
- let requestBody = parseParaModel(element, openapiSpec["components"]["schemas"]);
1003
- apiOperator.requestBody = requestBody;
1454
+ if (element.schema == void 0) {
1455
+ console.log("pathKey is:", path);
1456
+ console.log("key is:", key);
1457
+ console.log("content is:", content);
1458
+ console.log("Unsupported requestBody schema format:", element);
1459
+ continue;
1460
+ }
1461
+ if (key != "application/x-www-form-urlencoded" && key != "multipart/form-data") {
1462
+ let requestBody = parseParaModel(element, openapiSpec["components"]["schemas"]);
1463
+ apiOperator["requestBody"]["content"][key] = JSON.stringify(requestBody, null, 4);
1464
+ } else {
1465
+ let requestFormDataBody = parseFormDataParaModel(element, openapiSpec["components"]["schemas"]);
1466
+ apiOperator["requestBody"]["content"][key] = requestFormDataBody;
1467
+ }
1468
+ apiOperator["parameterHasBody"] = true;
1004
1469
  }
1005
1470
  }
1006
1471
  }
1472
+ if (apiOperator.consumes) {
1473
+ if (apiOperator.consumes.length > 0) {
1474
+ apiOperator["currentConsume"] = apiOperator["consumes"][0];
1475
+ }
1476
+ }
1007
1477
  }
1008
- apiOperator.rawApiInfo = operation;
1009
1478
  apiOperatorList.push(apiOperator);
1010
1479
  }
1011
1480
  });