@scalar/api-client 3.0.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +41 -0
  3. package/dist/components/HttpMethod/HttpMethod.vue.d.ts +2 -2
  4. package/dist/components/Sidebar/Actions/SidebarListElementForm.vue.d.ts +2 -2
  5. package/dist/plugins/posthog/index.d.ts +23 -0
  6. package/dist/plugins/posthog/index.d.ts.map +1 -0
  7. package/dist/plugins/posthog/index.js +58 -0
  8. package/dist/plugins/posthog/index.js.map +1 -0
  9. package/dist/style.css +121 -61
  10. package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts.map +1 -1
  11. package/dist/v2/blocks/operation-block/OperationBlock.vue.js.map +1 -1
  12. package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js +15 -12
  13. package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js.map +1 -1
  14. package/dist/v2/blocks/operation-block/helpers/decode-buffer.d.ts +5 -2
  15. package/dist/v2/blocks/operation-block/helpers/decode-buffer.d.ts.map +1 -1
  16. package/dist/v2/blocks/operation-block/helpers/decode-buffer.js +5 -2
  17. package/dist/v2/blocks/operation-block/helpers/decode-buffer.js.map +1 -1
  18. package/dist/v2/blocks/operation-block/helpers/har-to-fetch-request.d.ts +8 -9
  19. package/dist/v2/blocks/operation-block/helpers/har-to-fetch-request.d.ts.map +1 -1
  20. package/dist/v2/blocks/operation-block/helpers/har-to-fetch-request.js +8 -10
  21. package/dist/v2/blocks/operation-block/helpers/har-to-fetch-request.js.map +1 -1
  22. package/dist/v2/blocks/operation-block/helpers/response-cache.d.ts +2 -1
  23. package/dist/v2/blocks/operation-block/helpers/response-cache.d.ts.map +1 -1
  24. package/dist/v2/blocks/operation-block/helpers/response-cache.js.map +1 -1
  25. package/dist/v2/blocks/operation-block/helpers/send-request.d.ts +11 -3
  26. package/dist/v2/blocks/operation-block/helpers/send-request.d.ts.map +1 -1
  27. package/dist/v2/blocks/operation-block/helpers/send-request.js +19 -12
  28. package/dist/v2/blocks/operation-block/helpers/send-request.js.map +1 -1
  29. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.d.ts.map +1 -1
  30. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.js +1 -1
  31. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.js.map +1 -1
  32. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.script.js +4 -0
  33. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.script.js.map +1 -1
  34. package/dist/v2/blocks/request-block/RequestBlock.vue.script.js +1 -1
  35. package/dist/v2/blocks/request-block/components/RequestBody.vue.d.ts.map +1 -1
  36. package/dist/v2/blocks/request-block/components/RequestBody.vue.js +1 -1
  37. package/dist/v2/blocks/request-block/components/RequestBody.vue.js.map +1 -1
  38. package/dist/v2/blocks/request-block/components/RequestBody.vue.script.js +1 -0
  39. package/dist/v2/blocks/request-block/components/RequestBody.vue.script.js.map +1 -1
  40. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.d.ts.map +1 -1
  41. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.js.map +1 -1
  42. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.script.js +1 -0
  43. package/dist/v2/blocks/request-block/components/RequestTableRow.vue.script.js.map +1 -1
  44. package/dist/v2/blocks/request-block/helpers/get-default-headers.js +1 -1
  45. package/dist/v2/blocks/response-block/ResponseBlock.vue.d.ts +3 -2
  46. package/dist/v2/blocks/response-block/ResponseBlock.vue.d.ts.map +1 -1
  47. package/dist/v2/blocks/response-block/ResponseBlock.vue.js +1 -1
  48. package/dist/v2/blocks/response-block/ResponseBlock.vue.js.map +1 -1
  49. package/dist/v2/blocks/response-block/ResponseBlock.vue.script.js +12 -6
  50. package/dist/v2/blocks/response-block/ResponseBlock.vue.script.js.map +1 -1
  51. package/dist/v2/blocks/response-block/components/ResponseBody.vue.d.ts +2 -0
  52. package/dist/v2/blocks/response-block/components/ResponseBody.vue.d.ts.map +1 -1
  53. package/dist/v2/blocks/response-block/components/ResponseBody.vue.js +1 -1
  54. package/dist/v2/blocks/response-block/components/ResponseBody.vue.js.map +1 -1
  55. package/dist/v2/blocks/response-block/components/ResponseBody.vue.script.js +34 -14
  56. package/dist/v2/blocks/response-block/components/ResponseBody.vue.script.js.map +1 -1
  57. package/dist/v2/blocks/response-block/helpers/process-response-body.d.ts +1 -1
  58. package/dist/v2/blocks/response-block/helpers/process-response-body.js +2 -3
  59. package/dist/v2/blocks/response-block/helpers/process-response-body.js.map +1 -1
  60. package/dist/v2/blocks/response-block/helpers/resolve-response-body-handler.d.ts +11 -0
  61. package/dist/v2/blocks/response-block/helpers/resolve-response-body-handler.d.ts.map +1 -0
  62. package/dist/v2/blocks/response-block/helpers/resolve-response-body-handler.js +44 -0
  63. package/dist/v2/blocks/response-block/helpers/resolve-response-body-handler.js.map +1 -0
  64. package/dist/v2/blocks/response-block/helpers/resolve-response-content-type.d.ts +14 -0
  65. package/dist/v2/blocks/response-block/helpers/resolve-response-content-type.d.ts.map +1 -0
  66. package/dist/v2/blocks/response-block/helpers/resolve-response-content-type.js +13 -0
  67. package/dist/v2/blocks/response-block/helpers/resolve-response-content-type.js.map +1 -0
  68. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.d.ts +1 -1
  69. package/dist/v2/blocks/scalar-address-bar-block/components/EnvironmentSelector.vue.js.map +1 -1
  70. package/dist/v2/blocks/scalar-address-bar-block/components/EnvironmentSelector.vue.script.js +3 -3
  71. package/dist/v2/blocks/scalar-address-bar-block/components/EnvironmentSelector.vue.script.js.map +1 -1
  72. package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.script.js.map +1 -1
  73. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.d.ts.map +1 -1
  74. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.js.map +1 -1
  75. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.script.js +131 -48
  76. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.script.js.map +1 -1
  77. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuthScopesAddModal.vue.d.ts +2 -2
  78. package/dist/v2/blocks/scalar-auth-selector-block/components/OAuthScopesAddModal.vue.d.ts.map +1 -1
  79. package/dist/v2/blocks/scalar-auth-selector-block/helpers/extract-security-scheme-secrets.d.ts.map +1 -1
  80. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.d.ts +16 -0
  81. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.d.ts.map +1 -1
  82. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.js +43 -1
  83. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.js.map +1 -1
  84. package/dist/v2/components/code-input/CodeInput.vue.d.ts +6 -2
  85. package/dist/v2/components/code-input/CodeInput.vue.d.ts.map +1 -1
  86. package/dist/v2/components/code-input/CodeInput.vue.js +1 -1
  87. package/dist/v2/components/code-input/CodeInput.vue.js.map +1 -1
  88. package/dist/v2/components/code-input/CodeInput.vue.script.js +9 -4
  89. package/dist/v2/components/code-input/CodeInput.vue.script.js.map +1 -1
  90. package/dist/v2/components/data-table/DataTableInput.vue.d.ts +3 -0
  91. package/dist/v2/components/data-table/DataTableInput.vue.d.ts.map +1 -1
  92. package/dist/v2/components/data-table/DataTableInput.vue.js +1 -1
  93. package/dist/v2/components/data-table/DataTableInput.vue.js.map +1 -1
  94. package/dist/v2/components/data-table/DataTableInput.vue.script.js +7 -1
  95. package/dist/v2/components/data-table/DataTableInput.vue.script.js.map +1 -1
  96. package/dist/v2/components/forms/ConfirmationForm.vue.d.ts +2 -2
  97. package/dist/v2/constants.js +1 -1
  98. package/dist/v2/features/app/App.vue.d.ts.map +1 -1
  99. package/dist/v2/features/app/App.vue.js.map +1 -1
  100. package/dist/v2/features/app/App.vue.script.js +17 -4
  101. package/dist/v2/features/app/App.vue.script.js.map +1 -1
  102. package/dist/v2/features/app/app-state.d.ts +6 -1
  103. package/dist/v2/features/app/app-state.d.ts.map +1 -1
  104. package/dist/v2/features/app/app-state.js +5 -3
  105. package/dist/v2/features/app/app-state.js.map +1 -1
  106. package/dist/v2/features/app/components/DesktopTab.vue.d.ts +2 -2
  107. package/dist/v2/features/app/helpers/create-api-client-app.d.ts +9 -1
  108. package/dist/v2/features/app/helpers/create-api-client-app.d.ts.map +1 -1
  109. package/dist/v2/features/app/helpers/create-api-client-app.js +3 -2
  110. package/dist/v2/features/app/helpers/create-api-client-app.js.map +1 -1
  111. package/dist/v2/features/app/helpers/create-temp-operation.d.ts.map +1 -1
  112. package/dist/v2/features/app/helpers/create-temp-operation.js +4 -1
  113. package/dist/v2/features/app/helpers/create-temp-operation.js.map +1 -1
  114. package/dist/v2/features/app/helpers/routes.d.ts +4 -2
  115. package/dist/v2/features/app/helpers/routes.d.ts.map +1 -1
  116. package/dist/v2/features/app/helpers/routes.js.map +1 -1
  117. package/dist/v2/features/collection/DocumentCollection.vue.script.js +2 -1
  118. package/dist/v2/features/collection/DocumentCollection.vue.script.js.map +1 -1
  119. package/dist/v2/features/collection/OperationCollection.vue.script.js +2 -1
  120. package/dist/v2/features/collection/OperationCollection.vue.script.js.map +1 -1
  121. package/dist/v2/features/collection/WorkspaceCollection.vue.script.js +2 -1
  122. package/dist/v2/features/collection/WorkspaceCollection.vue.script.js.map +1 -1
  123. package/dist/v2/features/collection/components/Authentication.vue.d.ts.map +1 -1
  124. package/dist/v2/features/collection/components/Authentication.vue.js +1 -1
  125. package/dist/v2/features/collection/components/Authentication.vue.js.map +1 -1
  126. package/dist/v2/features/collection/components/Authentication.vue.script.js +10 -1
  127. package/dist/v2/features/collection/components/Authentication.vue.script.js.map +1 -1
  128. package/dist/v2/features/collection/components/Cookies.vue.script.js +1 -0
  129. package/dist/v2/features/collection/components/Cookies.vue.script.js.map +1 -1
  130. package/dist/v2/features/collection/components/Editor/Editor.vue.script.js +1 -0
  131. package/dist/v2/features/collection/components/Editor/Editor.vue.script.js.map +1 -1
  132. package/dist/v2/features/collection/components/Environment.vue.script.js +1 -0
  133. package/dist/v2/features/collection/components/Environment.vue.script.js.map +1 -1
  134. package/dist/v2/features/collection/components/Form.vue.d.ts +2 -0
  135. package/dist/v2/features/collection/components/Form.vue.d.ts.map +1 -1
  136. package/dist/v2/features/collection/components/Form.vue.js.map +1 -1
  137. package/dist/v2/features/collection/components/Form.vue.script.js +4 -1
  138. package/dist/v2/features/collection/components/Form.vue.script.js.map +1 -1
  139. package/dist/v2/features/collection/components/LabelInput.vue.d.ts +1 -1
  140. package/dist/v2/features/collection/components/Overview.vue.script.js +1 -0
  141. package/dist/v2/features/collection/components/Overview.vue.script.js.map +1 -1
  142. package/dist/v2/features/collection/components/Runner/components/Runner.vue.d.ts.map +1 -1
  143. package/dist/v2/features/collection/components/Runner/components/Runner.vue.js.map +1 -1
  144. package/dist/v2/features/collection/components/Runner/components/Runner.vue.script.js +4 -2
  145. package/dist/v2/features/collection/components/Runner/components/Runner.vue.script.js.map +1 -1
  146. package/dist/v2/features/collection/components/Runner/components/RunnerTree.vue.d.ts +2 -2
  147. package/dist/v2/features/collection/components/Runner/hooks/use-runner-execution.d.ts +4 -2
  148. package/dist/v2/features/collection/components/Runner/hooks/use-runner-execution.d.ts.map +1 -1
  149. package/dist/v2/features/collection/components/Runner/hooks/use-runner-execution.js +3 -2
  150. package/dist/v2/features/collection/components/Runner/hooks/use-runner-execution.js.map +1 -1
  151. package/dist/v2/features/collection/components/Scripts.vue.script.js +1 -0
  152. package/dist/v2/features/collection/components/Scripts.vue.script.js.map +1 -1
  153. package/dist/v2/features/collection/components/Servers.vue.d.ts.map +1 -1
  154. package/dist/v2/features/collection/components/Servers.vue.js.map +1 -1
  155. package/dist/v2/features/collection/components/Servers.vue.script.js +3 -1
  156. package/dist/v2/features/collection/components/Servers.vue.script.js.map +1 -1
  157. package/dist/v2/features/collection/components/Settings.vue.script.js +1 -0
  158. package/dist/v2/features/collection/components/Settings.vue.script.js.map +1 -1
  159. package/dist/v2/features/command-palette/components/CommandActionForm.vue.d.ts +2 -2
  160. package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.d.ts.map +1 -1
  161. package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.js.map +1 -1
  162. package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.script.js +1 -1
  163. package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.script.js.map +1 -1
  164. package/dist/v2/features/command-palette/components/CommandPaletteImportPostman.vue.d.ts.map +1 -1
  165. package/dist/v2/features/command-palette/components/CommandPaletteImportPostman.vue.js.map +1 -1
  166. package/dist/v2/features/command-palette/components/CommandPaletteImportPostman.vue.script.js +26 -21
  167. package/dist/v2/features/command-palette/components/CommandPaletteImportPostman.vue.script.js.map +1 -1
  168. package/dist/v2/features/command-palette/components/PostmanImportPreview.vue.js +1 -1
  169. package/dist/v2/features/command-palette/components/PostmanImportPreview.vue.js.map +1 -1
  170. package/dist/v2/features/command-palette/components/PostmanImportPreview.vue.script.js +1 -1
  171. package/dist/v2/features/command-palette/components/PostmanImportPreview.vue.script.js.map +1 -1
  172. package/dist/v2/features/command-palette/helpers/get-postman-convert-options.d.ts +14 -0
  173. package/dist/v2/features/command-palette/helpers/get-postman-convert-options.d.ts.map +1 -0
  174. package/dist/v2/features/command-palette/helpers/get-postman-convert-options.js +19 -0
  175. package/dist/v2/features/command-palette/helpers/get-postman-convert-options.js.map +1 -0
  176. package/dist/v2/features/command-palette/helpers/get-postman-document-details.js +1 -1
  177. package/dist/v2/features/command-palette/helpers/get-postman-document-details.js.map +1 -1
  178. package/dist/v2/features/command-palette/helpers/load-document-from-source.d.ts.map +1 -1
  179. package/dist/v2/features/command-palette/helpers/load-document-from-source.js +1 -1
  180. package/dist/v2/features/command-palette/helpers/load-document-from-source.js.map +1 -1
  181. package/dist/v2/features/environments/components/EnvironmentDeleteModal.vue.d.ts +2 -2
  182. package/dist/v2/features/environments/components/EnvironmentVariablesDropdown.vue.d.ts +1 -1
  183. package/dist/v2/features/environments/components/EnvironmentVariablesDropdown.vue.d.ts.map +1 -1
  184. package/dist/v2/features/environments/components/EnvironmentVariablesDropdown.vue.js.map +1 -1
  185. package/dist/v2/features/environments/components/EnvironmentVariablesDropdown.vue.script.js +2 -2
  186. package/dist/v2/features/environments/components/EnvironmentVariablesDropdown.vue.script.js.map +1 -1
  187. package/dist/v2/features/global-cookies/components/CookiesTable.vue.d.ts.map +1 -1
  188. package/dist/v2/features/global-cookies/components/CookiesTable.vue.js +1 -1
  189. package/dist/v2/features/global-cookies/components/CookiesTable.vue.js.map +1 -1
  190. package/dist/v2/features/global-cookies/components/CookiesTable.vue.script.js +2 -0
  191. package/dist/v2/features/global-cookies/components/CookiesTable.vue.script.js.map +1 -1
  192. package/dist/v2/features/modal/Modal.vue.d.ts +7 -6
  193. package/dist/v2/features/modal/Modal.vue.d.ts.map +1 -1
  194. package/dist/v2/features/modal/Modal.vue.js.map +1 -1
  195. package/dist/v2/features/modal/Modal.vue.script.js.map +1 -1
  196. package/dist/v2/features/modal/helpers/create-api-client-modal.d.ts +5 -5
  197. package/dist/v2/features/modal/helpers/create-api-client-modal.d.ts.map +1 -1
  198. package/dist/v2/features/modal/helpers/create-api-client-modal.js +11 -0
  199. package/dist/v2/features/modal/helpers/create-api-client-modal.js.map +1 -1
  200. package/dist/v2/features/modal/helpers/types.d.ts +1 -7
  201. package/dist/v2/features/modal/helpers/types.d.ts.map +1 -1
  202. package/dist/v2/features/modal/index.d.ts +1 -1
  203. package/dist/v2/features/modal/index.d.ts.map +1 -1
  204. package/dist/v2/features/operation/Operation.vue.d.ts +0 -5
  205. package/dist/v2/features/operation/Operation.vue.d.ts.map +1 -1
  206. package/dist/v2/features/operation/Operation.vue.js.map +1 -1
  207. package/dist/v2/features/operation/Operation.vue.script.js.map +1 -1
  208. package/dist/v2/types/options.d.ts +15 -0
  209. package/dist/v2/types/options.d.ts.map +1 -0
  210. package/package.json +21 -16
  211. package/dist/v2/features/command-palette/helpers/is-postman-collection.d.ts +0 -11
  212. package/dist/v2/features/command-palette/helpers/is-postman-collection.d.ts.map +0 -1
  213. package/dist/v2/features/command-palette/helpers/is-postman-collection.js +0 -24
  214. package/dist/v2/features/command-palette/helpers/is-postman-collection.js.map +0 -1
  215. package/dist/v2/posthog.d.ts +0 -3
  216. package/dist/v2/posthog.d.ts.map +0 -1
  217. package/dist/v2/posthog.js +0 -20
  218. package/dist/v2/posthog.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, normalizeClass, openBlock, renderList, toDisplayString, unref, withCtx, withModifiers } from "vue";
1
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, normalizeClass, openBlock, renderList, toDisplayString, unref, withCtx } from "vue";
2
2
  import { ScalarButton, ScalarDropdown, ScalarDropdownDivider, ScalarDropdownItem, ScalarIcon } from "@scalar/components";
3
3
  //#region src/v2/blocks/scalar-address-bar-block/components/EnvironmentSelector.vue?vue&type=script&setup=true&lang.ts
4
4
  var _hoisted_1 = { class: "relative flex items-center" };
@@ -59,7 +59,7 @@ var EnvironmentSelector_vue_vue_type_script_setup_true_lang_default = /* @__PURE
59
59
  hasActiveEnvironment.value ? (openBlock(), createBlock(unref(ScalarDropdownItem), {
60
60
  key: 0,
61
61
  class: "group/item flex w-full items-center gap-1.5",
62
- onClick: _cache[0] || (_cache[0] = withModifiers(($event) => handleSelectEnvironment(""), ["stop"]))
62
+ onClick: _cache[0] || (_cache[0] = ($event) => handleSelectEnvironment(""))
63
63
  }, {
64
64
  default: withCtx(() => [createElementVNode("div", { class: normalizeClass(["flex h-4 w-4 items-center justify-center rounded-full p-[3px]", !__props.activeEnvironment ? "bg-c-accent text-b-1" : "shadow-border text-transparent"]) }, [createVNode(unref(ScalarIcon), {
65
65
  class: "size-2.5",
@@ -73,7 +73,7 @@ var EnvironmentSelector_vue_vue_type_script_setup_true_lang_default = /* @__PURE
73
73
  return openBlock(), createBlock(unref(ScalarDropdownItem), {
74
74
  key: environmentName,
75
75
  class: "group/item flex w-full min-w-0 items-center gap-1.5 overflow-hidden text-ellipsis whitespace-nowrap",
76
- onClick: withModifiers(($event) => handleSelectEnvironment(environmentName), ["stop"])
76
+ onClick: ($event) => handleSelectEnvironment(environmentName)
77
77
  }, {
78
78
  default: withCtx(() => [createElementVNode("div", { class: normalizeClass(["flex h-4 w-4 items-center justify-center rounded-full p-[3px]", __props.activeEnvironment === environmentName ? "bg-c-accent text-b-1" : "shadow-border text-transparent"]) }, [createVNode(unref(ScalarIcon), {
79
79
  class: "size-2.5",
@@ -1 +1 @@
1
- {"version":3,"file":"EnvironmentSelector.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-address-bar-block/components/EnvironmentSelector.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarDropdown,\n ScalarDropdownDivider,\n ScalarDropdownItem,\n ScalarIcon,\n} from '@scalar/components'\nimport { computed } from 'vue'\n\nconst { environments = [], activeEnvironment } = defineProps<{\n /** List of available environments */\n environments?: string[]\n /** Currently selected environment */\n activeEnvironment?: string\n}>()\n\nconst emit = defineEmits<{\n /** Emitted when an environment is selected */\n (e: 'select:environment', environmentName: string): void\n /** Emitted when user wants to add a new environment */\n (e: 'add:environment'): void\n}>()\n\n/** Whether an environment is currently active */\nconst hasActiveEnvironment = computed(() => !!activeEnvironment)\n\n/** Whether environments exist */\nconst hasEnvironments = computed(() => environments.length > 0)\n\n/** Whether the currently selected environment exists in the dropdown options */\nconst hasSelectedEnvironmentInOptions = computed(() => {\n if (!activeEnvironment) {\n return false\n }\n\n return environments.includes(activeEnvironment)\n})\n\n/** True when an environment is selected but unavailable in the current context */\nconst hasMissingActiveEnvironment = computed(\n () => hasActiveEnvironment.value && !hasSelectedEnvironmentInOptions.value,\n)\n\n/** Display text for the button */\nconst displayText = computed(() => {\n if (hasMissingActiveEnvironment.value) {\n return `${activeEnvironment} (Unavailable)`\n }\n\n if (hasActiveEnvironment.value) {\n return activeEnvironment\n }\n if (!hasEnvironments.value) {\n return 'Add Environment'\n }\n return 'Select Environment'\n})\n\n/** Button styling based on state */\nconst buttonClass = computed(() => {\n if (hasMissingActiveEnvironment.value) {\n return 'hover:bg-b-2 text-c-2 border-transparent'\n }\n\n if (hasActiveEnvironment.value) {\n return 'bg-c-accent/10 text-c-accent hover:bg-c-accent/20 border-c-accent/30'\n }\n if (!hasEnvironments.value) {\n return 'hover:bg-b-2 text-c-3 border-transparent'\n }\n return 'hover:bg-b-2 text-c-2 border-transparent'\n})\n\nconst handleAddEnvironment = () => {\n emit('add:environment')\n}\n\nconst handleSelectEnvironment = (environmentName: string) => {\n emit('select:environment', environmentName)\n}\n</script>\n\n<template>\n <div class=\"relative flex items-center\">\n <!-- Environment indicator badge (only show when active) -->\n\n <ScalarDropdown>\n <ScalarButton\n :aria-label=\"`Current environment: ${displayText}`\"\n class=\"line-clamp-1 h-full w-fit justify-start border px-2 py-1 font-normal transition-colors\"\n :class=\"buttonClass\"\n size=\"sm\"\n variant=\"ghost\">\n <div class=\"flex max-w-[220px] min-w-0 items-center gap-1.5\">\n <!-- Icon indicator -->\n <ScalarIcon\n class=\"shrink-0\"\n :class=\"\n hasActiveEnvironment && !hasMissingActiveEnvironment\n ? 'text-c-accent'\n : 'text-c-3'\n \"\n icon=\"Globe\"\n size=\"sm\" />\n\n <!-- Environment name -->\n <span\n class=\"text-xxs block max-w-[160px] min-w-0 truncate text-left font-medium\">\n {{ displayText }}\n </span>\n\n <!-- Dropdown arrow -->\n <ScalarIcon\n class=\"shrink-0\"\n icon=\"ChevronDown\"\n size=\"xs\" />\n </div>\n </ScalarButton>\n\n <template #items>\n <!-- No environment option (clear selection) -->\n <ScalarDropdownItem\n v-if=\"hasActiveEnvironment\"\n class=\"group/item flex w-full items-center gap-1.5\"\n @click.stop=\"handleSelectEnvironment('')\">\n <div\n class=\"flex h-4 w-4 items-center justify-center rounded-full p-[3px]\"\n :class=\"\n !activeEnvironment\n ? 'bg-c-accent text-b-1'\n : 'shadow-border text-transparent'\n \">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <span class=\"text-c-2\">No Environment</span>\n </ScalarDropdownItem>\n\n <ScalarDropdownDivider v-if=\"hasActiveEnvironment && hasEnvironments\" />\n\n <!-- Environment list -->\n <ScalarDropdownItem\n v-for=\"environmentName in environments\"\n :key=\"environmentName\"\n class=\"group/item flex w-full min-w-0 items-center gap-1.5 overflow-hidden text-ellipsis whitespace-nowrap\"\n @click.stop=\"handleSelectEnvironment(environmentName)\">\n <div\n class=\"flex h-4 w-4 items-center justify-center rounded-full p-[3px]\"\n :class=\"\n activeEnvironment === environmentName\n ? 'bg-c-accent text-b-1'\n : 'shadow-border text-transparent'\n \">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <span class=\"min-w-0 flex-1 truncate\">{{ environmentName }}</span>\n </ScalarDropdownItem>\n <ScalarDropdownDivider v-if=\"hasMissingActiveEnvironment\" />\n\n <ScalarDropdownItem\n v-if=\"hasMissingActiveEnvironment\"\n class=\"group/item flex h-auto w-full min-w-0 items-start gap-1.5 overflow-hidden\"\n disabled>\n <div\n class=\"bg-c-accent text-b-1 mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full p-[3px]\">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <div class=\"min-w-0 flex-1 text-left\">\n <span class=\"block truncate\">\n {{ activeEnvironment }}\n </span>\n <span class=\"text-c-3 block truncate text-xs\">\n Not available in this context\n </span>\n </div>\n </ScalarDropdownItem>\n\n <ScalarDropdownDivider v-if=\"hasEnvironments\" />\n\n <!-- Add new environment button -->\n <ScalarDropdownItem\n class=\"text-c-accent flex items-center gap-1.5\"\n @click=\"handleAddEnvironment\">\n <div class=\"flex h-4 w-4 items-center justify-center\">\n <ScalarIcon\n icon=\"Add\"\n size=\"sm\" />\n </div>\n <span>{{\n hasEnvironments ? 'New Environment' : 'Create Environment'\n }}</span>\n </ScalarDropdownItem>\n\n <!-- Helper text for empty state -->\n <div\n v-if=\"!hasEnvironments && !hasActiveEnvironment\"\n class=\"text-c-3 px-2 py-1.5 text-xs\">\n <p class=\"mb-1\">\n Environments let you manage variables like API keys and base URLs\n across different contexts.\n </p>\n </div>\n </template>\n </ScalarDropdown>\n </div>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"EnvironmentSelector.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-address-bar-block/components/EnvironmentSelector.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarDropdown,\n ScalarDropdownDivider,\n ScalarDropdownItem,\n ScalarIcon,\n} from '@scalar/components'\nimport { computed } from 'vue'\n\nconst { environments = [], activeEnvironment } = defineProps<{\n /** List of available environments */\n environments?: string[]\n /** Currently selected environment */\n activeEnvironment?: string\n}>()\n\nconst emit = defineEmits<{\n /** Emitted when an environment is selected */\n (e: 'select:environment', environmentName: string): void\n /** Emitted when user wants to add a new environment */\n (e: 'add:environment'): void\n}>()\n\n/** Whether an environment is currently active */\nconst hasActiveEnvironment = computed(() => !!activeEnvironment)\n\n/** Whether environments exist */\nconst hasEnvironments = computed(() => environments.length > 0)\n\n/** Whether the currently selected environment exists in the dropdown options */\nconst hasSelectedEnvironmentInOptions = computed(() => {\n if (!activeEnvironment) {\n return false\n }\n\n return environments.includes(activeEnvironment)\n})\n\n/** True when an environment is selected but unavailable in the current context */\nconst hasMissingActiveEnvironment = computed(\n () => hasActiveEnvironment.value && !hasSelectedEnvironmentInOptions.value,\n)\n\n/** Display text for the button */\nconst displayText = computed(() => {\n if (hasMissingActiveEnvironment.value) {\n return `${activeEnvironment} (Unavailable)`\n }\n\n if (hasActiveEnvironment.value) {\n return activeEnvironment\n }\n if (!hasEnvironments.value) {\n return 'Add Environment'\n }\n return 'Select Environment'\n})\n\n/** Button styling based on state */\nconst buttonClass = computed(() => {\n if (hasMissingActiveEnvironment.value) {\n return 'hover:bg-b-2 text-c-2 border-transparent'\n }\n\n if (hasActiveEnvironment.value) {\n return 'bg-c-accent/10 text-c-accent hover:bg-c-accent/20 border-c-accent/30'\n }\n if (!hasEnvironments.value) {\n return 'hover:bg-b-2 text-c-3 border-transparent'\n }\n return 'hover:bg-b-2 text-c-2 border-transparent'\n})\n\nconst handleAddEnvironment = () => {\n emit('add:environment')\n}\n\nconst handleSelectEnvironment = (environmentName: string) => {\n emit('select:environment', environmentName)\n}\n</script>\n\n<template>\n <div class=\"relative flex items-center\">\n <!-- Environment indicator badge (only show when active) -->\n\n <ScalarDropdown>\n <ScalarButton\n :aria-label=\"`Current environment: ${displayText}`\"\n class=\"line-clamp-1 h-full w-fit justify-start border px-2 py-1 font-normal transition-colors\"\n :class=\"buttonClass\"\n size=\"sm\"\n variant=\"ghost\">\n <div class=\"flex max-w-[220px] min-w-0 items-center gap-1.5\">\n <!-- Icon indicator -->\n <ScalarIcon\n class=\"shrink-0\"\n :class=\"\n hasActiveEnvironment && !hasMissingActiveEnvironment\n ? 'text-c-accent'\n : 'text-c-3'\n \"\n icon=\"Globe\"\n size=\"sm\" />\n\n <!-- Environment name -->\n <span\n class=\"text-xxs block max-w-[160px] min-w-0 truncate text-left font-medium\">\n {{ displayText }}\n </span>\n\n <!-- Dropdown arrow -->\n <ScalarIcon\n class=\"shrink-0\"\n icon=\"ChevronDown\"\n size=\"xs\" />\n </div>\n </ScalarButton>\n\n <template #items>\n <!-- No environment option (clear selection) -->\n <ScalarDropdownItem\n v-if=\"hasActiveEnvironment\"\n class=\"group/item flex w-full items-center gap-1.5\"\n @click=\"handleSelectEnvironment('')\">\n <div\n class=\"flex h-4 w-4 items-center justify-center rounded-full p-[3px]\"\n :class=\"\n !activeEnvironment\n ? 'bg-c-accent text-b-1'\n : 'shadow-border text-transparent'\n \">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <span class=\"text-c-2\">No Environment</span>\n </ScalarDropdownItem>\n\n <ScalarDropdownDivider v-if=\"hasActiveEnvironment && hasEnvironments\" />\n\n <!-- Environment list -->\n <ScalarDropdownItem\n v-for=\"environmentName in environments\"\n :key=\"environmentName\"\n class=\"group/item flex w-full min-w-0 items-center gap-1.5 overflow-hidden text-ellipsis whitespace-nowrap\"\n @click=\"handleSelectEnvironment(environmentName)\">\n <div\n class=\"flex h-4 w-4 items-center justify-center rounded-full p-[3px]\"\n :class=\"\n activeEnvironment === environmentName\n ? 'bg-c-accent text-b-1'\n : 'shadow-border text-transparent'\n \">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <span class=\"min-w-0 flex-1 truncate\">{{ environmentName }}</span>\n </ScalarDropdownItem>\n <ScalarDropdownDivider v-if=\"hasMissingActiveEnvironment\" />\n\n <ScalarDropdownItem\n v-if=\"hasMissingActiveEnvironment\"\n class=\"group/item flex h-auto w-full min-w-0 items-start gap-1.5 overflow-hidden\"\n disabled>\n <div\n class=\"bg-c-accent text-b-1 mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full p-[3px]\">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <div class=\"min-w-0 flex-1 text-left\">\n <span class=\"block truncate\">\n {{ activeEnvironment }}\n </span>\n <span class=\"text-c-3 block truncate text-xs\">\n Not available in this context\n </span>\n </div>\n </ScalarDropdownItem>\n\n <ScalarDropdownDivider v-if=\"hasEnvironments\" />\n\n <!-- Add new environment button -->\n <ScalarDropdownItem\n class=\"text-c-accent flex items-center gap-1.5\"\n @click=\"handleAddEnvironment\">\n <div class=\"flex h-4 w-4 items-center justify-center\">\n <ScalarIcon\n icon=\"Add\"\n size=\"sm\" />\n </div>\n <span>{{\n hasEnvironments ? 'New Environment' : 'Create Environment'\n }}</span>\n </ScalarDropdownItem>\n\n <!-- Helper text for empty state -->\n <div\n v-if=\"!hasEnvironments && !hasActiveEnvironment\"\n class=\"text-c-3 px-2 py-1.5 text-xs\">\n <p class=\"mb-1\">\n Environments let you manage variables like API keys and base URLs\n across different contexts.\n </p>\n </div>\n </template>\n </ScalarDropdown>\n </div>\n</template>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"AuthSelector.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarComboboxMultiselect,\n ScalarIconButton,\n ScalarListboxCheckbox,\n useModal,\n type Icon,\n type ScalarButton as ScalarButtonType,\n} from '@scalar/components'\nimport { ScalarIconCaretDown, ScalarIconTrash } from '@scalar/icons'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type {\n AuthMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n isAuthOptional,\n type MergedSecuritySchemes,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n OpenApiDocument,\n SecurityRequirementObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, useId } from 'vue'\n\nimport DeleteRequestAuthModal from '@/v2/blocks/scalar-auth-selector-block/components/DeleteRequestAuthModal.vue'\nimport type { OAuth2Options } from '@/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue'\nimport {\n formatComplexScheme,\n formatScheme,\n getSecuritySchemeOptions,\n type SecuritySchemeOption,\n} from '@/v2/blocks/scalar-auth-selector-block/helpers/security-scheme'\nimport { CollapsibleSection } from '@/v2/components/layout'\n\nimport RequestAuthDataTable from './RequestAuthDataTable.vue'\n\nconst {\n environment,\n eventBus,\n createAnySecurityScheme = false,\n defaultOpen = true,\n isStatic = false,\n meta,\n proxyUrl,\n securityRequirements,\n securitySchemes,\n selectedSecurity,\n server,\n title,\n options,\n} = defineProps<{\n environment: XScalarEnvironment\n eventBus: WorkspaceEventBus\n /** Allows adding authentication which is not in the document */\n createAnySecurityScheme?: boolean\n /** Whether the authentication disclosure should start expanded */\n defaultOpen?: boolean\n /** Creates a static disclosure that cannot be collapsed */\n isStatic?: boolean\n meta: AuthMeta\n proxyUrl: string\n securityRequirements: OpenApiDocument['security']\n securitySchemes: MergedSecuritySchemes\n selectedSecurity: SelectedSecurity | undefined\n server: ServerObject | null\n title: string\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}>()\n\nconst titleId = useId()\nconst comboboxButtonRef = ref<typeof ScalarButtonType | null>(null)\nconst isDisclosureOpen = ref(false)\n\nconst deleteModal = useModal()\nconst schemeToDelete = ref<{\n label: string\n payload: SecurityRequirementObject\n} | null>(null)\n\n/**\n * Determines if authentication is required or optional\n *\n * Auth is optional when there is an empty security requirement and no complex requirements.\n * Complex requirements have multiple auth schemes combined (e.g., API key + OAuth).\n */\nconst authIndicator = computed<{ icon: Icon; text: string } | null>(() => {\n if (!securityRequirements?.length) {\n return null\n }\n\n const isOptional = isAuthOptional(securityRequirements)\n\n return {\n icon: isOptional ? 'Unlock' : 'Lock',\n text: isOptional ? 'Optional' : 'Required',\n }\n})\n\n/** All available auth scheme options for the dropdown */\nconst availableSchemeOptions = computed(() =>\n getSecuritySchemeOptions(\n securityRequirements ?? [],\n securitySchemes ?? {},\n selectedSecurity?.selectedSchemes ?? [],\n createAnySecurityScheme,\n ),\n)\n\n/** Currently active auth schemes selected for this operation or collection */\nconst activeSchemeOptions = computed<SecuritySchemeOption[]>(() => {\n const schemes = selectedSecurity?.selectedSchemes\n if (!schemes?.length) {\n return []\n }\n\n return schemes.flatMap((requirement) => {\n const schemeNames = Object.keys(requirement)\n\n if (schemeNames.length === 0) {\n return []\n }\n\n // Complex auth requirement with multiple schemes\n if (schemeNames.length > 1) {\n return formatComplexScheme(requirement)\n }\n\n // Simple auth requirement with single scheme\n const schemeName = schemeNames[0]\n if (!schemeName) {\n return []\n }\n\n const scheme = getResolvedRef(securitySchemes?.[schemeName])\n if (!scheme) {\n return []\n }\n\n return formatScheme({\n name: schemeName,\n value: requirement,\n })\n })\n})\n\n/**\n * Opens the combobox dropdown when clicking the auth indicator badge.\n * Prevents the disclosure from toggling if it is already open.\n */\nconst handleAuthIndicatorClick = (event: Event): void => {\n if (isDisclosureOpen.value) {\n event.stopPropagation()\n }\n comboboxButtonRef.value?.$el.click()\n}\n\n/**\n * Updates the selected auth schemes.\n * Separates existing schemes from newly created ones for the event payload.\n */\nconst handleSchemeSelection = (selected: SecuritySchemeOption[]): void => {\n const existingSchemes = selected\n .filter((option) => option.payload === undefined)\n .map((option) => unpackProxyObject(option.value, { depth: 2 }))\n\n const newSchemes = selected\n .filter((option) => option.payload !== undefined)\n .map((option) => ({\n name: option.label,\n scheme: option.payload!,\n }))\n\n eventBus.emit('auth:update:selected-security-schemes', {\n selectedRequirements: existingSchemes,\n newSchemes,\n meta,\n })\n}\n\n/** Shows the delete confirmation modal for the selected scheme */\nconst handleDeleteRequest = (option: {\n label: string\n value: SecurityRequirementObject\n}): void => {\n schemeToDelete.value = { label: option.label, payload: option.value }\n deleteModal.show()\n}\n\n/** Deletes the selected auth scheme after confirmation */\nconst handleDeleteConfirm = (): void => {\n if (!schemeToDelete.value) {\n return\n }\n\n eventBus.emit('auth:delete:security-scheme', {\n names: Object.keys(schemeToDelete.value.payload),\n })\n\n schemeToDelete.value = null\n deleteModal.hide()\n}\n\ndefineExpose({\n authIndicator,\n selectedSchemeOptions: activeSchemeOptions,\n schemeOptions: availableSchemeOptions,\n})\n</script>\n<template>\n <CollapsibleSection\n class=\"group/params relative\"\n :defaultOpen\n :isStatic=\"isStatic\"\n :itemCount=\"activeSchemeOptions.length\"\n @update:modelValue=\"(open) => (isDisclosureOpen = open)\">\n <template #title>\n <div\n :id=\"titleId\"\n class=\"inline-flex items-center gap-0.5 leading-[20px]\">\n <span>{{ title }}</span>\n\n <span\n v-if=\"authIndicator\"\n class=\"text-c-3 hover:bg-b-3 hover:text-c-1 -my-0.5 -mr-1 cursor-pointer rounded px-1 py-0.5 leading-[normal] font-normal\"\n :class=\"{ 'text-c-1': authIndicator.text === 'Required' }\"\n data-testid=\"auth-indicator\"\n @click=\"handleAuthIndicatorClick\">\n {{ authIndicator.text }}\n </span>\n </div>\n </template>\n\n <!-- Auth Dropdown (hidden when only one scheme is available) -->\n <template #actions>\n <ScalarComboboxMultiselect\n class=\"w-72 text-xs\"\n :modelValue=\"activeSchemeOptions\"\n multiple\n :options=\"availableSchemeOptions\"\n placement=\"bottom-end\"\n teleport\n @delete=\"handleDeleteRequest\"\n @update:modelValue=\"handleSchemeSelection\">\n <ScalarButton\n ref=\"comboboxButtonRef\"\n :aria-describedby=\"titleId\"\n class=\"group/combobox-button hover:text-c-1 text-c-2 flex h-fit w-full items-center gap-1 px-0.75 py-0.25 text-base font-normal\"\n variant=\"ghost\">\n <!-- Single auth scheme selected -->\n <template v-if=\"activeSchemeOptions.length === 1\">\n <span class=\"sr-only\">Selected Auth Type:</span>\n {{ activeSchemeOptions[0]?.label }}\n </template>\n\n <!-- Multiple auth schemes selected -->\n <template v-else-if=\"activeSchemeOptions.length > 1\">\n Multiple\n <span class=\"sr-only\">Auth Types Selected</span>\n </template>\n\n <!-- No auth schemes selected -->\n <template v-else>\n <span class=\"sr-only\">Select</span>\n Auth Type\n </template>\n\n <ScalarIconCaretDown\n class=\"size-3 shrink-0 transition-transform duration-100 group-aria-expanded/combobox-button:rotate-180\"\n weight=\"bold\" />\n </ScalarButton>\n\n <template #option=\"{ option, selected }\">\n <ScalarListboxCheckbox\n multiselect\n :selected=\"selected\" />\n <div class=\"min-w-0 flex-1 truncate\">\n {{ option.label }}\n </div>\n <ScalarIconButton\n v-if=\"option.isDeletable\"\n class=\"-m-0.5 shrink-0 p-0.5 opacity-0 group-hover/item:opacity-100\"\n :icon=\"ScalarIconTrash\"\n :label=\"`Delete ${option.label}`\"\n size=\"xs\"\n @click.stop=\"handleDeleteRequest(option)\" />\n </template>\n </ScalarComboboxMultiselect>\n </template>\n\n <!-- Auth Table -->\n <RequestAuthDataTable\n :activeAuthIndex=\"selectedSecurity?.selectedIndex ?? 0\"\n :environment\n :eventBus\n :isStatic\n :meta\n :options\n :proxyUrl\n :securitySchemes\n :selectedSchemeOptions=\"activeSchemeOptions\"\n :server />\n\n <!-- Delete Auth Modal -->\n <DeleteRequestAuthModal\n v-if=\"schemeToDelete\"\n :label=\"schemeToDelete.label\"\n :scheme=\"schemeToDelete\"\n :state=\"deleteModal\"\n @close=\"deleteModal.hide()\"\n @delete=\"handleDeleteConfirm\" />\n </CollapsibleSection>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"AuthSelector.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarComboboxMultiselect,\n ScalarIconButton,\n ScalarListboxCheckbox,\n useModal,\n type Icon,\n type ScalarButton as ScalarButtonType,\n} from '@scalar/components'\nimport { ScalarIconCaretDown, ScalarIconTrash } from '@scalar/icons'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type {\n AuthMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n isAuthOptional,\n type MergedSecuritySchemes,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n OpenApiDocument,\n SecurityRequirementObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, useId } from 'vue'\n\nimport DeleteRequestAuthModal from '@/v2/blocks/scalar-auth-selector-block/components/DeleteRequestAuthModal.vue'\nimport type { OAuth2Options } from '@/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue'\nimport {\n formatComplexScheme,\n formatScheme,\n getSecuritySchemeOptions,\n type SecuritySchemeOption,\n} from '@/v2/blocks/scalar-auth-selector-block/helpers/security-scheme'\nimport { CollapsibleSection } from '@/v2/components/layout'\n\nimport RequestAuthDataTable from './RequestAuthDataTable.vue'\n\nconst {\n environment,\n eventBus,\n createAnySecurityScheme = false,\n defaultOpen = true,\n isStatic = false,\n meta,\n proxyUrl,\n securityRequirements,\n securitySchemes,\n selectedSecurity,\n server,\n title,\n options,\n} = defineProps<{\n environment: XScalarEnvironment\n eventBus: WorkspaceEventBus\n /** Allows adding authentication which is not in the document */\n createAnySecurityScheme?: boolean\n /** Whether the authentication disclosure should start expanded */\n defaultOpen?: boolean\n /** Creates a static disclosure that cannot be collapsed */\n isStatic?: boolean\n meta: AuthMeta\n proxyUrl: string\n securityRequirements: OpenApiDocument['security']\n securitySchemes: MergedSecuritySchemes\n selectedSecurity: SelectedSecurity | undefined\n server: ServerObject | null\n title: string\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}>()\n\nconst titleId = useId()\nconst comboboxButtonRef = ref<typeof ScalarButtonType | null>(null)\nconst isDisclosureOpen = ref(false)\n\nconst deleteModal = useModal()\nconst schemeToDelete = ref<{\n label: string\n payload: SecurityRequirementObject\n} | null>(null)\n\n/**\n * Determines if authentication is required or optional\n *\n * Auth is optional when there is an empty security requirement and no complex requirements.\n * Complex requirements have multiple auth schemes combined (e.g., API key + OAuth).\n */\nconst authIndicator = computed<{ icon: Icon; text: string } | null>(() => {\n if (!securityRequirements?.length) {\n return null\n }\n\n const isOptional = isAuthOptional(securityRequirements)\n\n return {\n icon: isOptional ? 'Unlock' : 'Lock',\n text: isOptional ? 'Optional' : 'Required',\n }\n})\n\n/** All available auth scheme options for the dropdown */\nconst availableSchemeOptions = computed(() =>\n getSecuritySchemeOptions(\n securityRequirements ?? [],\n securitySchemes ?? {},\n selectedSecurity?.selectedSchemes ?? [],\n createAnySecurityScheme,\n ),\n)\n\n/** Currently active auth schemes selected for this operation or collection */\nconst activeSchemeOptions = computed<SecuritySchemeOption[]>(() => {\n const schemes = selectedSecurity?.selectedSchemes\n if (!schemes?.length) {\n return []\n }\n\n return schemes.flatMap((requirement) => {\n const schemeNames = Object.keys(requirement)\n\n if (schemeNames.length === 0) {\n return []\n }\n\n // Complex auth requirement with multiple schemes\n if (schemeNames.length > 1) {\n return formatComplexScheme(requirement)\n }\n\n // Simple auth requirement with single scheme\n const schemeName = schemeNames[0]\n if (!schemeName) {\n return []\n }\n\n const scheme = getResolvedRef(securitySchemes?.[schemeName])\n if (!scheme) {\n return []\n }\n\n return formatScheme({\n name: schemeName,\n value: requirement,\n })\n })\n})\n\n/**\n * Opens the combobox dropdown when clicking the auth indicator badge.\n * Prevents the disclosure from toggling if it is already open.\n */\nconst handleAuthIndicatorClick = (event: Event): void => {\n if (isDisclosureOpen.value) {\n event.stopPropagation()\n }\n comboboxButtonRef.value?.$el.click()\n}\n\n/**\n * Updates the selected auth schemes.\n * Separates existing schemes from newly created ones for the event payload.\n */\nconst handleSchemeSelection = (selected: SecuritySchemeOption[]): void => {\n const existingSchemes = selected\n .filter((option) => option.payload === undefined)\n .map((option) => unpackProxyObject(option.value, { depth: 2 }))\n\n const newSchemes = selected\n .filter((option) => option.payload !== undefined)\n .map((option) => ({\n name: option.label,\n scheme: option.payload!,\n }))\n\n eventBus.emit('auth:update:selected-security-schemes', {\n selectedRequirements: existingSchemes,\n newSchemes,\n meta,\n })\n}\n\n/** Shows the delete confirmation modal for the selected scheme */\nconst handleDeleteRequest = (option: {\n label: string\n value: SecurityRequirementObject\n}): void => {\n schemeToDelete.value = { label: option.label, payload: option.value }\n deleteModal.show()\n}\n\n/** Deletes the selected auth scheme after confirmation */\nconst handleDeleteConfirm = (): void => {\n if (!schemeToDelete.value) {\n return\n }\n\n eventBus.emit('auth:delete:security-scheme', {\n names: Object.keys(schemeToDelete.value.payload),\n })\n\n schemeToDelete.value = null\n deleteModal.hide()\n}\n\ndefineExpose({\n authIndicator,\n selectedSchemeOptions: activeSchemeOptions,\n schemeOptions: availableSchemeOptions,\n})\n</script>\n<template>\n <CollapsibleSection\n class=\"group/params relative\"\n :defaultOpen\n :isStatic=\"isStatic\"\n :itemCount=\"activeSchemeOptions.length\"\n @update:modelValue=\"(open) => (isDisclosureOpen = open)\">\n <template #title>\n <div\n :id=\"titleId\"\n class=\"inline-flex items-center gap-0.5 leading-[20px]\">\n <span>{{ title }}</span>\n\n <span\n v-if=\"authIndicator\"\n class=\"text-c-3 hover:bg-b-3 hover:text-c-1 -my-0.5 -mr-1 cursor-pointer rounded px-1 py-0.5 leading-[normal] font-normal\"\n :class=\"{ 'text-c-1': authIndicator.text === 'Required' }\"\n data-testid=\"auth-indicator\"\n @click=\"handleAuthIndicatorClick\">\n {{ authIndicator.text }}\n </span>\n </div>\n </template>\n\n <!-- Auth Dropdown (hidden when only one scheme is available) -->\n <template #actions>\n <ScalarComboboxMultiselect\n class=\"w-72 text-xs\"\n :modelValue=\"activeSchemeOptions\"\n multiple\n :options=\"availableSchemeOptions\"\n placement=\"bottom-end\"\n teleport\n @delete=\"handleDeleteRequest\"\n @update:modelValue=\"handleSchemeSelection\">\n <ScalarButton\n ref=\"comboboxButtonRef\"\n :aria-describedby=\"titleId\"\n class=\"group/combobox-button hover:text-c-1 text-c-2 flex h-fit w-full items-center gap-1 px-0.75 py-0.25 text-base font-normal\"\n variant=\"ghost\">\n <!-- Single auth scheme selected -->\n <template v-if=\"activeSchemeOptions.length === 1\">\n <span class=\"sr-only\">Selected Auth Type:</span>\n {{ activeSchemeOptions[0]?.label }}\n </template>\n\n <!-- Multiple auth schemes selected -->\n <template v-else-if=\"activeSchemeOptions.length > 1\">\n Multiple\n <span class=\"sr-only\">Auth Types Selected</span>\n </template>\n\n <!-- No auth schemes selected -->\n <template v-else>\n <span class=\"sr-only\">Select</span>\n Auth Type\n </template>\n\n <ScalarIconCaretDown\n class=\"size-3 shrink-0 transition-transform duration-100 group-aria-expanded/combobox-button:rotate-180\"\n weight=\"bold\" />\n </ScalarButton>\n\n <template #option=\"{ option, selected }\">\n <ScalarListboxCheckbox\n multiselect\n :selected=\"selected\" />\n <div class=\"min-w-0 flex-1 truncate\">\n {{ option.label }}\n </div>\n <ScalarIconButton\n v-if=\"option.isDeletable\"\n class=\"-m-0.5 shrink-0 p-0.5 opacity-0 group-hover/item:opacity-100\"\n :icon=\"ScalarIconTrash\"\n :label=\"`Delete ${option.label}`\"\n size=\"xs\"\n @click.stop=\"handleDeleteRequest(option)\" />\n </template>\n </ScalarComboboxMultiselect>\n </template>\n\n <!-- Auth Table -->\n <RequestAuthDataTable\n :activeAuthIndex=\"selectedSecurity?.selectedIndex ?? 0\"\n :environment\n :eventBus\n :isStatic\n :meta\n :options\n :proxyUrl\n :securitySchemes\n :selectedSchemeOptions=\"activeSchemeOptions\"\n :server />\n\n <!-- Delete Auth Modal -->\n <DeleteRequestAuthModal\n v-if=\"schemeToDelete\"\n :label=\"schemeToDelete.label\"\n :scheme=\"schemeToDelete\"\n :state=\"deleteModal\"\n @close=\"deleteModal.hide()\"\n @delete=\"handleDeleteConfirm\" />\n </CollapsibleSection>\n</template>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"OAuth2.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue"],"names":[],"mappings":"AAyaA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AAIzE,OAAO,KAAK,EAEV,iBAAiB,EAClB,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAKL,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,EAChC,MAAM,yCAAyC,CAAA;AAChD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AAGnH,OAAO,KAAK,EAEV,YAAY,EACb,MAAM,8DAA8D,CAAA;AAWrE,uDAAuD;AACvD,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,sBAAsB,EAAE,mBAAmB,CAAC,CAAA;wBACxD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,QAAA,MAAM,YAAY;IAEhB,wCAAwC;iBAC3B,kBAAkB;IAC/B,kBAAkB;WACX,sBAAsB;IAC7B,6BAA6B;UACvB,MAAM,sBAAsB;IAClC,sBAAsB;oBACN,MAAM,EAAE;IACxB,sBAAsB;YACd,0BAA0B;IAClC,mCAAmC;YAC3B,YAAY,GAAG,IAAI;IAC3B,gBAAgB;cACN,MAAM;IAChB,kCAAkC;UAC5B,MAAM;IACZ,2CAA2C;cACjC,iBAAiB;IAC3B,uDAAuD;cAC7C,aAAa;;;;;;;;;;;;;;IAnBvB,wCAAwC;iBAC3B,kBAAkB;IAC/B,kBAAkB;WACX,sBAAsB;IAC7B,6BAA6B;UACvB,MAAM,sBAAsB;IAClC,sBAAsB;oBACN,MAAM,EAAE;IACxB,sBAAsB;YACd,0BAA0B;IAClC,mCAAmC;YAC3B,YAAY,GAAG,IAAI;IAC3B,gBAAgB;cACN,MAAM;IAChB,kCAAkC;UAC5B,MAAM;IACZ,2CAA2C;cACjC,iBAAiB;IAC3B,uDAAuD;cAC7C,aAAa;;;;;;;;;;;;;kFAmxBrB,CAAC"}
1
+ {"version":3,"file":"OAuth2.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue"],"names":[],"mappings":"AAqhBA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AAIzE,OAAO,KAAK,EAEV,iBAAiB,EAClB,MAAM,gCAAgC,CAAA;AACvC,OAAO,EAKL,KAAK,sBAAsB,EAC3B,KAAK,0BAA0B,EAChC,MAAM,yCAAyC,CAAA;AAChD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AAGnH,OAAO,KAAK,EAEV,YAAY,EACb,MAAM,8DAA8D,CAAA;AAcrE,uDAAuD;AACvD,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,sBAAsB,EAAE,mBAAmB,CAAC,CAAA;wBACxD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,QAAA,MAAM,YAAY;IAEhB,wCAAwC;iBAC3B,kBAAkB;IAC/B,kBAAkB;WACX,sBAAsB;IAC7B,6BAA6B;UACvB,MAAM,sBAAsB;IAClC,sBAAsB;oBACN,MAAM,EAAE;IACxB,sBAAsB;YACd,0BAA0B;IAClC,mCAAmC;YAC3B,YAAY,GAAG,IAAI;IAC3B,gBAAgB;cACN,MAAM;IAChB,kCAAkC;UAC5B,MAAM;IACZ,2CAA2C;cACjC,iBAAiB;IAC3B,uDAAuD;cAC7C,aAAa;;;;;;;;;;;;;;IAnBvB,wCAAwC;iBAC3B,kBAAkB;IAC/B,kBAAkB;WACX,sBAAsB;IAC7B,6BAA6B;UACvB,MAAM,sBAAsB;IAClC,sBAAsB;oBACN,MAAM,EAAE;IACxB,sBAAsB;YACd,0BAA0B;IAClC,mCAAmC;YAC3B,YAAY,GAAG,IAAI;IAC3B,gBAAgB;cACN,MAAM;IAChB,kCAAkC;UAC5B,MAAM;IACZ,2CAA2C;cACjC,iBAAiB;IAC3B,uDAAuD;cAC7C,aAAa;;;;;;;;;;;;;kFAq7BrB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"OAuth2.vue.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue"],"sourcesContent":["<script lang=\"ts\">\n/** Any config options required for the OAuth2 flow */\nexport type OAuth2Options = Pick<ApiClientConfiguration, 'oauth2RedirectUri'>\n</script>\n\n<script setup lang=\"ts\">\nimport { ScalarButton, useLoadingState } from '@scalar/components'\nimport type { ApiClientConfiguration } from '@scalar/types/api-reference'\nimport { pkceOptions } from '@scalar/types/entities'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { SecretsOAuthFlows } from '@scalar/workspace-store/entities/auth'\nimport type {\n ApiReferenceEvents,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n getEnvironmentVariables,\n type OAuthFlowAuthorizationCodeSecret,\n type OAuthFlowClientCredentialsSecret,\n type OAuthFlowPasswordSecret,\n type OAuthFlowsObjectSecret,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCredentialsLocation } from '@scalar/workspace-store/schemas/extensions/security/x-scalar-credentials-location'\nimport { type XusePkce } from '@scalar/workspace-store/schemas/extensions/security/x-use-pkce'\nimport type {\n OAuthFlow,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport OAuthScopesInput from '@/v2/blocks/scalar-auth-selector-block/components/OAuthScopesInput.vue'\nimport { authorizeOauth2 } from '@/v2/blocks/scalar-auth-selector-block/helpers/oauth'\nimport { resolveDefaultOAuth2RedirectUri } from '@/v2/blocks/scalar-auth-selector-block/helpers/resolve-default-oauth2-redirect-url'\nimport { DataTableRow } from '@/v2/components/data-table'\n\nimport RequestAuthDataTableInput from './RequestAuthDataTableInput.vue'\n\nconst {\n environment,\n flows,\n type,\n scheme,\n selectedScopes: selectedScopesProp,\n server,\n proxyUrl,\n eventBus,\n name,\n options = {},\n} = defineProps<{\n /** Current environment configuration */\n environment: XScalarEnvironment\n /** OAuth flows */\n flows: OAuthFlowsObjectSecret\n /** Type of the OAuth flow */\n type: keyof OAuthFlowsObjectSecret\n /** Selected scopes */\n selectedScopes: string[]\n /** Security scheme */\n scheme: SecuritySchemeObjectSecret\n /** Current server configuration */\n server: ServerObject | null\n /** Proxy URL */\n proxyUrl: string\n /** Name of the security scheme */\n name: string\n /** Event bus for authentication updates */\n eventBus: WorkspaceEventBus\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}>()\n\nconst emits = defineEmits<{\n (\n e: 'update:selectedScopes',\n payload: Pick<\n ApiReferenceEvents['auth:update:selected-scopes'],\n 'scopes' | 'newScopePayload'\n >,\n ): void\n}>()\n\nconst loader = useLoadingState()\nconst { toast } = useToasts()\n\n/** The current OAuth flow based on the selected type */\nconst flow = computed(() => flows[type]!)\ntype NonImplicitFlow =\n | OAuthFlowPasswordSecret\n | OAuthFlowClientCredentialsSecret\n | OAuthFlowAuthorizationCodeSecret\n\n/** We filter selected scopes to only include scopes that are in this flow*/\nconst selectedScopes = computed(() =>\n selectedScopesProp.filter((scope) => scope in (flow.value.scopes ?? {})),\n)\n\n/** Updates the security scheme base */\nconst handleOauth2Update = (\n payload: Partial<OAuthFlow & XScalarCredentialsLocation>,\n): void => {\n // OpenIdConnect uses the secrets update for all\n if (scheme.type === 'openIdConnect') {\n return handleOauth2SecretsUpdate(payload)\n }\n\n eventBus.emit('auth:update:security-scheme', {\n payload: {\n type: scheme.type,\n flows: {\n [type]: payload,\n },\n },\n name,\n })\n}\n\n/** Updates the flow secrets */\nconst handleOauth2SecretsUpdate = (\n payload: Omit<Partial<SecretsOAuthFlows[keyof SecretsOAuthFlows]>, 'type'>,\n): void =>\n eventBus.emit('auth:update:security-scheme-secrets', {\n payload: {\n type: scheme.type,\n [type]: payload,\n },\n name,\n })\n\n/** Clears the flow secrets */\nconst clearOauth2Secrets = (): void =>\n eventBus.emit('auth:clear:security-scheme-secrets', {\n name,\n })\n\n/** Track if we have set the redirect uri */\nconst hasPrefilledRedirectUri = ref(false)\n\n/** Default the redirect-uri to the current origin if we have access to window */\nwatch(\n () =>\n (flow.value as OAuthFlowAuthorizationCodeSecret)[\n 'x-scalar-secret-redirect-uri'\n ],\n (newRedirectUri) => {\n const defaultRedirectUri = resolveDefaultOAuth2RedirectUri(options)\n\n if (\n hasPrefilledRedirectUri.value ||\n newRedirectUri ||\n !defaultRedirectUri ||\n !('x-scalar-secret-redirect-uri' in flow.value)\n ) {\n return\n }\n hasPrefilledRedirectUri.value = true\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-redirect-uri': defaultRedirectUri,\n })\n },\n { immediate: true },\n)\n\n/**\n * Authorizes the user using the specified OAuth flow.\n * Opens the appropriate OAuth dialog and/or performs the token exchange.\n */\nconst handleAuthorize = async (): Promise<void> => {\n if (loader.isLoading) {\n return\n }\n\n loader.start()\n\n const [error, tokens] = await authorizeOauth2(\n flows,\n type,\n selectedScopes.value,\n server,\n proxyUrl,\n getEnvironmentVariables(environment),\n )\n\n await loader.clear()\n\n if (tokens?.accessToken) {\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': tokens.accessToken,\n ...(tokens.refreshToken\n ? { 'x-scalar-secret-refresh-token': tokens.refreshToken }\n : {}),\n })\n } else {\n console.error(error)\n toast(error?.message ?? 'Failed to authorize', 'error')\n }\n}\n\n/** Updates the secret location */\nconst handleSecretLocationUpdate = (value: string): void => {\n const credentialsLocation = value === 'body' ? 'body' : 'header'\n\n if (scheme.type !== 'openIdConnect') {\n handleOauth2Update({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n }\n\n handleOauth2SecretsUpdate({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n}\n</script>\n\n<template>\n <!-- Access Token Display: Shows when user is already authorized -->\n <template v-if=\"Boolean(flow['x-scalar-secret-token'])\">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"border-r-transparent\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token']\"\n placeholder=\"QUxMIFlPVVIgQkFTRSBBUkUgQkVMT05HIFRPIFVT\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-token': v })\n \">\n Access Token\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 items-center justify-end gap-2 border-t\">\n <ScalarButton\n class=\"mr-1 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n () =>\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': '',\n 'x-scalar-secret-refresh-token': '',\n })\n \">\n Clear\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n\n <!-- Authorization Form: Shows when user needs to authorize -->\n <template v-else>\n <DataTableRow>\n <RequestAuthDataTableInput\n v-if=\"'authorizationUrl' in flow\"\n containerClass=\"border-r-0\"\n :environment\n :modelValue=\"flow['x-scalar-secret-auth-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/authorize\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-auth-url': v })\n handleOauth2Update({ authorizationUrl: v })\n }\n \">\n Auth URL\n </RequestAuthDataTableInput>\n\n <RequestAuthDataTableInput\n v-if=\"'tokenUrl' in flow\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/token\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-token-url': v })\n handleOauth2Update({ tokenUrl: v })\n }\n \">\n Token URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-redirect-uri' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-redirect-uri']\"\n placeholder=\"https://galaxy.scalar.com/callback\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-redirect-uri': v })\n }\n \">\n Redirect URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <template\n v-if=\"\n 'x-scalar-secret-username' in flow && 'x-scalar-secret-password' in flow\n \">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"text-c-2\"\n :environment\n :modelValue=\"flow['x-scalar-secret-username']\"\n placeholder=\"janedoe\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-username': v })\n \">\n Username\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-password']\"\n placeholder=\"********\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-password': v })\n \">\n Password\n </RequestAuthDataTableInput>\n </DataTableRow>\n </template>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-id']\"\n placeholder=\"12345\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-client-id': v })\n \">\n Client ID\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-client-secret' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-secret']\"\n placeholder=\"XYZ123\"\n type=\"password\"\n @update:modelValue=\"\n (v) =>\n handleOauth2SecretsUpdate({ 'x-scalar-secret-client-secret': v })\n \">\n Client Secret\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-usePkce' in flow\">\n <RequestAuthDataTableInput\n :enum=\"pkceOptions\"\n :environment\n :modelValue=\"flow['x-usePkce']\"\n readOnly\n @update:modelValue=\"\n (v) =>\n handleOauth2Update({\n 'x-usePkce': v as XusePkce['x-usePkce'],\n })\n \">\n Use PKCE\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Credentials Location -->\n <DataTableRow v-if=\"type !== 'implicit'\">\n <RequestAuthDataTableInput\n :enum=\"['header', 'body']\"\n :environment\n :modelValue=\"\n (flow as NonImplicitFlow)['x-scalar-credentials-location'] || 'header'\n \"\n placeholder=\"header\"\n readOnly\n @update:modelValue=\"(v) => handleSecretLocationUpdate(v)\">\n Credentials Location\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Scopes -->\n <DataTableRow>\n <OAuthScopesInput\n :flow\n :flowType=\"type\"\n :selectedScopes\n @update:selectedScopes=\"(v) => emits('update:selectedScopes', v)\" />\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 w-full items-center justify-end border-t\">\n <!-- Allow clearing the oauth section and going back to discovery -->\n <ScalarButton\n v-if=\"scheme.type === 'openIdConnect'\"\n class=\"mr-1 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"clearOauth2Secrets\">\n Clear\n </ScalarButton>\n\n <ScalarButton\n class=\"mr-0.75 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleAuthorize\">\n Authorize\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"OAuth2.vue.js","names":[],"sources":["../../../../../src/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue"],"sourcesContent":["<script lang=\"ts\">\n/** Any config options required for the OAuth2 flow */\nexport type OAuth2Options = Pick<ApiClientConfiguration, 'oauth2RedirectUri'>\n</script>\n\n<script setup lang=\"ts\">\nimport { ScalarButton, useLoadingState } from '@scalar/components'\nimport type { ApiClientConfiguration } from '@scalar/types/api-reference'\nimport { pkceOptions } from '@scalar/types/entities'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { SecretsOAuthFlows } from '@scalar/workspace-store/entities/auth'\nimport type {\n ApiReferenceEvents,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n getEnvironmentVariables,\n type OAuthFlowAuthorizationCodeSecret,\n type OAuthFlowClientCredentialsSecret,\n type OAuthFlowPasswordSecret,\n type OAuthFlowsObjectSecret,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCredentialsLocation } from '@scalar/workspace-store/schemas/extensions/security/x-scalar-credentials-location'\nimport { type XusePkce } from '@scalar/workspace-store/schemas/extensions/security/x-use-pkce'\nimport type {\n OAuthFlow,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport OAuthScopesInput from '@/v2/blocks/scalar-auth-selector-block/components/OAuthScopesInput.vue'\nimport {\n authorizeOauth2,\n refreshOauth2Token,\n} from '@/v2/blocks/scalar-auth-selector-block/helpers/oauth'\nimport { resolveDefaultOAuth2RedirectUri } from '@/v2/blocks/scalar-auth-selector-block/helpers/resolve-default-oauth2-redirect-url'\nimport { DataTableRow } from '@/v2/components/data-table'\n\nimport RequestAuthDataTableInput from './RequestAuthDataTableInput.vue'\n\nconst {\n environment,\n flows,\n type,\n scheme,\n selectedScopes: selectedScopesProp,\n server,\n proxyUrl,\n eventBus,\n name,\n options = {},\n} = defineProps<{\n /** Current environment configuration */\n environment: XScalarEnvironment\n /** OAuth flows */\n flows: OAuthFlowsObjectSecret\n /** Type of the OAuth flow */\n type: keyof OAuthFlowsObjectSecret\n /** Selected scopes */\n selectedScopes: string[]\n /** Security scheme */\n scheme: SecuritySchemeObjectSecret\n /** Current server configuration */\n server: ServerObject | null\n /** Proxy URL */\n proxyUrl: string\n /** Name of the security scheme */\n name: string\n /** Event bus for authentication updates */\n eventBus: WorkspaceEventBus\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}>()\n\nconst emits = defineEmits<{\n (\n e: 'update:selectedScopes',\n payload: Pick<\n ApiReferenceEvents['auth:update:selected-scopes'],\n 'scopes' | 'newScopePayload'\n >,\n ): void\n}>()\n\nconst loader = useLoadingState()\nconst { toast } = useToasts()\n\n/** The current OAuth flow based on the selected type */\nconst flow = computed(() => flows[type]!)\ntype NonImplicitFlow =\n | OAuthFlowPasswordSecret\n | OAuthFlowClientCredentialsSecret\n | OAuthFlowAuthorizationCodeSecret\n\n/** We filter selected scopes to only include scopes that are in this flow*/\nconst selectedScopes = computed(() =>\n selectedScopesProp.filter((scope) => scope in (flow.value.scopes ?? {})),\n)\n\n/** Updates the security scheme base */\nconst handleOauth2Update = (\n payload: Partial<OAuthFlow & XScalarCredentialsLocation>,\n): void => {\n // OpenIdConnect uses the secrets update for all\n if (scheme.type === 'openIdConnect') {\n return handleOauth2SecretsUpdate(payload)\n }\n\n eventBus.emit('auth:update:security-scheme', {\n payload: {\n type: scheme.type,\n flows: {\n [type]: payload,\n },\n },\n name,\n })\n}\n\n/** Updates the flow secrets */\nconst handleOauth2SecretsUpdate = (\n payload: Omit<Partial<SecretsOAuthFlows[keyof SecretsOAuthFlows]>, 'type'>,\n): void =>\n eventBus.emit('auth:update:security-scheme-secrets', {\n payload: {\n type: scheme.type,\n [type]: payload,\n },\n name,\n })\n\n/** Clears the flow secrets */\nconst clearOauth2Secrets = (): void => {\n if (loader.isLoading) {\n return\n }\n eventBus.emit('auth:clear:security-scheme-secrets', {\n name,\n })\n}\n\n/** Clears stored access and refresh tokens (authorized state) */\nconst handleClearAccessTokens = (): void => {\n if (loader.isLoading) {\n return\n }\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': '',\n 'x-scalar-secret-refresh-token': '',\n })\n}\n\n/** Track redirect URI prefill per flow instance to support document switching */\nconst prefilledFlowIdentity = ref<string | null>(null)\nconst hasHandledRedirectPrefill = ref(false)\n\nconst resolveFlowIdentity = (\n currentFlow: OAuthFlowsObjectSecret[keyof OAuthFlowsObjectSecret] | undefined,\n): string =>\n JSON.stringify({\n type,\n authorizationUrl:\n currentFlow && 'authorizationUrl' in currentFlow\n ? currentFlow.authorizationUrl\n : '',\n tokenUrl:\n currentFlow && 'tokenUrl' in currentFlow ? currentFlow.tokenUrl : '',\n refreshUrl: currentFlow?.refreshUrl ?? '',\n scopes: Object.keys(currentFlow?.scopes ?? {}),\n })\n\n/** Default the redirect-uri to the current origin if we have access to window */\nwatch(\n () => flow.value,\n (currentFlow) => {\n if (!currentFlow || !('x-scalar-secret-redirect-uri' in currentFlow)) {\n return\n }\n\n const flowIdentity = resolveFlowIdentity(currentFlow)\n if (prefilledFlowIdentity.value !== flowIdentity) {\n prefilledFlowIdentity.value = flowIdentity\n hasHandledRedirectPrefill.value = false\n }\n\n if (hasHandledRedirectPrefill.value) {\n return\n }\n\n const newRedirectUri = (currentFlow as OAuthFlowAuthorizationCodeSecret)[\n 'x-scalar-secret-redirect-uri'\n ]\n const defaultRedirectUri = resolveDefaultOAuth2RedirectUri(options)\n\n hasHandledRedirectPrefill.value = true\n\n if (newRedirectUri || !defaultRedirectUri) {\n return\n }\n\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-redirect-uri': defaultRedirectUri,\n })\n },\n { immediate: true },\n)\n\n/**\n * Authorizes the user using the specified OAuth flow.\n * Opens the appropriate OAuth dialog and/or performs the token exchange.\n */\nconst handleAuthorize = async (): Promise<void> => {\n if (loader.isLoading) {\n return\n }\n\n loader.start()\n\n const [error, tokens] = await authorizeOauth2(\n flows,\n type,\n selectedScopes.value,\n server,\n proxyUrl,\n getEnvironmentVariables(environment),\n )\n\n await loader.clear()\n\n if (tokens?.accessToken) {\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': tokens.accessToken,\n ...(tokens.refreshToken\n ? { 'x-scalar-secret-refresh-token': tokens.refreshToken }\n : {}),\n })\n } else {\n console.error(error)\n toast(error?.message ?? 'Failed to authorize', 'error')\n }\n}\n\n/** Whether the current flow supports refreshing the access token */\nconst supportsRefreshToken = computed(() => type !== 'implicit')\n\n/**\n * Refresh URL placeholder, shows tokenUrl as hint if refreshUrl is not specified.\n * This helps users understand that tokenUrl will be used as fallback.\n */\nconst refreshUrlPlaceholder = computed(() => {\n if ('tokenUrl' in flow.value && flow.value.tokenUrl) {\n return flow.value.tokenUrl\n }\n return 'https://galaxy.scalar.com/oauth/refresh'\n})\n\n/**\n * Uses the stored refresh token to obtain a new access token\n * via grant_type=refresh_token.\n */\nconst handleRefresh = async (): Promise<void> => {\n if (loader.isLoading || type === 'implicit') {\n return\n }\n\n loader.start()\n\n const [error, tokens] = await refreshOauth2Token(\n flows,\n type,\n proxyUrl,\n server,\n getEnvironmentVariables(environment),\n )\n\n await loader.clear()\n\n if (tokens?.accessToken) {\n handleOauth2SecretsUpdate({\n 'x-scalar-secret-token': tokens.accessToken,\n ...(tokens.refreshToken\n ? { 'x-scalar-secret-refresh-token': tokens.refreshToken }\n : {}),\n })\n } else {\n console.error(error)\n toast(error?.message ?? 'Failed to refresh token', 'error')\n }\n}\n\n/** Updates the secret location */\nconst handleSecretLocationUpdate = (value: string): void => {\n const credentialsLocation = value === 'body' ? 'body' : 'header'\n\n if (scheme.type !== 'openIdConnect') {\n handleOauth2Update({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n }\n\n handleOauth2SecretsUpdate({\n 'x-scalar-credentials-location': credentialsLocation,\n })\n}\n</script>\n\n<template>\n <!-- Access Token Display: Shows when user is already authorized -->\n <template v-if=\"Boolean(flow['x-scalar-secret-token'])\">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"border-r-transparent\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token']\"\n placeholder=\"QUxMIFlPVVIgQkFTRSBBUkUgQkVMT05HIFRPIFVT\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-token': v })\n \">\n Access Token\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"supportsRefreshToken\">\n <RequestAuthDataTableInput\n class=\"border-r-transparent\"\n :environment\n :modelValue=\"flow.refreshUrl ?? ''\"\n :placeholder=\"refreshUrlPlaceholder\"\n @update:modelValue=\"(v) => handleOauth2Update({ refreshUrl: v })\">\n Refresh URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 items-center justify-end gap-2 border-t\">\n <ScalarButton\n v-if=\"supportsRefreshToken\"\n class=\"p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleRefresh\">\n Refresh\n </ScalarButton>\n <ScalarButton\n class=\"mr-1 p-0 px-2 py-0.5\"\n :disabled=\"loader.isLoading\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleClearAccessTokens\">\n Clear\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n\n <!-- Authorization Form: Shows when user needs to authorize -->\n <template v-else>\n <DataTableRow>\n <RequestAuthDataTableInput\n v-if=\"'authorizationUrl' in flow\"\n containerClass=\"border-r-0\"\n :environment\n :modelValue=\"flow['x-scalar-secret-auth-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/authorize\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-auth-url': v })\n handleOauth2Update({ authorizationUrl: v })\n }\n \">\n Auth URL\n </RequestAuthDataTableInput>\n\n <RequestAuthDataTableInput\n v-if=\"'tokenUrl' in flow\"\n :environment\n :modelValue=\"flow['x-scalar-secret-token-url'] ?? ''\"\n placeholder=\"https://galaxy.scalar.com/token\"\n @update:modelValue=\"\n (v) => {\n handleOauth2SecretsUpdate({ 'x-scalar-secret-token-url': v })\n handleOauth2Update({ tokenUrl: v })\n }\n \">\n Token URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-redirect-uri' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-redirect-uri']\"\n placeholder=\"Optional redirect URL\"\n @update:modelValue=\"\n (v) => {\n hasHandledRedirectPrefill = true\n handleOauth2SecretsUpdate({ 'x-scalar-secret-redirect-uri': v })\n }\n \">\n Redirect URL\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <template\n v-if=\"\n 'x-scalar-secret-username' in flow && 'x-scalar-secret-password' in flow\n \">\n <DataTableRow>\n <RequestAuthDataTableInput\n class=\"text-c-2\"\n :environment\n :modelValue=\"flow['x-scalar-secret-username']\"\n placeholder=\"janedoe\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-username': v })\n \">\n Username\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-password']\"\n placeholder=\"********\"\n type=\"password\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-password': v })\n \">\n Password\n </RequestAuthDataTableInput>\n </DataTableRow>\n </template>\n\n <DataTableRow>\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-id']\"\n placeholder=\"12345\"\n @update:modelValue=\"\n (v) => handleOauth2SecretsUpdate({ 'x-scalar-secret-client-id': v })\n \">\n Client ID\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-scalar-secret-client-secret' in flow\">\n <RequestAuthDataTableInput\n :environment\n :modelValue=\"flow['x-scalar-secret-client-secret']\"\n placeholder=\"XYZ123\"\n type=\"password\"\n @update:modelValue=\"\n (v) =>\n handleOauth2SecretsUpdate({ 'x-scalar-secret-client-secret': v })\n \">\n Client Secret\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <DataTableRow v-if=\"'x-usePkce' in flow\">\n <RequestAuthDataTableInput\n :enum=\"pkceOptions\"\n :environment\n :modelValue=\"flow['x-usePkce']\"\n readOnly\n @update:modelValue=\"\n (v) =>\n handleOauth2Update({\n 'x-usePkce': v as XusePkce['x-usePkce'],\n })\n \">\n Use PKCE\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Credentials Location -->\n <DataTableRow v-if=\"type !== 'implicit'\">\n <RequestAuthDataTableInput\n :enum=\"['header', 'body']\"\n :environment\n :modelValue=\"\n (flow as NonImplicitFlow)['x-scalar-credentials-location'] || 'header'\n \"\n placeholder=\"header\"\n readOnly\n @update:modelValue=\"(v) => handleSecretLocationUpdate(v)\">\n Credentials Location\n </RequestAuthDataTableInput>\n </DataTableRow>\n\n <!-- Scopes -->\n <DataTableRow>\n <OAuthScopesInput\n :flow\n :flowType=\"type\"\n :selectedScopes\n @update:selectedScopes=\"(v) => emits('update:selectedScopes', v)\" />\n </DataTableRow>\n\n <DataTableRow class=\"min-w-full\">\n <div class=\"flex h-8 w-full items-center justify-end border-t\">\n <!-- Allow clearing the oauth section and going back to discovery -->\n <ScalarButton\n v-if=\"scheme.type === 'openIdConnect'\"\n class=\"mr-1 p-0 px-2 py-0.5\"\n :disabled=\"loader.isLoading\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"clearOauth2Secrets\">\n Clear\n </ScalarButton>\n\n <ScalarButton\n class=\"mr-0.75 p-0 px-2 py-0.5\"\n :loader\n size=\"sm\"\n variant=\"outlined\"\n @click=\"handleAuthorize\">\n Authorize\n </ScalarButton>\n </div>\n </DataTableRow>\n </template>\n</template>\n"],"mappings":""}
@@ -1,6 +1,6 @@
1
1
  import DataTableRow_default from "../../../components/data-table/DataTableRow.vue.js";
2
2
  import OAuthScopesInput_default from "./OAuthScopesInput.vue.js";
3
- import { authorizeOauth2 } from "../helpers/oauth.js";
3
+ import { authorizeOauth2, refreshOauth2Token } from "../helpers/oauth.js";
4
4
  import { resolveDefaultOAuth2RedirectUri } from "../helpers/resolve-default-oauth2-redirect-url.js";
5
5
  import RequestAuthDataTableInput_default from "./RequestAuthDataTableInput.vue.js";
6
6
  import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, openBlock, ref, unref, watch, withCtx } from "vue";
@@ -53,14 +53,41 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
53
53
  name: __props.name
54
54
  });
55
55
  /** Clears the flow secrets */
56
- const clearOauth2Secrets = () => __props.eventBus.emit("auth:clear:security-scheme-secrets", { name: __props.name });
57
- /** Track if we have set the redirect uri */
58
- const hasPrefilledRedirectUri = ref(false);
56
+ const clearOauth2Secrets = () => {
57
+ if (loader.isLoading) return;
58
+ __props.eventBus.emit("auth:clear:security-scheme-secrets", { name: __props.name });
59
+ };
60
+ /** Clears stored access and refresh tokens (authorized state) */
61
+ const handleClearAccessTokens = () => {
62
+ if (loader.isLoading) return;
63
+ handleOauth2SecretsUpdate({
64
+ "x-scalar-secret-token": "",
65
+ "x-scalar-secret-refresh-token": ""
66
+ });
67
+ };
68
+ /** Track redirect URI prefill per flow instance to support document switching */
69
+ const prefilledFlowIdentity = ref(null);
70
+ const hasHandledRedirectPrefill = ref(false);
71
+ const resolveFlowIdentity = (currentFlow) => JSON.stringify({
72
+ type: __props.type,
73
+ authorizationUrl: currentFlow && "authorizationUrl" in currentFlow ? currentFlow.authorizationUrl : "",
74
+ tokenUrl: currentFlow && "tokenUrl" in currentFlow ? currentFlow.tokenUrl : "",
75
+ refreshUrl: currentFlow?.refreshUrl ?? "",
76
+ scopes: Object.keys(currentFlow?.scopes ?? {})
77
+ });
59
78
  /** Default the redirect-uri to the current origin if we have access to window */
60
- watch(() => flow.value["x-scalar-secret-redirect-uri"], (newRedirectUri) => {
79
+ watch(() => flow.value, (currentFlow) => {
80
+ if (!currentFlow || !("x-scalar-secret-redirect-uri" in currentFlow)) return;
81
+ const flowIdentity = resolveFlowIdentity(currentFlow);
82
+ if (prefilledFlowIdentity.value !== flowIdentity) {
83
+ prefilledFlowIdentity.value = flowIdentity;
84
+ hasHandledRedirectPrefill.value = false;
85
+ }
86
+ if (hasHandledRedirectPrefill.value) return;
87
+ const newRedirectUri = currentFlow["x-scalar-secret-redirect-uri"];
61
88
  const defaultRedirectUri = resolveDefaultOAuth2RedirectUri(__props.options);
62
- if (hasPrefilledRedirectUri.value || newRedirectUri || !defaultRedirectUri || !("x-scalar-secret-redirect-uri" in flow.value)) return;
63
- hasPrefilledRedirectUri.value = true;
89
+ hasHandledRedirectPrefill.value = true;
90
+ if (newRedirectUri || !defaultRedirectUri) return;
64
91
  handleOauth2SecretsUpdate({ "x-scalar-secret-redirect-uri": defaultRedirectUri });
65
92
  }, { immediate: true });
66
93
  /**
@@ -81,6 +108,34 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
81
108
  toast(error?.message ?? "Failed to authorize", "error");
82
109
  }
83
110
  };
111
+ /** Whether the current flow supports refreshing the access token */
112
+ const supportsRefreshToken = computed(() => __props.type !== "implicit");
113
+ /**
114
+ * Refresh URL placeholder, shows tokenUrl as hint if refreshUrl is not specified.
115
+ * This helps users understand that tokenUrl will be used as fallback.
116
+ */
117
+ const refreshUrlPlaceholder = computed(() => {
118
+ if ("tokenUrl" in flow.value && flow.value.tokenUrl) return flow.value.tokenUrl;
119
+ return "https://galaxy.scalar.com/oauth/refresh";
120
+ });
121
+ /**
122
+ * Uses the stored refresh token to obtain a new access token
123
+ * via grant_type=refresh_token.
124
+ */
125
+ const handleRefresh = async () => {
126
+ if (loader.isLoading || __props.type === "implicit") return;
127
+ loader.start();
128
+ const [error, tokens] = await refreshOauth2Token(__props.flows, __props.type, __props.proxyUrl, __props.server, getEnvironmentVariables(__props.environment));
129
+ await loader.clear();
130
+ if (tokens?.accessToken) handleOauth2SecretsUpdate({
131
+ "x-scalar-secret-token": tokens.accessToken,
132
+ ...tokens.refreshToken ? { "x-scalar-secret-refresh-token": tokens.refreshToken } : {}
133
+ });
134
+ else {
135
+ console.error(error);
136
+ toast(error?.message ?? "Failed to refresh token", "error");
137
+ }
138
+ };
84
139
  /** Updates the secret location */
85
140
  const handleSecretLocationUpdate = (value) => {
86
141
  const credentialsLocation = value === "body" ? "body" : "header";
@@ -88,35 +143,62 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
88
143
  handleOauth2SecretsUpdate({ "x-scalar-credentials-location": credentialsLocation });
89
144
  };
90
145
  return (_ctx, _cache) => {
91
- return Boolean(flow.value["x-scalar-secret-token"]) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createVNode(unref(DataTableRow_default), null, {
92
- default: withCtx(() => [createVNode(RequestAuthDataTableInput_default, {
93
- class: "border-r-transparent",
94
- environment: __props.environment,
95
- modelValue: flow.value["x-scalar-secret-token"],
96
- placeholder: "QUxMIFlPVVIgQkFTRSBBUkUgQkVMT05HIFRPIFVT",
97
- type: "password",
98
- "onUpdate:modelValue": _cache[0] || (_cache[0] = (v) => handleOauth2SecretsUpdate({ "x-scalar-secret-token": v }))
99
- }, {
100
- default: withCtx(() => [..._cache[12] || (_cache[12] = [createTextVNode(" Access Token ", -1)])]),
146
+ return Boolean(flow.value["x-scalar-secret-token"]) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
147
+ createVNode(unref(DataTableRow_default), null, {
148
+ default: withCtx(() => [createVNode(RequestAuthDataTableInput_default, {
149
+ class: "border-r-transparent",
150
+ environment: __props.environment,
151
+ modelValue: flow.value["x-scalar-secret-token"],
152
+ placeholder: "QUxMIFlPVVIgQkFTRSBBUkUgQkVMT05HIFRPIFVT",
153
+ type: "password",
154
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = (v) => handleOauth2SecretsUpdate({ "x-scalar-secret-token": v }))
155
+ }, {
156
+ default: withCtx(() => [..._cache[12] || (_cache[12] = [createTextVNode(" Access Token ", -1)])]),
157
+ _: 1
158
+ }, 8, ["environment", "modelValue"])]),
101
159
  _: 1
102
- }, 8, ["environment", "modelValue"])]),
103
- _: 1
104
- }), createVNode(unref(DataTableRow_default), { class: "min-w-full" }, {
105
- default: withCtx(() => [createElementVNode("div", _hoisted_1, [createVNode(unref(ScalarButton), {
106
- class: "mr-1 p-0 px-2 py-0.5",
107
- loader: unref(loader),
108
- size: "sm",
109
- variant: "outlined",
110
- onClick: _cache[1] || (_cache[1] = () => handleOauth2SecretsUpdate({
111
- "x-scalar-secret-token": "",
112
- "x-scalar-secret-refresh-token": ""
113
- }))
114
- }, {
115
- default: withCtx(() => [..._cache[13] || (_cache[13] = [createTextVNode(" Clear ", -1)])]),
160
+ }),
161
+ supportsRefreshToken.value ? (openBlock(), createBlock(unref(DataTableRow_default), { key: 0 }, {
162
+ default: withCtx(() => [createVNode(RequestAuthDataTableInput_default, {
163
+ class: "border-r-transparent",
164
+ environment: __props.environment,
165
+ modelValue: flow.value.refreshUrl ?? "",
166
+ placeholder: refreshUrlPlaceholder.value,
167
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = (v) => handleOauth2Update({ refreshUrl: v }))
168
+ }, {
169
+ default: withCtx(() => [..._cache[13] || (_cache[13] = [createTextVNode(" Refresh URL ", -1)])]),
170
+ _: 1
171
+ }, 8, [
172
+ "environment",
173
+ "modelValue",
174
+ "placeholder"
175
+ ])]),
116
176
  _: 1
117
- }, 8, ["loader"])])]),
118
- _: 1
119
- })], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
177
+ })) : createCommentVNode("", true),
178
+ createVNode(unref(DataTableRow_default), { class: "min-w-full" }, {
179
+ default: withCtx(() => [createElementVNode("div", _hoisted_1, [supportsRefreshToken.value ? (openBlock(), createBlock(unref(ScalarButton), {
180
+ key: 0,
181
+ class: "p-0 px-2 py-0.5",
182
+ loader: unref(loader),
183
+ size: "sm",
184
+ variant: "outlined",
185
+ onClick: handleRefresh
186
+ }, {
187
+ default: withCtx(() => [..._cache[14] || (_cache[14] = [createTextVNode(" Refresh ", -1)])]),
188
+ _: 1
189
+ }, 8, ["loader"])) : createCommentVNode("", true), createVNode(unref(ScalarButton), {
190
+ class: "mr-1 p-0 px-2 py-0.5",
191
+ disabled: unref(loader).isLoading,
192
+ size: "sm",
193
+ variant: "outlined",
194
+ onClick: handleClearAccessTokens
195
+ }, {
196
+ default: withCtx(() => [..._cache[15] || (_cache[15] = [createTextVNode(" Clear ", -1)])]),
197
+ _: 1
198
+ }, 8, ["disabled"])])]),
199
+ _: 1
200
+ })
201
+ ], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
120
202
  createVNode(unref(DataTableRow_default), null, {
121
203
  default: withCtx(() => ["authorizationUrl" in flow.value ? (openBlock(), createBlock(RequestAuthDataTableInput_default, {
122
204
  key: 0,
@@ -129,7 +211,7 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
129
211
  handleOauth2Update({ authorizationUrl: v });
130
212
  })
131
213
  }, {
132
- default: withCtx(() => [..._cache[14] || (_cache[14] = [createTextVNode(" Auth URL ", -1)])]),
214
+ default: withCtx(() => [..._cache[16] || (_cache[16] = [createTextVNode(" Auth URL ", -1)])]),
133
215
  _: 1
134
216
  }, 8, ["environment", "modelValue"])) : createCommentVNode("", true), "tokenUrl" in flow.value ? (openBlock(), createBlock(RequestAuthDataTableInput_default, {
135
217
  key: 1,
@@ -141,7 +223,7 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
141
223
  handleOauth2Update({ tokenUrl: v });
142
224
  })
143
225
  }, {
144
- default: withCtx(() => [..._cache[15] || (_cache[15] = [createTextVNode(" Token URL ", -1)])]),
226
+ default: withCtx(() => [..._cache[17] || (_cache[17] = [createTextVNode(" Token URL ", -1)])]),
145
227
  _: 1
146
228
  }, 8, ["environment", "modelValue"])) : createCommentVNode("", true)]),
147
229
  _: 1
@@ -150,12 +232,13 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
150
232
  default: withCtx(() => [createVNode(RequestAuthDataTableInput_default, {
151
233
  environment: __props.environment,
152
234
  modelValue: flow.value["x-scalar-secret-redirect-uri"],
153
- placeholder: "https://galaxy.scalar.com/callback",
235
+ placeholder: "Optional redirect URL",
154
236
  "onUpdate:modelValue": _cache[4] || (_cache[4] = (v) => {
237
+ hasHandledRedirectPrefill.value = true;
155
238
  handleOauth2SecretsUpdate({ "x-scalar-secret-redirect-uri": v });
156
239
  })
157
240
  }, {
158
- default: withCtx(() => [..._cache[16] || (_cache[16] = [createTextVNode(" Redirect URL ", -1)])]),
241
+ default: withCtx(() => [..._cache[18] || (_cache[18] = [createTextVNode(" Redirect URL ", -1)])]),
159
242
  _: 1
160
243
  }, 8, ["environment", "modelValue"])]),
161
244
  _: 1
@@ -168,7 +251,7 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
168
251
  placeholder: "janedoe",
169
252
  "onUpdate:modelValue": _cache[5] || (_cache[5] = (v) => handleOauth2SecretsUpdate({ "x-scalar-secret-username": v }))
170
253
  }, {
171
- default: withCtx(() => [..._cache[17] || (_cache[17] = [createTextVNode(" Username ", -1)])]),
254
+ default: withCtx(() => [..._cache[19] || (_cache[19] = [createTextVNode(" Username ", -1)])]),
172
255
  _: 1
173
256
  }, 8, ["environment", "modelValue"])]),
174
257
  _: 1
@@ -180,7 +263,7 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
180
263
  type: "password",
181
264
  "onUpdate:modelValue": _cache[6] || (_cache[6] = (v) => handleOauth2SecretsUpdate({ "x-scalar-secret-password": v }))
182
265
  }, {
183
- default: withCtx(() => [..._cache[18] || (_cache[18] = [createTextVNode(" Password ", -1)])]),
266
+ default: withCtx(() => [..._cache[20] || (_cache[20] = [createTextVNode(" Password ", -1)])]),
184
267
  _: 1
185
268
  }, 8, ["environment", "modelValue"])]),
186
269
  _: 1
@@ -192,7 +275,7 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
192
275
  placeholder: "12345",
193
276
  "onUpdate:modelValue": _cache[7] || (_cache[7] = (v) => handleOauth2SecretsUpdate({ "x-scalar-secret-client-id": v }))
194
277
  }, {
195
- default: withCtx(() => [..._cache[19] || (_cache[19] = [createTextVNode(" Client ID ", -1)])]),
278
+ default: withCtx(() => [..._cache[21] || (_cache[21] = [createTextVNode(" Client ID ", -1)])]),
196
279
  _: 1
197
280
  }, 8, ["environment", "modelValue"])]),
198
281
  _: 1
@@ -205,7 +288,7 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
205
288
  type: "password",
206
289
  "onUpdate:modelValue": _cache[8] || (_cache[8] = (v) => handleOauth2SecretsUpdate({ "x-scalar-secret-client-secret": v }))
207
290
  }, {
208
- default: withCtx(() => [..._cache[20] || (_cache[20] = [createTextVNode(" Client Secret ", -1)])]),
291
+ default: withCtx(() => [..._cache[22] || (_cache[22] = [createTextVNode(" Client Secret ", -1)])]),
209
292
  _: 1
210
293
  }, 8, ["environment", "modelValue"])]),
211
294
  _: 1
@@ -218,7 +301,7 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
218
301
  readOnly: "",
219
302
  "onUpdate:modelValue": _cache[9] || (_cache[9] = (v) => handleOauth2Update({ "x-usePkce": v }))
220
303
  }, {
221
- default: withCtx(() => [..._cache[21] || (_cache[21] = [createTextVNode(" Use PKCE ", -1)])]),
304
+ default: withCtx(() => [..._cache[23] || (_cache[23] = [createTextVNode(" Use PKCE ", -1)])]),
222
305
  _: 1
223
306
  }, 8, [
224
307
  "enum",
@@ -236,7 +319,7 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
236
319
  readOnly: "",
237
320
  "onUpdate:modelValue": _cache[10] || (_cache[10] = (v) => handleSecretLocationUpdate(v))
238
321
  }, {
239
- default: withCtx(() => [..._cache[22] || (_cache[22] = [createTextVNode(" Credentials Location ", -1)])]),
322
+ default: withCtx(() => [..._cache[24] || (_cache[24] = [createTextVNode(" Credentials Location ", -1)])]),
240
323
  _: 1
241
324
  }, 8, ["environment", "modelValue"])]),
242
325
  _: 1
@@ -258,21 +341,21 @@ var OAuth2_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineC
258
341
  default: withCtx(() => [createElementVNode("div", _hoisted_2, [__props.scheme.type === "openIdConnect" ? (openBlock(), createBlock(unref(ScalarButton), {
259
342
  key: 0,
260
343
  class: "mr-1 p-0 px-2 py-0.5",
261
- loader: unref(loader),
344
+ disabled: unref(loader).isLoading,
262
345
  size: "sm",
263
346
  variant: "outlined",
264
347
  onClick: clearOauth2Secrets
265
348
  }, {
266
- default: withCtx(() => [..._cache[23] || (_cache[23] = [createTextVNode(" Clear ", -1)])]),
349
+ default: withCtx(() => [..._cache[25] || (_cache[25] = [createTextVNode(" Clear ", -1)])]),
267
350
  _: 1
268
- }, 8, ["loader"])) : createCommentVNode("", true), createVNode(unref(ScalarButton), {
351
+ }, 8, ["disabled"])) : createCommentVNode("", true), createVNode(unref(ScalarButton), {
269
352
  class: "mr-0.75 p-0 px-2 py-0.5",
270
353
  loader: unref(loader),
271
354
  size: "sm",
272
355
  variant: "outlined",
273
356
  onClick: handleAuthorize
274
357
  }, {
275
- default: withCtx(() => [..._cache[24] || (_cache[24] = [createTextVNode(" Authorize ", -1)])]),
358
+ default: withCtx(() => [..._cache[26] || (_cache[26] = [createTextVNode(" Authorize ", -1)])]),
276
359
  _: 1
277
360
  }, 8, ["loader"])])]),
278
361
  _: 1