@scalar/api-reference 1.63.0 → 1.64.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 (257) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/dist/blocks/scalar-info-block/components/DownloadLink.vue.d.ts.map +1 -1
  3. package/dist/blocks/scalar-info-block/components/DownloadLink.vue.js +1 -1
  4. package/dist/blocks/scalar-info-block/components/DownloadLink.vue.js.map +1 -1
  5. package/dist/blocks/scalar-info-block/components/DownloadLink.vue.script.js.map +1 -1
  6. package/dist/blocks/scalar-info-block/components/IntroductionCard.vue.d.ts.map +1 -1
  7. package/dist/blocks/scalar-info-block/components/IntroductionCard.vue.js +1 -1
  8. package/dist/blocks/scalar-info-block/components/IntroductionCard.vue.js.map +1 -1
  9. package/dist/blocks/scalar-info-block/components/IntroductionCard.vue.script.js.map +1 -1
  10. package/dist/blocks/scalar-info-block/components/IntroductionLoading.vue.d.ts.map +1 -1
  11. package/dist/blocks/scalar-info-block/components/IntroductionLoading.vue.js +1 -1
  12. package/dist/blocks/scalar-info-block/components/IntroductionLoading.vue.js.map +1 -1
  13. package/dist/blocks/scalar-info-block/components/IntroductionLoading.vue.script.js +4 -4
  14. package/dist/blocks/scalar-info-block/components/IntroductionLoading.vue.script.js.map +1 -1
  15. package/dist/browser/chunks/AgentScalarChatInterface-C8lX3RCo.js +27 -0
  16. package/dist/browser/chunks/ScalarTextInput.vue-Xf60Nwf-.js +27 -0
  17. package/dist/browser/chunks/basic-shape-diamond.svg-BTEOT1FL.js +1 -1
  18. package/dist/browser/chunks/basic-shape-hexagon.svg-BSPzaCgF.js +1 -1
  19. package/dist/browser/chunks/basic-shape-primary-circle-ellipse-round.svg-DKmZ8UUU.js +1 -1
  20. package/dist/browser/chunks/basic-shape-primary-square-rectangle.svg-n2YRykHD.js +1 -1
  21. package/dist/browser/chunks/basic-shape-shield.svg-Bec9cJDA.js +1 -1
  22. package/dist/browser/chunks/browser-67K6wmG9.js +1 -1
  23. package/dist/browser/chunks/computer-device-desktop-monitor.svg-m6j893Hb.js +1 -1
  24. package/dist/browser/chunks/computer-device-desktop.svg-Dk1VVO7k.js +1 -1
  25. package/dist/browser/chunks/computer-device-laptop.svg-BNGVUCYS.js +1 -1
  26. package/dist/browser/chunks/computer-device-mobile-phone-android-samsung-back.svg-CC4UUTFw.js +1 -1
  27. package/dist/browser/chunks/computer-device-mobile-phone-android-samsung.svg-D8ExpMpL.js +1 -1
  28. package/dist/browser/chunks/computer-device-mobile-phone-iphone-x-back.svg-CLm7sgMM.js +1 -1
  29. package/dist/browser/chunks/computer-device-mobile-phone-iphone-x.svg-Xrttg6_7.js +1 -1
  30. package/dist/browser/chunks/computer-device-mobile-tablet-touch.svg-DQ2oTvOG.js +1 -1
  31. package/dist/browser/chunks/computer-device-mobile-tablet.svg-DCr0XlRc.js +1 -1
  32. package/dist/browser/chunks/computer-device-network-ethernet-cat6.svg-AK9l0iOl.js +1 -1
  33. package/dist/browser/chunks/computer-device-network-lan-www.svg-gUIdFBlE.js +1 -1
  34. package/dist/browser/chunks/computer-device-network-wifi-connection.svg-Be-EMm4e.js +1 -1
  35. package/dist/browser/chunks/computer-device-network-wifi-router.svg-Dc2VzyqK.js +1 -1
  36. package/dist/browser/chunks/ecology-science-erlenmeyer-flask.svg-DHgy7Jfd.js +1 -1
  37. package/dist/browser/chunks/image-flash-lightning.svg-EETR_y1q.js +1 -1
  38. package/dist/browser/chunks/image-picture-flower.svg-DN1AYzJU.js +1 -1
  39. package/dist/browser/chunks/interface-alert-exclamation-diamond.svg-C5NozMV_.js +1 -1
  40. package/dist/browser/chunks/interface-alert-exclamation-triangle-warning.svg-DaAg2fF5.js +1 -1
  41. package/dist/browser/chunks/interface-alert-information-circle.svg-ckkkt9Mv.js +1 -1
  42. package/dist/browser/chunks/interface-award-crown.svg-pjvn9hY-.js +1 -1
  43. package/dist/browser/chunks/interface-bookmark-tag.svg-r2r-lQq4.js +1 -1
  44. package/dist/browser/chunks/interface-bookmark.svg-BK9HKQBT.js +1 -1
  45. package/dist/browser/chunks/interface-calendar-date-one.svg-DNnF0M1I.js +1 -1
  46. package/dist/browser/chunks/interface-content-book-open-pages.svg-CQj_w9Vp.js +1 -1
  47. package/dist/browser/chunks/interface-content-book-page.svg-DppoeJRe.js +1 -1
  48. package/dist/browser/chunks/interface-content-file.svg-CvcD7OiY.js +1 -1
  49. package/dist/browser/chunks/interface-content-folder.svg-BmtS5I9A.js +1 -1
  50. package/dist/browser/chunks/interface-copy-clipboard.svg-Be6EI50X.js +1 -1
  51. package/dist/browser/chunks/interface-edit-attachment.svg-G5TKzpWX.js +1 -1
  52. package/dist/browser/chunks/interface-edit-binocular.svg-jzL-DvGB.js +1 -1
  53. package/dist/browser/chunks/interface-edit-magic-wand.svg-BOTlymvp.js +1 -1
  54. package/dist/browser/chunks/interface-edit-tool-paint-roller.svg-s9dwryx7.js +1 -1
  55. package/dist/browser/chunks/interface-edit-tool-pencil.svg-C7v0dbB3.js +1 -1
  56. package/dist/browser/chunks/interface-favorite-award.svg-CYHUgUG0.js +1 -1
  57. package/dist/browser/chunks/interface-favorite-flag.svg-C10zlKOb.js +1 -1
  58. package/dist/browser/chunks/interface-favorite-heart.svg-eoduXxlz.js +1 -1
  59. package/dist/browser/chunks/interface-favorite-star.svg-BSmxJetr.js +1 -1
  60. package/dist/browser/chunks/interface-favorite-stars-sparkles.svg-JTFLj3Ls.js +1 -1
  61. package/dist/browser/chunks/interface-hierarchy-flowchart.svg-Cg_Wy0kN.js +1 -1
  62. package/dist/browser/chunks/interface-home-house.svg-DytoGRnv.js +1 -1
  63. package/dist/browser/chunks/interface-hyperlink.svg-CuEfmmQI.js +1 -1
  64. package/dist/browser/chunks/interface-lighting-brightness.svg-DSK0h_Pa.js +1 -1
  65. package/dist/browser/chunks/interface-lock-closed.svg-Cn6TaLYv.js +1 -1
  66. package/dist/browser/chunks/interface-lock-open-unlock.svg-CVkG5-9W.js +1 -1
  67. package/dist/browser/chunks/interface-login-key.svg-y-cwwXjN.js +1 -1
  68. package/dist/browser/chunks/interface-search.svg-S-puVFJB.js +1 -1
  69. package/dist/browser/chunks/interface-setting-cog.svg-CTH4_lLg.js +1 -1
  70. package/dist/browser/chunks/interface-share-megaphone-bullhorn.svg-Pbp39MyC.js +1 -1
  71. package/dist/browser/chunks/interface-share-rocket.svg-BgCsIRZO.js +1 -1
  72. package/dist/browser/chunks/interface-share-satellite.svg-DAMN9d5G.js +1 -1
  73. package/dist/browser/chunks/interface-share-space-ship.svg-Dt-Mejxk.js +1 -1
  74. package/dist/browser/chunks/interface-share.svg-vFYTXSti.js +1 -1
  75. package/dist/browser/chunks/interface-signal-square.svg-DNG4LpAe.js +1 -1
  76. package/dist/browser/chunks/interface-time-clock-circle.svg-Bpz-nLxo.js +1 -1
  77. package/dist/browser/chunks/interface-time-hour-glass.svg-D7agfKsH.js +1 -1
  78. package/dist/browser/chunks/interface-users-multiple.svg-CkPJBBnG.js +1 -1
  79. package/dist/browser/chunks/interface-weather-moon.svg-CaTZFMPO.js +1 -1
  80. package/dist/browser/chunks/mail-chat-bubble-square.svg-DC8RIihp.js +1 -1
  81. package/dist/browser/chunks/mail-send-email-paper-airplane.svg-D8OLs9jz.js +1 -1
  82. package/dist/browser/chunks/mail-send-envelope.svg-CV33h5Sx.js +1 -1
  83. package/dist/browser/chunks/{modal-BVUfMpuv.js → modal-B8Opb61-.js} +2 -2
  84. package/dist/browser/chunks/modal-Dcl-Y2Zk.js +99 -0
  85. package/dist/browser/chunks/money-cashier-receipt.svg-CJL8C2gs.js +1 -1
  86. package/dist/browser/chunks/money-currency-dollar-pay.svg-VdBplCTx.js +1 -1
  87. package/dist/browser/chunks/money-graph-arrow-increase.svg-DcRov3zk.js +1 -1
  88. package/dist/browser/chunks/money-graph-bar-chart-increase.svg-Cc7KxjX-.js +1 -1
  89. package/dist/browser/chunks/nature-ecology-leaf.svg-DR3cTZxt.js +1 -1
  90. package/dist/browser/chunks/phone-telephone.svg-DyY0gUlk.js +1 -1
  91. package/dist/browser/chunks/programming-bug.svg-BHLT-Qhp.js +1 -1
  92. package/dist/browser/chunks/programming-cloud.svg-B6YW33ba.js +1 -1
  93. package/dist/browser/chunks/programming-computer-database-server.svg-B6o5Sdn-.js +1 -1
  94. package/dist/browser/chunks/programming-computer-database.svg-Cl7OVtpJ.js +1 -1
  95. package/dist/browser/chunks/programming-module-four-layout.svg-BQrerL1x.js +1 -1
  96. package/dist/browser/chunks/programming-module-three.svg-B2KTQzBM.js +1 -1
  97. package/dist/browser/chunks/programming-module.svg-CiID7kPm.js +1 -1
  98. package/dist/browser/chunks/programming-script-code.svg-D1M5rtkN.js +1 -1
  99. package/dist/browser/chunks/runtime-core.esm-bundler-Byrbbu5Q.js +1 -1
  100. package/dist/browser/chunks/shopping-cart.svg-BEegiIR9.js +1 -1
  101. package/dist/browser/chunks/shopping-gift-present.svg-BUHwuLix.js +1 -1
  102. package/dist/browser/chunks/shopping-shipping-box-parcel-package.svg-D6fxWdYx.js +1 -1
  103. package/dist/browser/chunks/tag-new-circle.svg-jsg1bGs0.js +1 -1
  104. package/dist/browser/chunks/travel-map-earth-globe.svg-ClbMiU-f.js +1 -1
  105. package/dist/browser/chunks/vendor-CBP43oHJ.js +306 -0
  106. package/dist/browser/standalone.esm.js +24 -24
  107. package/dist/browser/standalone.js +308 -308
  108. package/dist/components/ApiReference.vue.d.ts.map +1 -1
  109. package/dist/components/ApiReference.vue.js +1 -1
  110. package/dist/components/ApiReference.vue.js.map +1 -1
  111. package/dist/components/ApiReference.vue.script.js +94 -19
  112. package/dist/components/ApiReference.vue.script.js.map +1 -1
  113. package/dist/components/Badge/Badge.vue.d.ts.map +1 -1
  114. package/dist/components/Badge/Badge.vue.js +1 -1
  115. package/dist/components/Badge/Badge.vue.js.map +1 -1
  116. package/dist/components/Badge/Badge.vue.script.js +8 -8
  117. package/dist/components/Badge/Badge.vue.script.js.map +1 -1
  118. package/dist/components/Content/AsyncApi/Operation.vue.d.ts.map +1 -1
  119. package/dist/components/Content/AsyncApi/Operation.vue.js +1 -1
  120. package/dist/components/Content/AsyncApi/Operation.vue.js.map +1 -1
  121. package/dist/components/Content/AsyncApi/Operation.vue.script.js +5 -0
  122. package/dist/components/Content/AsyncApi/Operation.vue.script.js.map +1 -1
  123. package/dist/components/Content/AsyncApi/helpers/get-async-api-required-security.d.ts +17 -0
  124. package/dist/components/Content/AsyncApi/helpers/get-async-api-required-security.d.ts.map +1 -0
  125. package/dist/components/Content/AsyncApi/helpers/get-async-api-required-security.js +21 -0
  126. package/dist/components/Content/AsyncApi/helpers/get-async-api-required-security.js.map +1 -0
  127. package/dist/components/Content/Schema/SchemaComposition.vue.d.ts.map +1 -1
  128. package/dist/components/Content/Schema/SchemaComposition.vue.js.map +1 -1
  129. package/dist/components/Content/Schema/SchemaComposition.vue.script.js +68 -33
  130. package/dist/components/Content/Schema/SchemaComposition.vue.script.js.map +1 -1
  131. package/dist/components/Content/Schema/SchemaEnums.vue.d.ts.map +1 -1
  132. package/dist/components/Content/Schema/SchemaEnums.vue.js +1 -1
  133. package/dist/components/Content/Schema/SchemaEnums.vue.js.map +1 -1
  134. package/dist/components/Content/Schema/SchemaEnums.vue.script.js +15 -7
  135. package/dist/components/Content/Schema/SchemaEnums.vue.script.js.map +1 -1
  136. package/dist/components/Content/Schema/SchemaPropertyHeading.vue.d.ts.map +1 -1
  137. package/dist/components/Content/Schema/SchemaPropertyHeading.vue.js +1 -1
  138. package/dist/components/Content/Schema/SchemaPropertyHeading.vue.js.map +1 -1
  139. package/dist/components/Content/Schema/SchemaPropertyHeading.vue.script.js +30 -20
  140. package/dist/components/Content/Schema/SchemaPropertyHeading.vue.script.js.map +1 -1
  141. package/dist/components/Content/Schema/helpers/optimize-value-for-display.d.ts.map +1 -1
  142. package/dist/components/Content/Schema/helpers/optimize-value-for-display.js +1 -4
  143. package/dist/components/Content/Schema/helpers/optimize-value-for-display.js.map +1 -1
  144. package/dist/components/Content/Schema/helpers/partition-all-of-compositions.d.ts +32 -0
  145. package/dist/components/Content/Schema/helpers/partition-all-of-compositions.d.ts.map +1 -0
  146. package/dist/components/Content/Schema/helpers/partition-all-of-compositions.js +97 -0
  147. package/dist/components/Content/Schema/helpers/partition-all-of-compositions.js.map +1 -0
  148. package/dist/components/LinkList/LinkList.vue.js +1 -1
  149. package/dist/components/LinkList/LinkList.vue.js.map +1 -1
  150. package/dist/components/LinkList/LinkList.vue.script.js +1 -1
  151. package/dist/components/LinkList/LinkList.vue.script.js.map +1 -1
  152. package/dist/components/Section/CompactSection.vue.d.ts.map +1 -1
  153. package/dist/components/Section/CompactSection.vue.js +1 -1
  154. package/dist/components/Section/CompactSection.vue.js.map +1 -1
  155. package/dist/components/Section/CompactSection.vue.script.js +21 -5
  156. package/dist/components/Section/CompactSection.vue.script.js.map +1 -1
  157. package/dist/components/Section/SectionHeader.vue.d.ts.map +1 -1
  158. package/dist/components/Section/SectionHeader.vue.js +1 -1
  159. package/dist/components/Section/SectionHeader.vue.js.map +1 -1
  160. package/dist/components/Section/SectionHeader.vue.script.js +1 -1
  161. package/dist/components/Section/SectionHeader.vue.script.js.map +1 -1
  162. package/dist/features/Operation/Operation.vue.script.js +1 -1
  163. package/dist/features/Operation/components/OperationScopes.vue.d.ts +8 -0
  164. package/dist/features/Operation/components/OperationScopes.vue.d.ts.map +1 -0
  165. package/dist/features/Operation/components/OperationScopes.vue.js +7 -0
  166. package/dist/features/Operation/components/OperationScopes.vue.js.map +1 -0
  167. package/dist/features/Operation/components/OperationScopes.vue.script.js +60 -0
  168. package/dist/features/Operation/components/OperationScopes.vue.script.js.map +1 -0
  169. package/dist/features/Operation/components/SecurityRequirementBadge.vue.d.ts.map +1 -1
  170. package/dist/features/Operation/components/SecurityRequirementBadge.vue.js.map +1 -1
  171. package/dist/features/Operation/components/SecurityRequirementBadge.vue.script.js +89 -16
  172. package/dist/features/Operation/components/SecurityRequirementBadge.vue.script.js.map +1 -1
  173. package/dist/features/Operation/helpers/get-required-security.d.ts +13 -0
  174. package/dist/features/Operation/helpers/get-required-security.d.ts.map +1 -1
  175. package/dist/features/Operation/helpers/get-required-security.js +22 -1
  176. package/dist/features/Operation/helpers/get-required-security.js.map +1 -1
  177. package/dist/features/Operation/layouts/ClassicLayout.vue.d.ts +1 -1
  178. package/dist/features/Operation/layouts/ClassicLayout.vue.d.ts.map +1 -1
  179. package/dist/features/Operation/layouts/ClassicLayout.vue.js +1 -1
  180. package/dist/features/Operation/layouts/ClassicLayout.vue.js.map +1 -1
  181. package/dist/features/Operation/layouts/ClassicLayout.vue.script.js +15 -6
  182. package/dist/features/Operation/layouts/ClassicLayout.vue.script.js.map +1 -1
  183. package/dist/features/Operation/layouts/ModernLayout.vue.d.ts.map +1 -1
  184. package/dist/features/Operation/layouts/ModernLayout.vue.js +1 -1
  185. package/dist/features/Operation/layouts/ModernLayout.vue.js.map +1 -1
  186. package/dist/features/Operation/layouts/ModernLayout.vue.script.js +2 -0
  187. package/dist/features/Operation/layouts/ModernLayout.vue.script.js.map +1 -1
  188. package/dist/features/developer-tools/components/ApiReferenceToolbarConfigTheme.vue.d.ts +2 -2
  189. package/dist/features/developer-tools/components/ApiReferenceToolbarPopover.vue.script.js +1 -1
  190. package/dist/features/external-docs/ExternalDocs.vue.d.ts.map +1 -1
  191. package/dist/features/external-docs/ExternalDocs.vue.js.map +1 -1
  192. package/dist/features/external-docs/ExternalDocs.vue.script.js +6 -6
  193. package/dist/features/external-docs/ExternalDocs.vue.script.js.map +1 -1
  194. package/dist/features/info-object/Contact.vue.d.ts.map +1 -1
  195. package/dist/features/info-object/Contact.vue.js.map +1 -1
  196. package/dist/features/info-object/Contact.vue.script.js +8 -8
  197. package/dist/features/info-object/Contact.vue.script.js.map +1 -1
  198. package/dist/features/info-object/InfoLink.vue.d.ts.map +1 -1
  199. package/dist/features/info-object/InfoLink.vue.js.map +1 -1
  200. package/dist/features/info-object/InfoLink.vue.script.js +6 -6
  201. package/dist/features/info-object/InfoLink.vue.script.js.map +1 -1
  202. package/dist/features/info-object/License.vue.d.ts.map +1 -1
  203. package/dist/features/info-object/License.vue.js.map +1 -1
  204. package/dist/features/info-object/License.vue.script.js +2 -2
  205. package/dist/features/info-object/License.vue.script.js.map +1 -1
  206. package/dist/features/info-object/TermsOfService.vue.d.ts.map +1 -1
  207. package/dist/features/info-object/TermsOfService.vue.js.map +1 -1
  208. package/dist/features/info-object/TermsOfService.vue.script.js +2 -2
  209. package/dist/features/info-object/TermsOfService.vue.script.js.map +1 -1
  210. package/dist/features/localization/locales/ar.d.ts +1 -0
  211. package/dist/features/localization/locales/ar.d.ts.map +1 -1
  212. package/dist/features/localization/locales/ar.js +2 -1
  213. package/dist/features/localization/locales/ar.js.map +1 -1
  214. package/dist/features/localization/locales/de.d.ts +1 -0
  215. package/dist/features/localization/locales/de.d.ts.map +1 -1
  216. package/dist/features/localization/locales/de.js +2 -1
  217. package/dist/features/localization/locales/de.js.map +1 -1
  218. package/dist/features/localization/locales/en.d.ts +1 -0
  219. package/dist/features/localization/locales/en.d.ts.map +1 -1
  220. package/dist/features/localization/locales/en.js +2 -1
  221. package/dist/features/localization/locales/en.js.map +1 -1
  222. package/dist/features/localization/locales/es.d.ts +1 -0
  223. package/dist/features/localization/locales/es.d.ts.map +1 -1
  224. package/dist/features/localization/locales/es.js +2 -1
  225. package/dist/features/localization/locales/es.js.map +1 -1
  226. package/dist/features/localization/locales/fr.d.ts +1 -0
  227. package/dist/features/localization/locales/fr.d.ts.map +1 -1
  228. package/dist/features/localization/locales/fr.js +2 -1
  229. package/dist/features/localization/locales/fr.js.map +1 -1
  230. package/dist/features/localization/locales/ru.d.ts +1 -0
  231. package/dist/features/localization/locales/ru.d.ts.map +1 -1
  232. package/dist/features/localization/locales/ru.js +2 -1
  233. package/dist/features/localization/locales/ru.js.map +1 -1
  234. package/dist/features/localization/locales/zh-cn.d.ts +1 -0
  235. package/dist/features/localization/locales/zh-cn.d.ts.map +1 -1
  236. package/dist/features/localization/locales/zh-cn.js +2 -1
  237. package/dist/features/localization/locales/zh-cn.js.map +1 -1
  238. package/dist/features/localization/translations.d.ts +7 -0
  239. package/dist/features/localization/translations.d.ts.map +1 -1
  240. package/dist/helpers/storage.d.ts +21 -2
  241. package/dist/helpers/storage.d.ts.map +1 -1
  242. package/dist/standalone/lib/html-api.d.ts.map +1 -1
  243. package/dist/standalone/lib/html-api.js +11 -4
  244. package/dist/standalone/lib/html-api.js.map +1 -1
  245. package/dist/standalone/lib/load-plugins-from-urls.d.ts +13 -0
  246. package/dist/standalone/lib/load-plugins-from-urls.d.ts.map +1 -0
  247. package/dist/standalone/lib/load-plugins-from-urls.js +60 -0
  248. package/dist/standalone/lib/load-plugins-from-urls.js.map +1 -0
  249. package/dist/style.css +358 -320
  250. package/dist/styles/print.css +118 -0
  251. package/dist/styles/tailwind.config.css +16 -0
  252. package/dist/vue-styles.css +167 -193
  253. package/package.json +16 -16
  254. package/dist/browser/chunks/AgentScalarChatInterface-YU9KKgvZ.js +0 -27
  255. package/dist/browser/chunks/ScalarTextInput.vue-B-Nhpn0q.js +0 -27
  256. package/dist/browser/chunks/modal-WJ4Gcv8N.js +0 -99
  257. package/dist/browser/chunks/vendor-BqFs9NIb.js +0 -306
@@ -1 +1 @@
1
- {"version":3,"file":"SectionHeader.vue.script.js","names":["$slots"],"sources":["../../../src/components/Section/SectionHeader.vue"],"sourcesContent":["<script setup lang=\"ts\">\nconst { tight, removeMargin = false } = defineProps<{\n tight?: boolean\n removeMargin?: boolean\n}>()\n</script>\n\n<template>\n <div class=\"section-header-wrapper xl:gap-12\">\n <div\n class=\"section-header\"\n :class=\"{ tight, 'mb-3': !removeMargin }\">\n <slot />\n </div>\n <slot\n v-if=\"$slots.links\"\n name=\"links\" />\n </div>\n</template>\n\n<style scoped>\n@reference \"@/style.css\";\n\n.section-header-wrapper {\n display: grid;\n grid-template-columns: 1fr;\n}\n\n@variant xl {\n .section-header-wrapper {\n grid-template-columns: repeat(2, 1fr);\n }\n}\n\n.section-header {\n font-size: var(--font-size, var(--scalar-heading-1));\n font-weight: var(--font-weight, var(--scalar-bold));\n /* prettier-ignore */\n color: var(--scalar-color-1);\n word-wrap: break-word;\n line-height: 1.45;\n margin-top: 0;\n}\n\n.section-header.tight {\n margin-bottom: 6px;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;uBAQE,mBASM,OATN,YASM,CARJ,mBAIM,OAAA,EAHJ,OAAK,eAAA,CAAC,kBAAgB;IAAA,OACZ,QAAA;IAAK,QAAA,CAAW,QAAA;IAAY,CAAA,CAAA,EAAA,EAAA,CACtC,WAAQ,KAAA,QAAA,WAAA,EAAA,EAAA,KAAA,GAAA,KAAA,CAAA,EAAA,EAAA,EAGFA,KAAAA,OAAO,QADf,WAEiB,KAAA,QAAA,SAAA,EAAA,KAAA,GAAA,EAAA,KAAA,GAAA,KAAA,GAAA,mBAAA,IAAA,KAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"SectionHeader.vue.script.js","names":["$slots"],"sources":["../../../src/components/Section/SectionHeader.vue"],"sourcesContent":["<script setup lang=\"ts\">\nconst { tight, removeMargin = false } = defineProps<{\n tight?: boolean\n removeMargin?: boolean\n}>()\n</script>\n\n<!--\n The reference is an embeddable widget, so the header collapses based on the\n rendered width of the reference (the narrow: variant), not the viewport.\n The section-header-wrapper class stays as a styling hook for\n SectionContainerAccordion.\n-->\n<template>\n <div\n class=\"section-header-wrapper narrow:grid-cols-1 narrow:gap-0 grid grid-cols-2 gap-12\">\n <div\n class=\"section-header\"\n :class=\"{ tight, 'mb-3': !removeMargin }\">\n <slot />\n </div>\n <slot\n v-if=\"$slots.links\"\n name=\"links\" />\n </div>\n</template>\n\n<style scoped>\n.section-header {\n font-size: var(--font-size, var(--scalar-heading-1));\n font-weight: var(--font-weight, var(--scalar-bold));\n /* prettier-ignore */\n color: var(--scalar-color-1);\n word-wrap: break-word;\n line-height: 1.45;\n margin-top: 0;\n}\n\n.section-header.tight {\n margin-bottom: 6px;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;uBAcE,mBAUM,OAVN,YAUM,CARJ,mBAIM,OAAA,EAHJ,OAAK,eAAA,CAAC,kBAAgB;IAAA,OACZ,QAAA;IAAK,QAAA,CAAW,QAAA;IAAY,CAAA,CAAA,EAAA,EAAA,CACtC,WAAQ,KAAA,QAAA,WAAA,EAAA,EAAA,KAAA,GAAA,KAAA,CAAA,EAAA,EAAA,EAGFA,KAAAA,OAAO,QADf,WAEiB,KAAA,QAAA,SAAA,EAAA,KAAA,GAAA,EAAA,KAAA,GAAA,KAAA,GAAA,mBAAA,IAAA,KAAA,CAAA,CAAA"}
@@ -1,5 +1,5 @@
1
- import { filterSelectedSecurity } from "./helpers/filter-selected-security.js";
2
1
  import { getRequiredSecurity } from "./helpers/get-required-security.js";
2
+ import { filterSelectedSecurity } from "./helpers/filter-selected-security.js";
3
3
  import ClassicLayout_default from "./layouts/ClassicLayout.vue.js";
4
4
  import ModernLayout_default from "./layouts/ModernLayout.vue.js";
5
5
  import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, defineComponent, openBlock } from "vue";
@@ -0,0 +1,8 @@
1
+ import { type RequiredSecurity } from '../../../features/Operation/helpers/get-required-security.js';
2
+ type __VLS_Props = {
3
+ requiredSecurity: RequiredSecurity;
4
+ };
5
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
6
+ declare const _default: typeof __VLS_export;
7
+ export default _default;
8
+ //# sourceMappingURL=OperationScopes.vue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OperationScopes.vue.d.ts","sourceRoot":"","sources":["../../../../src/features/Operation/components/OperationScopes.vue"],"names":[],"mappings":"AA+EA,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,oDAAoD,CAAA;AAE3D,KAAK,WAAW,GAAG;IACjB,gBAAgB,EAAE,gBAAgB,CAAA;CACnC,CAAC;AA+GF,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
@@ -0,0 +1,7 @@
1
+ import OperationScopes_vue_vue_type_script_setup_true_lang_default from "./OperationScopes.vue.script.js";
2
+ //#region src/features/Operation/components/OperationScopes.vue
3
+ var OperationScopes_default = OperationScopes_vue_vue_type_script_setup_true_lang_default;
4
+ //#endregion
5
+ export { OperationScopes_default as default };
6
+
7
+ //# sourceMappingURL=OperationScopes.vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OperationScopes.vue.js","names":[],"sources":["../../../../src/features/Operation/components/OperationScopes.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { useLocalization } from '@/features/localization'\nimport {\n getRequiredScopeGroups,\n type RequiredSecurity,\n} from '@/features/Operation/helpers/get-required-security'\n\nconst { requiredSecurity } = defineProps<{\n requiredSecurity: RequiredSecurity\n}>()\n\nconst { translate } = useLocalization()\n\n/**\n * Required OAuth scopes grouped by security alternative (OR). A single group is the\n * common case and renders as a plain list. Multiple groups are kept separate so that\n * mutually exclusive scope sets are not implied to be required all at once.\n */\nconst scopeGroups = computed(() => getRequiredScopeGroups(requiredSecurity))\n\n/**\n * Whether at least one security alternative is satisfied without any OAuth scopes\n * (for example an API key or HTTP bearer). Those alternatives carry no scopes, so they\n * are absent from `scopeGroups`, but their existence means the listed scopes are only\n * required for some auth paths — not mandatory for the operation.\n */\nconst hasScopeFreeAlternative = computed(() =>\n requiredSecurity.requirements.some((group) =>\n group.schemes.every((scheme) => scheme.scopes.length === 0),\n ),\n)\n\n/**\n * Show the \"one of\" hint whenever the listed scopes are just one of several auth\n * alternatives — either multiple scoped groups, or a single scoped group alongside a\n * scope-free alternative. Without it, a lone scope list would read as mandatory.\n */\nconst showAlternativesHint = computed(\n () =>\n scopeGroups.value.length > 1 ||\n (scopeGroups.value.length > 0 && hasScopeFreeAlternative.value),\n)\n</script>\n\n<template>\n <div\n v-if=\"scopeGroups.length\"\n class=\"mt-6\">\n <div class=\"text-c-1 mt-3 mb-3 text-lg leading-[1.45] font-medium\">\n {{ translate('authentication.scopes') }}\n </div>\n <!-- Multiple alternatives (or a scope-free one): satisfying any single alternative is enough (OR). -->\n <div\n v-if=\"showAlternativesHint\"\n class=\"text-c-2 mb-2 text-sm\">\n {{ translate('authentication.oneOf') }}\n </div>\n <ul\n v-for=\"(group, index) in scopeGroups\"\n :key=\"index\"\n class=\"mb-3 list-none p-0 text-sm\"\n :class=\"{ 'mt-3 border-t pt-3': scopeGroups.length > 1 && index > 0 }\">\n <li\n v-for=\"scope in group\"\n :key=\"scope\"\n class=\"font-code text-c-2\">\n {{ scope }}\n </li>\n </ul>\n </div>\n</template>\n"],"mappings":""}
@@ -0,0 +1,60 @@
1
+ import { useLocalization } from "../../localization/use-localization.js";
2
+ import { getRequiredScopeGroups } from "../helpers/get-required-security.js";
3
+ import { Fragment, computed, createCommentVNode, createElementBlock, createElementVNode, defineComponent, normalizeClass, openBlock, renderList, toDisplayString, unref } from "vue";
4
+ //#region src/features/Operation/components/OperationScopes.vue?vue&type=script&setup=true&lang.ts
5
+ var _hoisted_1 = {
6
+ key: 0,
7
+ class: "mt-6"
8
+ };
9
+ var _hoisted_2 = { class: "text-c-1 mt-3 mb-3 text-lg leading-[1.45] font-medium" };
10
+ var _hoisted_3 = {
11
+ key: 0,
12
+ class: "text-c-2 mb-2 text-sm"
13
+ };
14
+ var OperationScopes_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
15
+ __name: "OperationScopes",
16
+ props: { requiredSecurity: {} },
17
+ setup(__props) {
18
+ const { translate } = useLocalization();
19
+ /**
20
+ * Required OAuth scopes grouped by security alternative (OR). A single group is the
21
+ * common case and renders as a plain list. Multiple groups are kept separate so that
22
+ * mutually exclusive scope sets are not implied to be required all at once.
23
+ */
24
+ const scopeGroups = computed(() => getRequiredScopeGroups(__props.requiredSecurity));
25
+ /**
26
+ * Whether at least one security alternative is satisfied without any OAuth scopes
27
+ * (for example an API key or HTTP bearer). Those alternatives carry no scopes, so they
28
+ * are absent from `scopeGroups`, but their existence means the listed scopes are only
29
+ * required for some auth paths — not mandatory for the operation.
30
+ */
31
+ const hasScopeFreeAlternative = computed(() => __props.requiredSecurity.requirements.some((group) => group.schemes.every((scheme) => scheme.scopes.length === 0)));
32
+ /**
33
+ * Show the "one of" hint whenever the listed scopes are just one of several auth
34
+ * alternatives — either multiple scoped groups, or a single scoped group alongside a
35
+ * scope-free alternative. Without it, a lone scope list would read as mandatory.
36
+ */
37
+ const showAlternativesHint = computed(() => scopeGroups.value.length > 1 || scopeGroups.value.length > 0 && hasScopeFreeAlternative.value);
38
+ return (_ctx, _cache) => {
39
+ return scopeGroups.value.length ? (openBlock(), createElementBlock("div", _hoisted_1, [
40
+ createElementVNode("div", _hoisted_2, toDisplayString(unref(translate)("authentication.scopes")), 1),
41
+ showAlternativesHint.value ? (openBlock(), createElementBlock("div", _hoisted_3, toDisplayString(unref(translate)("authentication.oneOf")), 1)) : createCommentVNode("", true),
42
+ (openBlock(true), createElementBlock(Fragment, null, renderList(scopeGroups.value, (group, index) => {
43
+ return openBlock(), createElementBlock("ul", {
44
+ key: index,
45
+ class: normalizeClass(["mb-3 list-none p-0 text-sm", { "mt-3 border-t pt-3": scopeGroups.value.length > 1 && index > 0 }])
46
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(group, (scope) => {
47
+ return openBlock(), createElementBlock("li", {
48
+ key: scope,
49
+ class: "font-code text-c-2"
50
+ }, toDisplayString(scope), 1);
51
+ }), 128))], 2);
52
+ }), 128))
53
+ ])) : createCommentVNode("", true);
54
+ };
55
+ }
56
+ });
57
+ //#endregion
58
+ export { OperationScopes_vue_vue_type_script_setup_true_lang_default as default };
59
+
60
+ //# sourceMappingURL=OperationScopes.vue.script.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OperationScopes.vue.script.js","names":[],"sources":["../../../../src/features/Operation/components/OperationScopes.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { useLocalization } from '@/features/localization'\nimport {\n getRequiredScopeGroups,\n type RequiredSecurity,\n} from '@/features/Operation/helpers/get-required-security'\n\nconst { requiredSecurity } = defineProps<{\n requiredSecurity: RequiredSecurity\n}>()\n\nconst { translate } = useLocalization()\n\n/**\n * Required OAuth scopes grouped by security alternative (OR). A single group is the\n * common case and renders as a plain list. Multiple groups are kept separate so that\n * mutually exclusive scope sets are not implied to be required all at once.\n */\nconst scopeGroups = computed(() => getRequiredScopeGroups(requiredSecurity))\n\n/**\n * Whether at least one security alternative is satisfied without any OAuth scopes\n * (for example an API key or HTTP bearer). Those alternatives carry no scopes, so they\n * are absent from `scopeGroups`, but their existence means the listed scopes are only\n * required for some auth paths — not mandatory for the operation.\n */\nconst hasScopeFreeAlternative = computed(() =>\n requiredSecurity.requirements.some((group) =>\n group.schemes.every((scheme) => scheme.scopes.length === 0),\n ),\n)\n\n/**\n * Show the \"one of\" hint whenever the listed scopes are just one of several auth\n * alternatives — either multiple scoped groups, or a single scoped group alongside a\n * scope-free alternative. Without it, a lone scope list would read as mandatory.\n */\nconst showAlternativesHint = computed(\n () =>\n scopeGroups.value.length > 1 ||\n (scopeGroups.value.length > 0 && hasScopeFreeAlternative.value),\n)\n</script>\n\n<template>\n <div\n v-if=\"scopeGroups.length\"\n class=\"mt-6\">\n <div class=\"text-c-1 mt-3 mb-3 text-lg leading-[1.45] font-medium\">\n {{ translate('authentication.scopes') }}\n </div>\n <!-- Multiple alternatives (or a scope-free one): satisfying any single alternative is enough (OR). -->\n <div\n v-if=\"showAlternativesHint\"\n class=\"text-c-2 mb-2 text-sm\">\n {{ translate('authentication.oneOf') }}\n </div>\n <ul\n v-for=\"(group, index) in scopeGroups\"\n :key=\"index\"\n class=\"mb-3 list-none p-0 text-sm\"\n :class=\"{ 'mt-3 border-t pt-3': scopeGroups.length > 1 && index > 0 }\">\n <li\n v-for=\"scope in group\"\n :key=\"scope\"\n class=\"font-code text-c-2\">\n {{ scope }}\n </li>\n </ul>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;EAaA,MAAM,EAAE,cAAc,iBAAgB;;;;;;EAOtC,MAAM,cAAc,eAAe,uBAAuB,QAAA,iBAAiB,CAAA;;;;;;;EAQ3E,MAAM,0BAA0B,eAC9B,QAAA,iBAAiB,aAAa,MAAM,UAClC,MAAM,QAAQ,OAAO,WAAW,OAAO,OAAO,WAAW,EAAE,CAC5D,CACH;;;;;;EAOA,MAAM,uBAAuB,eAEzB,YAAY,MAAM,SAAS,KAC1B,YAAY,MAAM,SAAS,KAAK,wBAAwB,MAC7D;;UAKU,YAAA,MAAY,UAAA,WAAA,EADpB,mBAwBM,OAxBN,YAwBM;IArBJ,mBAEM,OAFN,YAEM,gBADD,MAAA,UAAS,CAAA,wBAAA,CAAA,EAAA,EAAA;IAIN,qBAAA,SAAA,WAAA,EADR,mBAIM,OAJN,YAIM,gBADD,MAAA,UAAS,CAAA,uBAAA,CAAA,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA;sBAEd,mBAWK,UAAA,MAAA,WAVsB,YAAA,QAAjB,OAAO,UAAK;yBADtB,mBAWK,MAAA;MATF,KAAK;MACN,OAAK,eAAA,CAAC,8BAA4B,EAAA,sBACF,YAAA,MAAY,SAAM,KAAQ,QAAK,GAAA,CAAA,CAAA;2BAC/D,mBAKK,UAAA,MAAA,WAJa,QAAT,UAAK;0BADd,mBAKK,MAAA;OAHF,KAAK;OACN,OAAM;yBACH,MAAK,EAAA,EAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"SecurityRequirementBadge.vue.d.ts","sourceRoot":"","sources":["../../../../src/features/Operation/components/SecurityRequirementBadge.vue"],"names":[],"mappings":"AA2IA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oDAAoD,CAAA;AAE1F,KAAK,WAAW,GAAG;IACjB,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAC;AAyPF,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
1
+ {"version":3,"file":"SecurityRequirementBadge.vue.d.ts","sourceRoot":"","sources":["../../../../src/features/Operation/components/SecurityRequirementBadge.vue"],"names":[],"mappings":"AAuOA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oDAAoD,CAAA;AAE1F,KAAK,WAAW,GAAG;IACjB,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAC;AAkWF,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
@@ -1 +1 @@
1
- {"version":3,"file":"SecurityRequirementBadge.vue.js","names":[],"sources":["../../../../src/features/Operation/components/SecurityRequirementBadge.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarPopover } from '@scalar/components/popover'\nimport { ScalarIconLockSimple, ScalarIconLockSimpleOpen } from '@scalar/icons'\nimport { computed } from 'vue'\n\nimport { useLocalization } from '@/features/localization'\nimport SecurityRequirementBadgeScheme from '@/features/Operation/components/SecurityRequirementBadgeScheme.vue'\nimport type { RequiredSecurity } from '@/features/Operation/helpers/get-required-security'\n\nconst { requiredSecurity, hideLabel = false } = defineProps<{\n requiredSecurity: RequiredSecurity\n hideLabel?: boolean\n}>()\nconst { translate } = useLocalization()\n\nconst label = computed(() =>\n requiredSecurity.state === 'required'\n ? translate('authentication.required')\n : translate('authentication.optional'),\n)\n\nconst verb = computed(() =>\n requiredSecurity.state === 'required'\n ? translate('authentication.requires')\n : translate('authentication.accepts'),\n)\n\n/** Single group, single scheme — shown inline in the header. */\nconst isSingleScheme = computed(\n () =>\n requiredSecurity.requirements.length === 1 &&\n requiredSecurity.requirements[0]?.schemes.length === 1,\n)\n\n/** Single group with multiple schemes — all must be satisfied (AND). */\nconst isAndGroup = computed(\n () =>\n requiredSecurity.requirements.length === 1 &&\n (requiredSecurity.requirements[0]?.schemes.length ?? 0) > 1,\n)\n\n/** Multiple groups — any one group satisfies authentication (OR). */\nconst isOrAlternatives = computed(\n () => requiredSecurity.requirements.length > 1,\n)\n</script>\n\n<template>\n <ScalarPopover\n v-if=\"requiredSecurity.state !== 'none'\"\n placement=\"bottom-end\">\n <button\n class=\"security-requirement-badge inline-flex w-fit shrink-0 items-center justify-center gap-1 text-sm\"\n :class=\"\n requiredSecurity.state === 'optional'\n ? 'text-c-2'\n : 'text-c-1 font-medium'\n \"\n type=\"button\"\n @click.stop>\n <ScalarIconLockSimple\n v-if=\"requiredSecurity.state === 'required'\"\n class=\"size-3\"\n weight=\"bold\" />\n <ScalarIconLockSimpleOpen\n v-else\n class=\"size-3\"\n weight=\"bold\" />\n <span v-if=\"!hideLabel\">{{ label }}</span>\n </button>\n <template #popover>\n <div class=\"flex max-w-xs min-w-48 flex-col gap-1.5 p-2 text-sm\">\n <div class=\"font-medium\">\n {{ verb }}\n <template v-if=\"isSingleScheme\">\n <SecurityRequirementBadgeScheme\n is=\"span\"\n class=\"contents\"\n :scheme=\"requiredSecurity.requirements[0]!.schemes[0]!\" />\n </template>\n <template v-else-if=\"isOrAlternatives\">\n {{ translate('authentication.oneOf') }}\n </template>\n <template v-else-if=\"isAndGroup\">\n {{ translate('authentication.allOf') }}\n </template>\n <template v-else>\n {{ translate('authentication.authentication') }}\n </template>\n </div>\n\n <!-- Multiple OR alternatives -->\n <ul\n v-if=\"isOrAlternatives\"\n class=\"contents\">\n <li\n v-for=\"(group, gi) in requiredSecurity.requirements\"\n :key=\"gi\"\n class=\"markdown\">\n <!-- Single scheme in this OR branch -->\n <SecurityRequirementBadgeScheme\n is=\"span\"\n v-if=\"group.schemes.length === 1\"\n class=\"contents\"\n :scheme=\"group.schemes[0]!\" />\n <!-- Multiple AND schemes in this OR branch -->\n <template v-else>\n <ul class=\"contents\">\n <SecurityRequirementBadgeScheme\n v-for=\"(scheme, si) in group.schemes\"\n :key=\"si\"\n :scheme />\n </ul>\n </template>\n </li>\n </ul>\n\n <!-- Single group, multiple AND schemes -->\n <ul\n v-else-if=\"isAndGroup\"\n class=\"contents\">\n <SecurityRequirementBadgeScheme\n v-for=\"(scheme, key) in requiredSecurity.requirements[0]!.schemes\"\n :key\n :scheme />\n </ul>\n </div>\n </template>\n </ScalarPopover>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"SecurityRequirementBadge.vue.js","names":[],"sources":["../../../../src/features/Operation/components/SecurityRequirementBadge.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarFloating,\n ScalarFloatingBackdrop,\n} from '@scalar/components/floating'\nimport { ScalarIconLockSimple, ScalarIconLockSimpleOpen } from '@scalar/icons'\nimport { onClickOutside, onKeyStroke } from '@vueuse/core'\nimport { computed, onBeforeUnmount, ref } from 'vue'\n\nimport { useLocalization } from '@/features/localization'\nimport SecurityRequirementBadgeScheme from '@/features/Operation/components/SecurityRequirementBadgeScheme.vue'\nimport type { RequiredSecurity } from '@/features/Operation/helpers/get-required-security'\n\nconst { requiredSecurity, hideLabel = false } = defineProps<{\n requiredSecurity: RequiredSecurity\n hideLabel?: boolean\n}>()\nconst { translate } = useLocalization()\n\n/**\n * The badge shows a small panel with the security details. It opens on hover\n * and on click, so we own the open state directly instead of leaning on a\n * click-only popover. Owning the state keeps the two interactions from fighting\n * each other: hover and the click of the same gesture (a tap fires both) can no\n * longer toggle each other off.\n */\nconst triggerRef = ref<HTMLButtonElement | null>(null)\nconst panelRef = ref<HTMLElement | null>(null)\nconst isOpen = ref(false)\n\n/**\n * Whether the panel is pinned open by a click. A pinned panel ignores the\n * pointer leaving so it behaves like the old click-to-open popover, and it only\n * closes on another click, a click outside, or Escape.\n */\nconst isPinned = ref(false)\nlet closeTimeout: ReturnType<typeof setTimeout> | undefined\n\n/**\n * Close after a short delay so the pointer can travel across the gap between the\n * badge and the panel without the panel disappearing. A pinned panel stays open.\n */\nconst scheduleClose = () => {\n if (isPinned.value) {\n return\n }\n clearTimeout(closeTimeout)\n closeTimeout = setTimeout(() => {\n isOpen.value = false\n }, 120)\n}\n\nconst cancelClose = () => clearTimeout(closeTimeout)\n\nconst openOnHover = () => {\n cancelClose()\n isOpen.value = true\n}\n\nconst close = () => {\n cancelClose()\n isOpen.value = false\n isPinned.value = false\n}\n\n/**\n * Toggle on click. A hover already opened the panel (and a tap's `mouseenter`\n * fires just before its `click`), so the first click pins it open rather than\n * closing it; a click on an already pinned panel closes it.\n */\nconst toggleOnClick = () => {\n if (isPinned.value) {\n close()\n return\n }\n cancelClose()\n isOpen.value = true\n isPinned.value = true\n}\n\nonClickOutside(triggerRef, close, { ignore: [panelRef] })\nonKeyStroke('Escape', () => {\n if (isOpen.value) {\n close()\n }\n})\n\nonBeforeUnmount(() => clearTimeout(closeTimeout))\n\nconst label = computed(() =>\n requiredSecurity.state === 'required'\n ? translate('authentication.required')\n : translate('authentication.optional'),\n)\n\nconst verb = computed(() =>\n requiredSecurity.state === 'required'\n ? translate('authentication.requires')\n : translate('authentication.accepts'),\n)\n\n/** Single group, single scheme — shown inline in the header. */\nconst isSingleScheme = computed(\n () =>\n requiredSecurity.requirements.length === 1 &&\n requiredSecurity.requirements[0]?.schemes.length === 1,\n)\n\n/** Single group with multiple schemes — all must be satisfied (AND). */\nconst isAndGroup = computed(\n () =>\n requiredSecurity.requirements.length === 1 &&\n (requiredSecurity.requirements[0]?.schemes.length ?? 0) > 1,\n)\n\n/** Multiple groups — any one group satisfies authentication (OR). */\nconst isOrAlternatives = computed(\n () => requiredSecurity.requirements.length > 1,\n)\n</script>\n\n<template>\n <ScalarFloating\n v-if=\"requiredSecurity.state !== 'none'\"\n placement=\"bottom-end\">\n <button\n ref=\"triggerRef\"\n class=\"security-requirement-badge inline-flex w-fit shrink-0 items-center justify-center gap-1 text-sm\"\n :class=\"\n requiredSecurity.state === 'optional'\n ? 'text-c-2'\n : 'text-c-1 font-medium'\n \"\n type=\"button\"\n :aria-expanded=\"isOpen\"\n aria-haspopup=\"dialog\"\n @click.stop=\"toggleOnClick\"\n @mouseenter=\"openOnHover\"\n @mouseleave=\"scheduleClose\">\n <ScalarIconLockSimple\n v-if=\"requiredSecurity.state === 'required'\"\n class=\"size-3\"\n weight=\"bold\" />\n <ScalarIconLockSimpleOpen\n v-else\n class=\"size-3\"\n weight=\"bold\" />\n <span v-if=\"!hideLabel\">{{ label }}</span>\n </button>\n <template #floating>\n <div\n v-if=\"isOpen\"\n ref=\"panelRef\"\n class=\"relative flex flex-col p-0.75\"\n @click.stop\n @mouseenter=\"cancelClose\"\n @mouseleave=\"scheduleClose\">\n <div class=\"flex max-w-xs min-w-48 flex-col gap-1.5 p-2 text-sm\">\n <div class=\"font-medium\">\n {{ verb }}\n <template v-if=\"isSingleScheme\">\n <SecurityRequirementBadgeScheme\n is=\"span\"\n class=\"contents\"\n :scheme=\"requiredSecurity.requirements[0]!.schemes[0]!\" />\n </template>\n <template v-else-if=\"isOrAlternatives\">\n {{ translate('authentication.oneOf') }}\n </template>\n <template v-else-if=\"isAndGroup\">\n {{ translate('authentication.allOf') }}\n </template>\n <template v-else>\n {{ translate('authentication.authentication') }}\n </template>\n </div>\n\n <!-- Multiple OR alternatives -->\n <ul\n v-if=\"isOrAlternatives\"\n class=\"contents\">\n <li\n v-for=\"(group, gi) in requiredSecurity.requirements\"\n :key=\"gi\"\n class=\"markdown\">\n <!-- Single scheme in this OR branch -->\n <SecurityRequirementBadgeScheme\n is=\"span\"\n v-if=\"group.schemes.length === 1\"\n class=\"contents\"\n :scheme=\"group.schemes[0]!\" />\n <!-- Multiple AND schemes in this OR branch -->\n <template v-else>\n <ul class=\"contents\">\n <SecurityRequirementBadgeScheme\n v-for=\"(scheme, si) in group.schemes\"\n :key=\"si\"\n :scheme />\n </ul>\n </template>\n </li>\n </ul>\n\n <!-- Single group, multiple AND schemes -->\n <ul\n v-else-if=\"isAndGroup\"\n class=\"contents\">\n <SecurityRequirementBadgeScheme\n v-for=\"(scheme, key) in requiredSecurity.requirements[0]!.schemes\"\n :key\n :scheme />\n </ul>\n </div>\n <ScalarFloatingBackdrop />\n </div>\n </template>\n </ScalarFloating>\n</template>\n"],"mappings":""}
@@ -1,21 +1,23 @@
1
1
  import { useLocalization } from "../../localization/use-localization.js";
2
2
  import SecurityRequirementBadgeScheme_default from "./SecurityRequirementBadgeScheme.vue.js";
3
- import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, defineComponent, normalizeClass, openBlock, renderList, toDisplayString, unref, withCtx, withModifiers } from "vue";
3
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, onBeforeUnmount, openBlock, ref, renderList, toDisplayString, unref, withCtx, withModifiers } from "vue";
4
+ import { onClickOutside, onKeyStroke } from "@vueuse/core";
4
5
  import { ScalarIconLockSimple, ScalarIconLockSimpleOpen } from "@scalar/icons";
5
- import { ScalarPopover } from "@scalar/components/popover";
6
+ import { ScalarFloating, ScalarFloatingBackdrop } from "@scalar/components/floating";
6
7
  //#region src/features/Operation/components/SecurityRequirementBadge.vue?vue&type=script&setup=true&lang.ts
7
- var _hoisted_1 = { key: 2 };
8
- var _hoisted_2 = { class: "flex max-w-xs min-w-48 flex-col gap-1.5 p-2 text-sm" };
9
- var _hoisted_3 = { class: "font-medium" };
10
- var _hoisted_4 = {
8
+ var _hoisted_1 = ["aria-expanded"];
9
+ var _hoisted_2 = { key: 2 };
10
+ var _hoisted_3 = { class: "flex max-w-xs min-w-48 flex-col gap-1.5 p-2 text-sm" };
11
+ var _hoisted_4 = { class: "font-medium" };
12
+ var _hoisted_5 = {
11
13
  key: 0,
12
14
  class: "contents"
13
15
  };
14
- var _hoisted_5 = {
16
+ var _hoisted_6 = {
15
17
  key: 1,
16
18
  class: "contents"
17
19
  };
18
- var _hoisted_6 = {
20
+ var _hoisted_7 = {
19
21
  key: 1,
20
22
  class: "contents"
21
23
  };
@@ -30,6 +32,63 @@ var SecurityRequirementBadge_vue_vue_type_script_setup_true_lang_default = /* @_
30
32
  },
31
33
  setup(__props) {
32
34
  const { translate } = useLocalization();
35
+ /**
36
+ * The badge shows a small panel with the security details. It opens on hover
37
+ * and on click, so we own the open state directly instead of leaning on a
38
+ * click-only popover. Owning the state keeps the two interactions from fighting
39
+ * each other: hover and the click of the same gesture (a tap fires both) can no
40
+ * longer toggle each other off.
41
+ */
42
+ const triggerRef = ref(null);
43
+ const panelRef = ref(null);
44
+ const isOpen = ref(false);
45
+ /**
46
+ * Whether the panel is pinned open by a click. A pinned panel ignores the
47
+ * pointer leaving so it behaves like the old click-to-open popover, and it only
48
+ * closes on another click, a click outside, or Escape.
49
+ */
50
+ const isPinned = ref(false);
51
+ let closeTimeout;
52
+ /**
53
+ * Close after a short delay so the pointer can travel across the gap between the
54
+ * badge and the panel without the panel disappearing. A pinned panel stays open.
55
+ */
56
+ const scheduleClose = () => {
57
+ if (isPinned.value) return;
58
+ clearTimeout(closeTimeout);
59
+ closeTimeout = setTimeout(() => {
60
+ isOpen.value = false;
61
+ }, 120);
62
+ };
63
+ const cancelClose = () => clearTimeout(closeTimeout);
64
+ const openOnHover = () => {
65
+ cancelClose();
66
+ isOpen.value = true;
67
+ };
68
+ const close = () => {
69
+ cancelClose();
70
+ isOpen.value = false;
71
+ isPinned.value = false;
72
+ };
73
+ /**
74
+ * Toggle on click. A hover already opened the panel (and a tap's `mouseenter`
75
+ * fires just before its `click`), so the first click pins it open rather than
76
+ * closing it; a click on an already pinned panel closes it.
77
+ */
78
+ const toggleOnClick = () => {
79
+ if (isPinned.value) {
80
+ close();
81
+ return;
82
+ }
83
+ cancelClose();
84
+ isOpen.value = true;
85
+ isPinned.value = true;
86
+ };
87
+ onClickOutside(triggerRef, close, { ignore: [panelRef] });
88
+ onKeyStroke("Escape", () => {
89
+ if (isOpen.value) close();
90
+ });
91
+ onBeforeUnmount(() => clearTimeout(closeTimeout));
33
92
  const label = computed(() => __props.requiredSecurity.state === "required" ? translate("authentication.required") : translate("authentication.optional"));
34
93
  const verb = computed(() => __props.requiredSecurity.state === "required" ? translate("authentication.requires") : translate("authentication.accepts"));
35
94
  /** Single group, single scheme — shown inline in the header. */
@@ -39,16 +98,24 @@ var SecurityRequirementBadge_vue_vue_type_script_setup_true_lang_default = /* @_
39
98
  /** Multiple groups — any one group satisfies authentication (OR). */
40
99
  const isOrAlternatives = computed(() => __props.requiredSecurity.requirements.length > 1);
41
100
  return (_ctx, _cache) => {
42
- return __props.requiredSecurity.state !== "none" ? (openBlock(), createBlock(unref(ScalarPopover), {
101
+ return __props.requiredSecurity.state !== "none" ? (openBlock(), createBlock(unref(ScalarFloating), {
43
102
  key: 0,
44
103
  placement: "bottom-end"
45
104
  }, {
46
- popover: withCtx(() => [createElementVNode("div", _hoisted_2, [createElementVNode("div", _hoisted_3, [createTextVNode(toDisplayString(verb.value) + " ", 1), isSingleScheme.value ? (openBlock(), createBlock(SecurityRequirementBadgeScheme_default, {
105
+ floating: withCtx(() => [isOpen.value ? (openBlock(), createElementBlock("div", {
106
+ key: 0,
107
+ ref_key: "panelRef",
108
+ ref: panelRef,
109
+ class: "relative flex flex-col p-0.75",
110
+ onClick: _cache[0] || (_cache[0] = withModifiers(() => {}, ["stop"])),
111
+ onMouseenter: cancelClose,
112
+ onMouseleave: scheduleClose
113
+ }, [createElementVNode("div", _hoisted_3, [createElementVNode("div", _hoisted_4, [createTextVNode(toDisplayString(verb.value) + " ", 1), isSingleScheme.value ? (openBlock(), createBlock(SecurityRequirementBadgeScheme_default, {
47
114
  key: 0,
48
115
  is: "span",
49
116
  class: "contents",
50
117
  scheme: __props.requiredSecurity.requirements[0].schemes[0]
51
- }, null, 8, ["scheme"])) : isOrAlternatives.value ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(unref(translate)("authentication.oneOf")), 1)], 64)) : isAndGroup.value ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [createTextVNode(toDisplayString(unref(translate)("authentication.allOf")), 1)], 64)) : (openBlock(), createElementBlock(Fragment, { key: 3 }, [createTextVNode(toDisplayString(unref(translate)("authentication.authentication")), 1)], 64))]), isOrAlternatives.value ? (openBlock(), createElementBlock("ul", _hoisted_4, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.requiredSecurity.requirements, (group, gi) => {
118
+ }, null, 8, ["scheme"])) : isOrAlternatives.value ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(unref(translate)("authentication.oneOf")), 1)], 64)) : isAndGroup.value ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [createTextVNode(toDisplayString(unref(translate)("authentication.allOf")), 1)], 64)) : (openBlock(), createElementBlock(Fragment, { key: 3 }, [createTextVNode(toDisplayString(unref(translate)("authentication.authentication")), 1)], 64))]), isOrAlternatives.value ? (openBlock(), createElementBlock("ul", _hoisted_5, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.requiredSecurity.requirements, (group, gi) => {
52
119
  return openBlock(), createElementBlock("li", {
53
120
  key: gi,
54
121
  class: "markdown"
@@ -57,22 +124,28 @@ var SecurityRequirementBadge_vue_vue_type_script_setup_true_lang_default = /* @_
57
124
  is: "span",
58
125
  class: "contents",
59
126
  scheme: group.schemes[0]
60
- }, null, 8, ["scheme"])) : (openBlock(), createElementBlock("ul", _hoisted_5, [(openBlock(true), createElementBlock(Fragment, null, renderList(group.schemes, (scheme, si) => {
127
+ }, null, 8, ["scheme"])) : (openBlock(), createElementBlock("ul", _hoisted_6, [(openBlock(true), createElementBlock(Fragment, null, renderList(group.schemes, (scheme, si) => {
61
128
  return openBlock(), createBlock(SecurityRequirementBadgeScheme_default, {
62
129
  key: si,
63
130
  scheme
64
131
  }, null, 8, ["scheme"]);
65
132
  }), 128))]))]);
66
- }), 128))])) : isAndGroup.value ? (openBlock(), createElementBlock("ul", _hoisted_6, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.requiredSecurity.requirements[0].schemes, (scheme, key) => {
133
+ }), 128))])) : isAndGroup.value ? (openBlock(), createElementBlock("ul", _hoisted_7, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.requiredSecurity.requirements[0].schemes, (scheme, key) => {
67
134
  return openBlock(), createBlock(SecurityRequirementBadgeScheme_default, {
68
135
  key,
69
136
  scheme
70
137
  }, null, 8, ["scheme"]);
71
- }), 128))])) : createCommentVNode("", true)])]),
138
+ }), 128))])) : createCommentVNode("", true)]), createVNode(unref(ScalarFloatingBackdrop))], 544)) : createCommentVNode("", true)]),
72
139
  default: withCtx(() => [createElementVNode("button", {
140
+ ref_key: "triggerRef",
141
+ ref: triggerRef,
73
142
  class: normalizeClass(["security-requirement-badge inline-flex w-fit shrink-0 items-center justify-center gap-1 text-sm", __props.requiredSecurity.state === "optional" ? "text-c-2" : "text-c-1 font-medium"]),
74
143
  type: "button",
75
- onClick: _cache[0] || (_cache[0] = withModifiers(() => {}, ["stop"]))
144
+ "aria-expanded": isOpen.value,
145
+ "aria-haspopup": "dialog",
146
+ onClick: withModifiers(toggleOnClick, ["stop"]),
147
+ onMouseenter: openOnHover,
148
+ onMouseleave: scheduleClose
76
149
  }, [__props.requiredSecurity.state === "required" ? (openBlock(), createBlock(unref(ScalarIconLockSimple), {
77
150
  key: 0,
78
151
  class: "size-3",
@@ -81,7 +154,7 @@ var SecurityRequirementBadge_vue_vue_type_script_setup_true_lang_default = /* @_
81
154
  key: 1,
82
155
  class: "size-3",
83
156
  weight: "bold"
84
- })), !__props.hideLabel ? (openBlock(), createElementBlock("span", _hoisted_1, toDisplayString(label.value), 1)) : createCommentVNode("", true)], 2)]),
157
+ })), !__props.hideLabel ? (openBlock(), createElementBlock("span", _hoisted_2, toDisplayString(label.value), 1)) : createCommentVNode("", true)], 42, _hoisted_1)]),
85
158
  _: 1
86
159
  })) : createCommentVNode("", true);
87
160
  };
@@ -1 +1 @@
1
- {"version":3,"file":"SecurityRequirementBadge.vue.script.js","names":[],"sources":["../../../../src/features/Operation/components/SecurityRequirementBadge.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarPopover } from '@scalar/components/popover'\nimport { ScalarIconLockSimple, ScalarIconLockSimpleOpen } from '@scalar/icons'\nimport { computed } from 'vue'\n\nimport { useLocalization } from '@/features/localization'\nimport SecurityRequirementBadgeScheme from '@/features/Operation/components/SecurityRequirementBadgeScheme.vue'\nimport type { RequiredSecurity } from '@/features/Operation/helpers/get-required-security'\n\nconst { requiredSecurity, hideLabel = false } = defineProps<{\n requiredSecurity: RequiredSecurity\n hideLabel?: boolean\n}>()\nconst { translate } = useLocalization()\n\nconst label = computed(() =>\n requiredSecurity.state === 'required'\n ? translate('authentication.required')\n : translate('authentication.optional'),\n)\n\nconst verb = computed(() =>\n requiredSecurity.state === 'required'\n ? translate('authentication.requires')\n : translate('authentication.accepts'),\n)\n\n/** Single group, single scheme — shown inline in the header. */\nconst isSingleScheme = computed(\n () =>\n requiredSecurity.requirements.length === 1 &&\n requiredSecurity.requirements[0]?.schemes.length === 1,\n)\n\n/** Single group with multiple schemes — all must be satisfied (AND). */\nconst isAndGroup = computed(\n () =>\n requiredSecurity.requirements.length === 1 &&\n (requiredSecurity.requirements[0]?.schemes.length ?? 0) > 1,\n)\n\n/** Multiple groups — any one group satisfies authentication (OR). */\nconst isOrAlternatives = computed(\n () => requiredSecurity.requirements.length > 1,\n)\n</script>\n\n<template>\n <ScalarPopover\n v-if=\"requiredSecurity.state !== 'none'\"\n placement=\"bottom-end\">\n <button\n class=\"security-requirement-badge inline-flex w-fit shrink-0 items-center justify-center gap-1 text-sm\"\n :class=\"\n requiredSecurity.state === 'optional'\n ? 'text-c-2'\n : 'text-c-1 font-medium'\n \"\n type=\"button\"\n @click.stop>\n <ScalarIconLockSimple\n v-if=\"requiredSecurity.state === 'required'\"\n class=\"size-3\"\n weight=\"bold\" />\n <ScalarIconLockSimpleOpen\n v-else\n class=\"size-3\"\n weight=\"bold\" />\n <span v-if=\"!hideLabel\">{{ label }}</span>\n </button>\n <template #popover>\n <div class=\"flex max-w-xs min-w-48 flex-col gap-1.5 p-2 text-sm\">\n <div class=\"font-medium\">\n {{ verb }}\n <template v-if=\"isSingleScheme\">\n <SecurityRequirementBadgeScheme\n is=\"span\"\n class=\"contents\"\n :scheme=\"requiredSecurity.requirements[0]!.schemes[0]!\" />\n </template>\n <template v-else-if=\"isOrAlternatives\">\n {{ translate('authentication.oneOf') }}\n </template>\n <template v-else-if=\"isAndGroup\">\n {{ translate('authentication.allOf') }}\n </template>\n <template v-else>\n {{ translate('authentication.authentication') }}\n </template>\n </div>\n\n <!-- Multiple OR alternatives -->\n <ul\n v-if=\"isOrAlternatives\"\n class=\"contents\">\n <li\n v-for=\"(group, gi) in requiredSecurity.requirements\"\n :key=\"gi\"\n class=\"markdown\">\n <!-- Single scheme in this OR branch -->\n <SecurityRequirementBadgeScheme\n is=\"span\"\n v-if=\"group.schemes.length === 1\"\n class=\"contents\"\n :scheme=\"group.schemes[0]!\" />\n <!-- Multiple AND schemes in this OR branch -->\n <template v-else>\n <ul class=\"contents\">\n <SecurityRequirementBadgeScheme\n v-for=\"(scheme, si) in group.schemes\"\n :key=\"si\"\n :scheme />\n </ul>\n </template>\n </li>\n </ul>\n\n <!-- Single group, multiple AND schemes -->\n <ul\n v-else-if=\"isAndGroup\"\n class=\"contents\">\n <SecurityRequirementBadgeScheme\n v-for=\"(scheme, key) in requiredSecurity.requirements[0]!.schemes\"\n :key\n :scheme />\n </ul>\n </div>\n </template>\n </ScalarPopover>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"SecurityRequirementBadge.vue.script.js","names":[],"sources":["../../../../src/features/Operation/components/SecurityRequirementBadge.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n ScalarFloating,\n ScalarFloatingBackdrop,\n} from '@scalar/components/floating'\nimport { ScalarIconLockSimple, ScalarIconLockSimpleOpen } from '@scalar/icons'\nimport { onClickOutside, onKeyStroke } from '@vueuse/core'\nimport { computed, onBeforeUnmount, ref } from 'vue'\n\nimport { useLocalization } from '@/features/localization'\nimport SecurityRequirementBadgeScheme from '@/features/Operation/components/SecurityRequirementBadgeScheme.vue'\nimport type { RequiredSecurity } from '@/features/Operation/helpers/get-required-security'\n\nconst { requiredSecurity, hideLabel = false } = defineProps<{\n requiredSecurity: RequiredSecurity\n hideLabel?: boolean\n}>()\nconst { translate } = useLocalization()\n\n/**\n * The badge shows a small panel with the security details. It opens on hover\n * and on click, so we own the open state directly instead of leaning on a\n * click-only popover. Owning the state keeps the two interactions from fighting\n * each other: hover and the click of the same gesture (a tap fires both) can no\n * longer toggle each other off.\n */\nconst triggerRef = ref<HTMLButtonElement | null>(null)\nconst panelRef = ref<HTMLElement | null>(null)\nconst isOpen = ref(false)\n\n/**\n * Whether the panel is pinned open by a click. A pinned panel ignores the\n * pointer leaving so it behaves like the old click-to-open popover, and it only\n * closes on another click, a click outside, or Escape.\n */\nconst isPinned = ref(false)\nlet closeTimeout: ReturnType<typeof setTimeout> | undefined\n\n/**\n * Close after a short delay so the pointer can travel across the gap between the\n * badge and the panel without the panel disappearing. A pinned panel stays open.\n */\nconst scheduleClose = () => {\n if (isPinned.value) {\n return\n }\n clearTimeout(closeTimeout)\n closeTimeout = setTimeout(() => {\n isOpen.value = false\n }, 120)\n}\n\nconst cancelClose = () => clearTimeout(closeTimeout)\n\nconst openOnHover = () => {\n cancelClose()\n isOpen.value = true\n}\n\nconst close = () => {\n cancelClose()\n isOpen.value = false\n isPinned.value = false\n}\n\n/**\n * Toggle on click. A hover already opened the panel (and a tap's `mouseenter`\n * fires just before its `click`), so the first click pins it open rather than\n * closing it; a click on an already pinned panel closes it.\n */\nconst toggleOnClick = () => {\n if (isPinned.value) {\n close()\n return\n }\n cancelClose()\n isOpen.value = true\n isPinned.value = true\n}\n\nonClickOutside(triggerRef, close, { ignore: [panelRef] })\nonKeyStroke('Escape', () => {\n if (isOpen.value) {\n close()\n }\n})\n\nonBeforeUnmount(() => clearTimeout(closeTimeout))\n\nconst label = computed(() =>\n requiredSecurity.state === 'required'\n ? translate('authentication.required')\n : translate('authentication.optional'),\n)\n\nconst verb = computed(() =>\n requiredSecurity.state === 'required'\n ? translate('authentication.requires')\n : translate('authentication.accepts'),\n)\n\n/** Single group, single scheme — shown inline in the header. */\nconst isSingleScheme = computed(\n () =>\n requiredSecurity.requirements.length === 1 &&\n requiredSecurity.requirements[0]?.schemes.length === 1,\n)\n\n/** Single group with multiple schemes — all must be satisfied (AND). */\nconst isAndGroup = computed(\n () =>\n requiredSecurity.requirements.length === 1 &&\n (requiredSecurity.requirements[0]?.schemes.length ?? 0) > 1,\n)\n\n/** Multiple groups — any one group satisfies authentication (OR). */\nconst isOrAlternatives = computed(\n () => requiredSecurity.requirements.length > 1,\n)\n</script>\n\n<template>\n <ScalarFloating\n v-if=\"requiredSecurity.state !== 'none'\"\n placement=\"bottom-end\">\n <button\n ref=\"triggerRef\"\n class=\"security-requirement-badge inline-flex w-fit shrink-0 items-center justify-center gap-1 text-sm\"\n :class=\"\n requiredSecurity.state === 'optional'\n ? 'text-c-2'\n : 'text-c-1 font-medium'\n \"\n type=\"button\"\n :aria-expanded=\"isOpen\"\n aria-haspopup=\"dialog\"\n @click.stop=\"toggleOnClick\"\n @mouseenter=\"openOnHover\"\n @mouseleave=\"scheduleClose\">\n <ScalarIconLockSimple\n v-if=\"requiredSecurity.state === 'required'\"\n class=\"size-3\"\n weight=\"bold\" />\n <ScalarIconLockSimpleOpen\n v-else\n class=\"size-3\"\n weight=\"bold\" />\n <span v-if=\"!hideLabel\">{{ label }}</span>\n </button>\n <template #floating>\n <div\n v-if=\"isOpen\"\n ref=\"panelRef\"\n class=\"relative flex flex-col p-0.75\"\n @click.stop\n @mouseenter=\"cancelClose\"\n @mouseleave=\"scheduleClose\">\n <div class=\"flex max-w-xs min-w-48 flex-col gap-1.5 p-2 text-sm\">\n <div class=\"font-medium\">\n {{ verb }}\n <template v-if=\"isSingleScheme\">\n <SecurityRequirementBadgeScheme\n is=\"span\"\n class=\"contents\"\n :scheme=\"requiredSecurity.requirements[0]!.schemes[0]!\" />\n </template>\n <template v-else-if=\"isOrAlternatives\">\n {{ translate('authentication.oneOf') }}\n </template>\n <template v-else-if=\"isAndGroup\">\n {{ translate('authentication.allOf') }}\n </template>\n <template v-else>\n {{ translate('authentication.authentication') }}\n </template>\n </div>\n\n <!-- Multiple OR alternatives -->\n <ul\n v-if=\"isOrAlternatives\"\n class=\"contents\">\n <li\n v-for=\"(group, gi) in requiredSecurity.requirements\"\n :key=\"gi\"\n class=\"markdown\">\n <!-- Single scheme in this OR branch -->\n <SecurityRequirementBadgeScheme\n is=\"span\"\n v-if=\"group.schemes.length === 1\"\n class=\"contents\"\n :scheme=\"group.schemes[0]!\" />\n <!-- Multiple AND schemes in this OR branch -->\n <template v-else>\n <ul class=\"contents\">\n <SecurityRequirementBadgeScheme\n v-for=\"(scheme, si) in group.schemes\"\n :key=\"si\"\n :scheme />\n </ul>\n </template>\n </li>\n </ul>\n\n <!-- Single group, multiple AND schemes -->\n <ul\n v-else-if=\"isAndGroup\"\n class=\"contents\">\n <SecurityRequirementBadgeScheme\n v-for=\"(scheme, key) in requiredSecurity.requirements[0]!.schemes\"\n :key\n :scheme />\n </ul>\n </div>\n <ScalarFloatingBackdrop />\n </div>\n </template>\n </ScalarFloating>\n</template>\n"],"mappings":"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"}
@@ -38,4 +38,17 @@ export type RequiredSecurity = {
38
38
  * appears — whether alongside real requirements or as the only entry — auth is treated as optional (state: 'optional').
39
39
  */
40
40
  export declare const getRequiredSecurity: (operation: Pick<OperationObject, "security"> | null | undefined, document: Pick<OpenApiDocument, "security" | "components">) => RequiredSecurity;
41
+ /**
42
+ * Required OAuth scopes grouped by security alternative (OR).
43
+ *
44
+ * Each returned array is the de-duplicated set of scopes for one alternative, kept in
45
+ * declaration order. Scopes are only collected for OAuth2 / OpenID Connect schemes, so
46
+ * alternatives without any scopes (for example API-key-only auth) are omitted and the
47
+ * result is empty when the operation requires no OAuth scopes.
48
+ *
49
+ * Grouping is preserved intentionally: unioning scopes across alternatives would imply
50
+ * that mutually exclusive scope sets are all required at once, which misstates OpenAPI
51
+ * OR semantics.
52
+ */
53
+ export declare const getRequiredScopeGroups: (requiredSecurity: RequiredSecurity) => string[][];
41
54
  //# sourceMappingURL=get-required-security.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"get-required-security.d.ts","sourceRoot":"","sources":["../../../../src/features/Operation/helpers/get-required-security.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8DAA8D,CAAA;AACnG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uDAAuD,CAAA;AAC5F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6DAA6D,CAAA;AAEvG,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,CAAA;AAEpE,MAAM,MAAM,sBAAsB,GAAG;IACnC,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAA;IACZ,kGAAkG;IAClG,MAAM,EAAE,oBAAoB,GAAG,SAAS,CAAA;IACxC,mGAAmG;IACnG,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,sBAAsB,EAAE,CAAA;CAClC,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,qBAAqB,CAAA;IAC5B;;;;;;;OAOG;IACH,YAAY,EAAE,qBAAqB,EAAE,CAAA;CACtC,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,GAC9B,WAAW,IAAI,CAAC,eAAe,EAAE,UAAU,CAAC,GAAG,IAAI,GAAG,SAAS,EAC/D,UAAU,IAAI,CAAC,eAAe,EAAE,UAAU,GAAG,YAAY,CAAC,KACzD,gBAgCF,CAAA"}
1
+ {"version":3,"file":"get-required-security.d.ts","sourceRoot":"","sources":["../../../../src/features/Operation/helpers/get-required-security.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8DAA8D,CAAA;AACnG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uDAAuD,CAAA;AAC5F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6DAA6D,CAAA;AAEvG,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,CAAA;AAEpE,MAAM,MAAM,sBAAsB,GAAG;IACnC,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAA;IACZ,kGAAkG;IAClG,MAAM,EAAE,oBAAoB,GAAG,SAAS,CAAA;IACxC,mGAAmG;IACnG,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,sBAAsB,EAAE,CAAA;CAClC,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,qBAAqB,CAAA;IAC5B;;;;;;;OAOG;IACH,YAAY,EAAE,qBAAqB,EAAE,CAAA;CACtC,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,GAC9B,WAAW,IAAI,CAAC,eAAe,EAAE,UAAU,CAAC,GAAG,IAAI,GAAG,SAAS,EAC/D,UAAU,IAAI,CAAC,eAAe,EAAE,UAAU,GAAG,YAAY,CAAC,KACzD,gBAgCF,CAAA;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,GAAI,kBAAkB,gBAAgB,KAAG,MAAM,EAAE,EAkBnF,CAAA"}
@@ -35,7 +35,28 @@ var getRequiredSecurity = (operation, document) => {
35
35
  requirements: groups
36
36
  };
37
37
  };
38
+ /**
39
+ * Required OAuth scopes grouped by security alternative (OR).
40
+ *
41
+ * Each returned array is the de-duplicated set of scopes for one alternative, kept in
42
+ * declaration order. Scopes are only collected for OAuth2 / OpenID Connect schemes, so
43
+ * alternatives without any scopes (for example API-key-only auth) are omitted and the
44
+ * result is empty when the operation requires no OAuth scopes.
45
+ *
46
+ * Grouping is preserved intentionally: unioning scopes across alternatives would imply
47
+ * that mutually exclusive scope sets are all required at once, which misstates OpenAPI
48
+ * OR semantics.
49
+ */
50
+ var getRequiredScopeGroups = (requiredSecurity) => {
51
+ const groups = [];
52
+ for (const group of requiredSecurity.requirements) {
53
+ const collected = /* @__PURE__ */ new Set();
54
+ for (const scheme of group.schemes) for (const scope of scheme.scopes) collected.add(scope);
55
+ if (collected.size > 0) groups.push([...collected]);
56
+ }
57
+ return groups;
58
+ };
38
59
  //#endregion
39
- export { getRequiredSecurity };
60
+ export { getRequiredScopeGroups, getRequiredSecurity };
40
61
 
41
62
  //# sourceMappingURL=get-required-security.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"get-required-security.js","names":[],"sources":["../../../../src/features/Operation/helpers/get-required-security.ts"],"sourcesContent":["import { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { isNonOptionalSecurityRequirement } from '@scalar/workspace-store/helpers/is-non-optional-security-requirement'\nimport type { OpenApiDocument } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport type { OperationObject } from '@scalar/workspace-store/schemas/v3.1/strict/operation'\nimport type { SecuritySchemeObject } from '@scalar/workspace-store/schemas/v3.1/strict/security-scheme'\n\nexport type RequiredSecurityState = 'required' | 'optional' | 'none'\n\nexport type RequiredSecurityScheme = {\n /** Scheme key as declared in `components.securitySchemes`. */\n name: string\n /** Resolved scheme object. `undefined` if the referenced scheme isn't defined on the document. */\n scheme: SecuritySchemeObject | undefined\n /** Scopes required by the operation for this scheme (OAuth2 / OpenID Connect). Empty otherwise. */\n scopes: string[]\n}\n\n/**\n * One alternative in the security requirement list.\n * All schemes within a group must be satisfied simultaneously (AND semantics).\n */\nexport type RequiredSecurityGroup = {\n schemes: RequiredSecurityScheme[]\n}\n\nexport type RequiredSecurity = {\n state: RequiredSecurityState\n /**\n * Each element is one alternative (OR semantics). Within each group, all schemes\n * must be satisfied simultaneously (AND semantics). Empty when `state === 'none'`.\n *\n * Mirrors the OpenAPI `security` array structure:\n * - outer array → OR (satisfy any one group)\n * - inner object → AND (all schemes in a group are required together)\n */\n requirements: RequiredSecurityGroup[]\n}\n\n/**\n * Determine whether an operation requires authentication, using `operation.security ?? document.security`\n * as the source of truth. Operation-level `security` fully overrides document-level — including `security: []`,\n * which explicitly opts the operation out of auth.\n *\n * OpenAPI encodes \"auth is optional\" by including an empty requirement object `{}`. Whenever `{}`\n * appears — whether alongside real requirements or as the only entry — auth is treated as optional (state: 'optional').\n */\nexport const getRequiredSecurity = (\n operation: Pick<OperationObject, 'security'> | null | undefined,\n document: Pick<OpenApiDocument, 'security' | 'components'>,\n): RequiredSecurity => {\n const securityList = operation?.security ?? document.security ?? []\n const definedSchemes = document.components?.securitySchemes ?? {}\n\n let hasEmpty = false\n const groups: RequiredSecurityGroup[] = []\n\n for (const requirement of securityList) {\n if (!isNonOptionalSecurityRequirement(requirement)) {\n hasEmpty = true\n continue\n }\n\n const schemes: RequiredSecurityScheme[] = Object.entries(requirement).map(([name, scopes]) => ({\n name,\n scheme: getResolvedRef(definedSchemes[name]),\n scopes: scopes.filter((s) => s.length > 0),\n }))\n\n if (schemes.length > 0) {\n groups.push({ schemes })\n }\n }\n\n if (groups.length === 0) {\n return { state: hasEmpty ? 'optional' : 'none', requirements: [] }\n }\n\n return {\n state: hasEmpty ? 'optional' : 'required',\n requirements: groups,\n }\n}\n"],"mappings":";;;;;;;;;;;AA8CA,IAAa,uBACX,WACA,aACqB;CACrB,MAAM,eAAe,WAAW,YAAY,SAAS,YAAY,EAAE;CACnE,MAAM,iBAAiB,SAAS,YAAY,mBAAmB,EAAE;CAEjE,IAAI,WAAW;CACf,MAAM,SAAkC,EAAE;AAE1C,MAAK,MAAM,eAAe,cAAc;AACtC,MAAI,CAAC,iCAAiC,YAAY,EAAE;AAClD,cAAW;AACX;;EAGF,MAAM,UAAoC,OAAO,QAAQ,YAAY,CAAC,KAAK,CAAC,MAAM,aAAa;GAC7F;GACA,QAAQ,eAAe,eAAe,MAAM;GAC5C,QAAQ,OAAO,QAAQ,MAAM,EAAE,SAAS,EAAE;GAC3C,EAAE;AAEH,MAAI,QAAQ,SAAS,EACnB,QAAO,KAAK,EAAE,SAAS,CAAC;;AAI5B,KAAI,OAAO,WAAW,EACpB,QAAO;EAAE,OAAO,WAAW,aAAa;EAAQ,cAAc,EAAE;EAAE;AAGpE,QAAO;EACL,OAAO,WAAW,aAAa;EAC/B,cAAc;EACf"}
1
+ {"version":3,"file":"get-required-security.js","names":[],"sources":["../../../../src/features/Operation/helpers/get-required-security.ts"],"sourcesContent":["import { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { isNonOptionalSecurityRequirement } from '@scalar/workspace-store/helpers/is-non-optional-security-requirement'\nimport type { OpenApiDocument } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport type { OperationObject } from '@scalar/workspace-store/schemas/v3.1/strict/operation'\nimport type { SecuritySchemeObject } from '@scalar/workspace-store/schemas/v3.1/strict/security-scheme'\n\nexport type RequiredSecurityState = 'required' | 'optional' | 'none'\n\nexport type RequiredSecurityScheme = {\n /** Scheme key as declared in `components.securitySchemes`. */\n name: string\n /** Resolved scheme object. `undefined` if the referenced scheme isn't defined on the document. */\n scheme: SecuritySchemeObject | undefined\n /** Scopes required by the operation for this scheme (OAuth2 / OpenID Connect). Empty otherwise. */\n scopes: string[]\n}\n\n/**\n * One alternative in the security requirement list.\n * All schemes within a group must be satisfied simultaneously (AND semantics).\n */\nexport type RequiredSecurityGroup = {\n schemes: RequiredSecurityScheme[]\n}\n\nexport type RequiredSecurity = {\n state: RequiredSecurityState\n /**\n * Each element is one alternative (OR semantics). Within each group, all schemes\n * must be satisfied simultaneously (AND semantics). Empty when `state === 'none'`.\n *\n * Mirrors the OpenAPI `security` array structure:\n * - outer array → OR (satisfy any one group)\n * - inner object → AND (all schemes in a group are required together)\n */\n requirements: RequiredSecurityGroup[]\n}\n\n/**\n * Determine whether an operation requires authentication, using `operation.security ?? document.security`\n * as the source of truth. Operation-level `security` fully overrides document-level — including `security: []`,\n * which explicitly opts the operation out of auth.\n *\n * OpenAPI encodes \"auth is optional\" by including an empty requirement object `{}`. Whenever `{}`\n * appears — whether alongside real requirements or as the only entry — auth is treated as optional (state: 'optional').\n */\nexport const getRequiredSecurity = (\n operation: Pick<OperationObject, 'security'> | null | undefined,\n document: Pick<OpenApiDocument, 'security' | 'components'>,\n): RequiredSecurity => {\n const securityList = operation?.security ?? document.security ?? []\n const definedSchemes = document.components?.securitySchemes ?? {}\n\n let hasEmpty = false\n const groups: RequiredSecurityGroup[] = []\n\n for (const requirement of securityList) {\n if (!isNonOptionalSecurityRequirement(requirement)) {\n hasEmpty = true\n continue\n }\n\n const schemes: RequiredSecurityScheme[] = Object.entries(requirement).map(([name, scopes]) => ({\n name,\n scheme: getResolvedRef(definedSchemes[name]),\n scopes: scopes.filter((s) => s.length > 0),\n }))\n\n if (schemes.length > 0) {\n groups.push({ schemes })\n }\n }\n\n if (groups.length === 0) {\n return { state: hasEmpty ? 'optional' : 'none', requirements: [] }\n }\n\n return {\n state: hasEmpty ? 'optional' : 'required',\n requirements: groups,\n }\n}\n\n/**\n * Required OAuth scopes grouped by security alternative (OR).\n *\n * Each returned array is the de-duplicated set of scopes for one alternative, kept in\n * declaration order. Scopes are only collected for OAuth2 / OpenID Connect schemes, so\n * alternatives without any scopes (for example API-key-only auth) are omitted and the\n * result is empty when the operation requires no OAuth scopes.\n *\n * Grouping is preserved intentionally: unioning scopes across alternatives would imply\n * that mutually exclusive scope sets are all required at once, which misstates OpenAPI\n * OR semantics.\n */\nexport const getRequiredScopeGroups = (requiredSecurity: RequiredSecurity): string[][] => {\n const groups: string[][] = []\n\n for (const group of requiredSecurity.requirements) {\n const collected = new Set<string>()\n\n for (const scheme of group.schemes) {\n for (const scope of scheme.scopes) {\n collected.add(scope)\n }\n }\n\n if (collected.size > 0) {\n groups.push([...collected])\n }\n }\n\n return groups\n}\n"],"mappings":";;;;;;;;;;;AA8CA,IAAa,uBACX,WACA,aACqB;CACrB,MAAM,eAAe,WAAW,YAAY,SAAS,YAAY,EAAE;CACnE,MAAM,iBAAiB,SAAS,YAAY,mBAAmB,EAAE;CAEjE,IAAI,WAAW;CACf,MAAM,SAAkC,EAAE;AAE1C,MAAK,MAAM,eAAe,cAAc;AACtC,MAAI,CAAC,iCAAiC,YAAY,EAAE;AAClD,cAAW;AACX;;EAGF,MAAM,UAAoC,OAAO,QAAQ,YAAY,CAAC,KAAK,CAAC,MAAM,aAAa;GAC7F;GACA,QAAQ,eAAe,eAAe,MAAM;GAC5C,QAAQ,OAAO,QAAQ,MAAM,EAAE,SAAS,EAAE;GAC3C,EAAE;AAEH,MAAI,QAAQ,SAAS,EACnB,QAAO,KAAK,EAAE,SAAS,CAAC;;AAI5B,KAAI,OAAO,WAAW,EACpB,QAAO;EAAE,OAAO,WAAW,aAAa;EAAQ,cAAc,EAAE;EAAE;AAGpE,QAAO;EACL,OAAO,WAAW,aAAa;EAC/B,cAAc;EACf;;;;;;;;;;;;;;AAeH,IAAa,0BAA0B,qBAAmD;CACxF,MAAM,SAAqB,EAAE;AAE7B,MAAK,MAAM,SAAS,iBAAiB,cAAc;EACjD,MAAM,4BAAY,IAAI,KAAa;AAEnC,OAAK,MAAM,UAAU,MAAM,QACzB,MAAK,MAAM,SAAS,OAAO,OACzB,WAAU,IAAI,MAAM;AAIxB,MAAI,UAAU,OAAO,EACnB,QAAO,KAAK,CAAC,GAAG,UAAU,CAAC;;AAI/B,QAAO"}
@@ -1,6 +1,6 @@
1
1
  import type { SecuritySchemeObjectSecret } from '@scalar/workspace-store/request-example';
2
2
  import type { OpenApiDocument, OperationObject, ServerObject } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document';
3
- import type { RequiredSecurity } from '../../../features/Operation/helpers/get-required-security.js';
3
+ import { type RequiredSecurity } from '../../../features/Operation/helpers/get-required-security.js';
4
4
  import type { OperationProps } from '../../../features/Operation/Operation.vue.js';
5
5
  type __VLS_Props = Omit<OperationProps, 'document' | 'pathValue' | 'server' | 'securitySchemes' | 'authStore'> & {
6
6
  /** Operation object with path params */
@@ -1 +1 @@
1
- {"version":3,"file":"ClassicLayout.vue.d.ts","sourceRoot":"","sources":["../../../../src/features/Operation/layouts/ClassicLayout.vue"],"names":[],"mappings":"AAsjBA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAA;AACzF,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,YAAY,EACb,MAAM,8DAA8D,CAAA;AAgBrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oDAAoD,CAAA;AAM1F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAA;AAUxE,KAAK,WAAW,GAAG,IAAI,CACnB,cAAc,EACd,UAAU,GAAG,WAAW,GAAG,QAAQ,GAAG,iBAAiB,GAAG,WAAW,CACtE,GAAG;IACF,wCAAwC;IACxC,SAAS,EAAE,eAAe,CAAA;IAC1B,4CAA4C;IAC5C,cAAc,EAAE,YAAY,GAAG,IAAI,CAAA;IACnC,sDAAsD;IACtD,uBAAuB,EAAE,0BAA0B,EAAE,CAAA;IACrD,sEAAsE;IACtE,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,eAAe,CAAA;CAC3B,CAAC;AAyrBJ,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
1
+ {"version":3,"file":"ClassicLayout.vue.d.ts","sourceRoot":"","sources":["../../../../src/features/Operation/layouts/ClassicLayout.vue"],"names":[],"mappings":"AAokBA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAA;AACzF,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,YAAY,EACb,MAAM,8DAA8D,CAAA;AAiBrE,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,oDAAoD,CAAA;AAM3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAA;AAUxE,KAAK,WAAW,GAAG,IAAI,CACnB,cAAc,EACd,UAAU,GAAG,WAAW,GAAG,QAAQ,GAAG,iBAAiB,GAAG,WAAW,CACtE,GAAG;IACF,wCAAwC;IACxC,SAAS,EAAE,eAAe,CAAA;IAC1B,4CAA4C;IAC5C,cAAc,EAAE,YAAY,GAAG,IAAI,CAAA;IACnC,sDAAsD;IACtD,uBAAuB,EAAE,0BAA0B,EAAE,CAAA;IACrD,sEAAsE;IACtE,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,eAAe,CAAA;CAC3B,CAAC;AA6sBJ,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
@@ -2,7 +2,7 @@ import _plugin_vue_export_helper_default from "../../../_virtual/_plugin-vue_exp
2
2
  import ClassicLayout_vue_vue_type_script_setup_true_lang_default from "./ClassicLayout.vue.script.js";
3
3
  /* empty css */
4
4
  //#region src/features/Operation/layouts/ClassicLayout.vue
5
- var ClassicLayout_default = /* @__PURE__ */ _plugin_vue_export_helper_default(ClassicLayout_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-9d937e58"]]);
5
+ var ClassicLayout_default = /* @__PURE__ */ _plugin_vue_export_helper_default(ClassicLayout_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-ae829610"]]);
6
6
  //#endregion
7
7
  export { ClassicLayout_default as default };
8
8
 
@@ -1 +1 @@
1
- {"version":3,"file":"ClassicLayout.vue.js","names":[],"sources":["../../../../src/features/Operation/layouts/ClassicLayout.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { CodeExample } from '@scalar/blocks/code-example'\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarMarkdown } from '@scalar/components/markdown'\nimport {\n ScalarIconCopy,\n ScalarIconPlay,\n ScalarIconWebhooksLogo,\n} from '@scalar/icons'\nimport { useClipboard } from '@scalar/use-hooks/useClipboard'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport type { SecuritySchemeObjectSecret } from '@scalar/workspace-store/request-example'\nimport type {\n OpenApiDocument,\n OperationObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, provide, ref } from 'vue'\n\nimport { Anchor } from '@/components/Anchor'\nimport { Badge } from '@/components/Badge'\nimport { HttpMethod } from '@/components/HttpMethod'\nimport { LinkList } from '@/components/LinkList'\nimport OperationPath from '@/components/OperationPath.vue'\nimport { SectionAccordion } from '@/components/Section'\nimport { ExampleResponses } from '@/features/example-responses'\nimport { ExternalDocs } from '@/features/external-docs'\nimport { useLocalization } from '@/features/localization'\nimport Callbacks from '@/features/Operation/components/callbacks/Callbacks.vue'\nimport OperationParameters from '@/features/Operation/components/OperationParameters.vue'\nimport OperationResponses from '@/features/Operation/components/OperationResponses.vue'\nimport SecurityRequirementBadge from '@/features/Operation/components/SecurityRequirementBadge.vue'\nimport type { RequiredSecurity } from '@/features/Operation/helpers/get-required-security'\nimport {\n getOperationStability,\n getOperationStabilityColor,\n isOperationDeprecated,\n} from '@/features/Operation/helpers/operation-stability'\nimport type { OperationProps } from '@/features/Operation/Operation.vue'\nimport {\n REQUEST_BODY_COMPOSITION_INDEX_SYMBOL,\n type RequestBodyCompositionSelection,\n} from '@/features/Operation/request-body-composition-index'\nimport { getXKeysFromObject } from '@/features/specification-extension'\nimport SpecificationExtension from '@/features/specification-extension/SpecificationExtension.vue'\nimport { TestRequestButton } from '@/features/test-request-button'\nimport { XBadges } from '@/features/x-badges'\n\nconst {\n clientOptions,\n document,\n eventBus,\n isWebhook,\n method,\n operation,\n options,\n path,\n requiredSecurity,\n selectedServer,\n selectedSecuritySchemes,\n selectedClient,\n selectedExample,\n} = defineProps<\n Omit<\n OperationProps,\n 'document' | 'pathValue' | 'server' | 'securitySchemes' | 'authStore'\n > & {\n /** Operation object with path params */\n operation: OperationObject\n /** The selected server for the operation */\n selectedServer: ServerObject | null\n /** The selected security schemes for the operation */\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n /** Required/optional security state for the badge next to the path */\n requiredSecurity: RequiredSecurity\n /** The document the operation belongs to, used to resolve schema references for display */\n document?: OpenApiDocument\n }\n>()\nconst { translate } = useLocalization()\n\nconst operationTitle = computed(() => operation.summary || path || '')\nconst operationExtensions = computed(() => getXKeysFromObject(operation))\n\n/** Track the selected request body content type so the code sample stays in sync */\nconst selectedRequestBodyContentType = ref<string | undefined>()\n\n/**\n * The example key actually shown in the request snippet for this operation.\n *\n * The test-request button lives in the accordion header, outside `OperationCodeSample`, so it\n * cannot read the resolved key from the footer slot like the modern layout does. We mirror it here\n * so the button opens the client with the same example the snippet displays, even when this\n * operation does not share the document-wide selection.\n */\nconst resolvedExampleKey = ref<string>('')\n\n/** Selected request body oneOf/anyOf variants; synced with schema dropdowns and code sample */\nconst requestBodyCompositionSelection = ref<RequestBodyCompositionSelection>({})\n\nconst requestBodyCompositionSelectionForCodeSample = computed(\n (): RequestBodyCompositionSelection => ({\n ...requestBodyCompositionSelection.value,\n }),\n)\n\nconst requestBodyCompositionSelectionKey = computed(() =>\n JSON.stringify(requestBodyCompositionSelectionForCodeSample.value),\n)\n\nprovide(REQUEST_BODY_COMPOSITION_INDEX_SYMBOL, requestBodyCompositionSelection)\n\nconst { copyToClipboard } = useClipboard()\n</script>\n<template>\n <SectionAccordion\n :id=\"id\"\n :aria-label=\"operationTitle\"\n class=\"reference-endpoint\"\n :modelValue=\"!isCollapsed\"\n transparent\n @update:modelValue=\"\n (value) => eventBus?.emit('toggle:nav-item', { id, open: value })\n \">\n <template #title>\n <div class=\"operation-title\">\n <div class=\"operation-details\">\n <HttpMethod\n class=\"endpoint-type\"\n :method=\"method\"\n short />\n <Anchor\n class=\"endpoint-anchor\"\n @copyAnchorUrl=\"() => eventBus?.emit('copy-url:nav-item', { id })\">\n <h3 class=\"endpoint-label\">\n <div class=\"endpoint-label-path\">\n <OperationPath\n :deprecated=\"isOperationDeprecated(operation)\"\n :path=\"path\" />\n </div>\n <div class=\"endpoint-label-name\">\n {{ operationTitle }}\n </div>\n <!-- Stability badge -->\n <Badge\n v-if=\"getOperationStability(operation)\"\n class=\"capitalize\"\n :class=\"getOperationStabilityColor(operation)\">\n {{ getOperationStability(operation) }}\n </Badge>\n\n <!-- Webhook badge -->\n <Badge\n v-if=\"isWebhook\"\n class=\"font-code text-green flex w-fit items-center justify-center gap-1\">\n <ScalarIconWebhooksLogo weight=\"bold\" />\n {{ translate('operation.webhook') }}\n </Badge>\n\n <!-- x-badges before -->\n <XBadges\n :badges=\"operation['x-badges']\"\n position=\"before\" />\n </h3>\n </Anchor>\n </div>\n </div>\n </template>\n <template #actions=\"{ active }\">\n <!-- Required auth indicator -->\n <SecurityRequirementBadge\n hideLabel\n :requiredSecurity />\n <!-- x-badges after -->\n <XBadges\n :badges=\"operation['x-badges']\"\n position=\"after\" />\n <template v-if=\"!options.hideTestRequestButton\">\n <TestRequestButton\n v-if=\"active && !isWebhook\"\n :id\n :eventBus\n :exampleName=\"resolvedExampleKey\"\n :method\n :path\n :requestBodyCompositionSelection=\"\n requestBodyCompositionSelectionForCodeSample\n \" />\n <ScalarIconPlay\n v-else\n class=\"endpoint-try-hint size-4.5\" />\n </template>\n <span\n v-if=\"options.showOperationId && operation.operationId\"\n class=\"font-code text-sm\">\n {{ operation.operationId }}\n </span>\n <ScalarIconButton\n class=\"endpoint-copy p-0.5\"\n :icon=\"ScalarIconCopy\"\n :label=\"translate('actions.copyEndpointUrl')\"\n size=\"xs\"\n variant=\"ghost\"\n @click.stop=\"copyToClipboard(path)\" />\n </template>\n <template\n v-if=\"operation.description\"\n #description>\n <ScalarMarkdown\n :anchorPrefix=\"id\"\n :aria-label=\"translate('common.description')\"\n role=\"group\"\n transformType=\"heading\"\n :value=\"operation.description\"\n withAnchors\n withImages />\n </template>\n <div class=\"endpoint-content\">\n <div class=\"operation-details-card\">\n <div\n v-if=\"Object.keys(operationExtensions).length > 0\"\n class=\"operation-details-card-item\">\n <SpecificationExtension :value=\"operationExtensions\" />\n </div>\n <div class=\"operation-details-card-item\">\n <OperationParameters\n v-model:selectedContentType=\"selectedRequestBodyContentType\"\n :document\n :eventBus\n :options\n :parameters=\"operation.parameters\"\n :requestBody=\"getResolvedRef(operation.requestBody)\" />\n </div>\n <div class=\"operation-details-card-item\">\n <OperationResponses\n :document\n :eventBus\n :options\n :responses=\"operation.responses\" />\n </div>\n\n <!-- Callbacks -->\n <div\n v-if=\"operation?.callbacks\"\n class=\"operation-details-card-item\">\n <Callbacks\n :callbacks=\"operation.callbacks\"\n :document\n :eventBus\n :options\n :path />\n </div>\n </div>\n\n <ExampleResponses\n v-if=\"operation.responses\"\n class=\"operation-example-card\"\n :eventBus\n :responses=\"operation.responses\"\n :selectedExample />\n\n <!-- New Example Request -->\n <div>\n <!-- External Docs -->\n <LinkList v-if=\"operation.externalDocs\">\n <ExternalDocs :value=\"operation.externalDocs\" />\n </LinkList>\n <!-- Request Example -->\n <ScalarErrorBoundary>\n <CodeExample\n :key=\"requestBodyCompositionSelectionKey\"\n class=\"operation-example-card\"\n :clientOptions\n :eventBus\n fallback\n :isWebhook\n :method\n :operation\n :path\n :requestBodyCompositionSelection=\"\n requestBodyCompositionSelectionForCodeSample\n \"\n :securitySchemes=\"selectedSecuritySchemes\"\n :selectedClient\n :selectedContentType=\"selectedRequestBodyContentType\"\n :selectedExample\n :selectedServer\n @update:exampleKey=\"resolvedExampleKey = $event\" />\n </ScalarErrorBoundary>\n </div>\n </div>\n </SectionAccordion>\n</template>\n\n<style scoped>\n@reference \"@/style.css\";\n\n.operation-title {\n display: flex;\n justify-content: space-between;\n}\n.operation-details {\n display: flex;\n align-items: center;\n margin-top: 0;\n gap: 9px;\n\n min-width: 0;\n flex-shrink: 1;\n}\n.operation-details :deep(.endpoint-anchor .scalar-button svg) {\n width: 16px;\n height: 16px;\n}\n.endpoint-type {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n\n position: relative;\n z-index: 0;\n\n width: 60px;\n padding: 6px;\n flex-shrink: 0;\n\n font-size: var(--scalar-small);\n\n text-transform: uppercase;\n font-weight: var(--scalar-bold);\n font-family: var(--scalar-font);\n}\n.endpoint-type::after {\n content: '';\n position: absolute;\n inset: 0;\n z-index: -1;\n\n background: currentColor;\n opacity: 0.15;\n\n border-radius: var(--scalar-radius);\n}\n\n.endpoint-anchor {\n display: flex;\n align-items: center;\n min-width: 0;\n flex-shrink: 1;\n}\n.endpoint-anchor.label {\n display: flex;\n}\n.endpoint-label {\n display: flex;\n align-items: baseline;\n gap: 9px;\n\n min-width: 0;\n flex-shrink: 1;\n\n color: var(--scalar-color-1);\n}\n\n.endpoint-label-path {\n font-family: var(--scalar-font-code);\n font-size: var(--scalar-mini);\n\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n}\n.endpoint-label-path :deep(em) {\n color: var(--scalar-color-2);\n}\n.endpoint-label-name {\n color: var(--scalar-color-2);\n font-size: var(--scalar-small);\n\n /* Concatenate the name before we shrink the path */\n flex-shrink: 1000000000;\n\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.endpoint-try-hint {\n padding: 2px;\n flex-shrink: 0;\n}\n.endpoint-copy {\n color: currentColor;\n}\n.endpoint-copy :deep(svg) {\n stroke-width: 2px;\n}\n\n.endpoint-content {\n display: grid;\n grid-auto-columns: 1fr;\n grid-auto-flow: row;\n gap: 9px;\n padding: 9px;\n}\n\n@variant lg {\n .endpoint-content {\n grid-auto-flow: column;\n }\n}\n\n@container (max-width: 900px) {\n .endpoint-content {\n grid-template-columns: 1fr;\n }\n}\n\n.endpoint-content > * {\n min-width: 0;\n}\n\n.operation-details-card {\n display: flex;\n flex-direction: column;\n gap: 12px;\n min-width: 0;\n}\n.operation-details-card-item :deep(.parameter-list),\n.operation-details-card-item :deep(.callbacks-list) {\n border: var(--scalar-border-width) solid var(--scalar-border-color);\n border-radius: var(--scalar-radius-lg);\n margin-top: 0;\n}\n\n.operation-details-card-item {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.operation-details-card-item :deep(.parameter-list-items) {\n margin-bottom: 0;\n}\n.operation-details-card :deep(.parameter-item:last-of-type .parameter-schema) {\n padding-bottom: 12px;\n}\n.operation-details-card :deep(.parameter-list .parameter-list) {\n margin-bottom: 12px;\n}\n.operation-details-card :deep(.parameter-item) {\n margin: 0;\n padding: 0;\n}\n.operation-details-card :deep(.property) {\n padding: 9px;\n margin: 0;\n}\n.operation-details-card :deep(.parameter-list-title),\n.operation-details-card :deep(.request-body-title),\n.operation-details-card :deep(.callbacks-title) {\n text-transform: uppercase;\n font-weight: var(--scalar-bold);\n font-size: var(--scalar-mini);\n color: var(--scalar-color-2);\n line-height: 1.33;\n padding: 9px;\n margin: 0;\n}\n\n.operation-details-card :deep(.callback-list-item-title) {\n padding-left: 28px;\n padding-right: 12px;\n}\n\n.operation-details-card :deep(.callback-list-item-icon) {\n left: 6px;\n}\n\n.operation-details-card :deep(.callback-operation-container) {\n padding-inline: 9px;\n padding-bottom: 9px;\n}\n\n.operation-details-card :deep(.callback-operation-container > .request-body),\n.operation-details-card :deep(.callback-operation-container > .parameter-list) {\n border: none;\n}\n\n.operation-details-card\n :deep(.callback-operation-container > .request-body > .request-body-header) {\n padding: 0;\n padding-bottom: 9px;\n border-bottom: var(--scalar-border-width) solid var(--scalar-border-color);\n}\n\n.operation-details-card :deep(.request-body-description) {\n margin-top: 0;\n padding: 9px 9px 0 9px;\n border-top: var(--scalar-border-width) solid var(--scalar-border-color);\n}\n\n.operation-details-card :deep(.request-body) {\n margin-top: 0;\n border-radius: var(--scalar-radius-lg);\n border: var(--scalar-border-width) solid var(--scalar-border-color);\n}\n.operation-details-card\n :deep(.request-body .schema-card--level-0 > .schema-card-description) {\n padding-inline: 9px;\n}\n\n.operation-details-card :deep(.request-body-header) {\n padding-bottom: 0;\n border-bottom: 0;\n}\n\n.operation-details-card :deep(.contents button) {\n margin-right: 9px;\n}\n\n.operation-details-card\n :deep(.schema-card--open + .schema-card:not(.schema-card--open)) {\n margin-inline: 9px;\n margin-bottom: 9px;\n}\n.operation-details-card :deep(.request-body-schema .property--level-0) {\n padding: 0;\n}\n.operation-details-card :deep(.request-body-schema .property--level-0) {\n padding: 0;\n}\n\n.operation-details-card :deep(.selected-content-type) {\n margin-right: 9px;\n}\n\n.operation-example-card {\n position: sticky;\n top: calc(var(--refs-viewport-offset) + 24px);\n max-height: calc(var(--refs-viewport-height) - 48px);\n}\n\n@media (max-width: 600px) {\n .operation-example-card {\n max-height: unset;\n position: static;\n }\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"ClassicLayout.vue.js","names":[],"sources":["../../../../src/features/Operation/layouts/ClassicLayout.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { CodeExample } from '@scalar/blocks/code-example'\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarMarkdown } from '@scalar/components/markdown'\nimport {\n ScalarIconCopy,\n ScalarIconPlay,\n ScalarIconWebhooksLogo,\n} from '@scalar/icons'\nimport { useClipboard } from '@scalar/use-hooks/useClipboard'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport type { SecuritySchemeObjectSecret } from '@scalar/workspace-store/request-example'\nimport type {\n OpenApiDocument,\n OperationObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, provide, ref } from 'vue'\n\nimport { Anchor } from '@/components/Anchor'\nimport { Badge } from '@/components/Badge'\nimport { HttpMethod } from '@/components/HttpMethod'\nimport { LinkList } from '@/components/LinkList'\nimport OperationPath from '@/components/OperationPath.vue'\nimport { SectionAccordion } from '@/components/Section'\nimport { ExampleResponses } from '@/features/example-responses'\nimport { ExternalDocs } from '@/features/external-docs'\nimport { useLocalization } from '@/features/localization'\nimport Callbacks from '@/features/Operation/components/callbacks/Callbacks.vue'\nimport OperationParameters from '@/features/Operation/components/OperationParameters.vue'\nimport OperationResponses from '@/features/Operation/components/OperationResponses.vue'\nimport OperationScopes from '@/features/Operation/components/OperationScopes.vue'\nimport SecurityRequirementBadge from '@/features/Operation/components/SecurityRequirementBadge.vue'\nimport {\n getRequiredScopeGroups,\n type RequiredSecurity,\n} from '@/features/Operation/helpers/get-required-security'\nimport {\n getOperationStability,\n getOperationStabilityColor,\n isOperationDeprecated,\n} from '@/features/Operation/helpers/operation-stability'\nimport type { OperationProps } from '@/features/Operation/Operation.vue'\nimport {\n REQUEST_BODY_COMPOSITION_INDEX_SYMBOL,\n type RequestBodyCompositionSelection,\n} from '@/features/Operation/request-body-composition-index'\nimport { getXKeysFromObject } from '@/features/specification-extension'\nimport SpecificationExtension from '@/features/specification-extension/SpecificationExtension.vue'\nimport { TestRequestButton } from '@/features/test-request-button'\nimport { XBadges } from '@/features/x-badges'\n\nconst {\n clientOptions,\n document,\n eventBus,\n isWebhook,\n method,\n operation,\n options,\n path,\n requiredSecurity,\n selectedServer,\n selectedSecuritySchemes,\n selectedClient,\n selectedExample,\n} = defineProps<\n Omit<\n OperationProps,\n 'document' | 'pathValue' | 'server' | 'securitySchemes' | 'authStore'\n > & {\n /** Operation object with path params */\n operation: OperationObject\n /** The selected server for the operation */\n selectedServer: ServerObject | null\n /** The selected security schemes for the operation */\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n /** Required/optional security state for the badge next to the path */\n requiredSecurity: RequiredSecurity\n /** The document the operation belongs to, used to resolve schema references for display */\n document?: OpenApiDocument\n }\n>()\nconst { translate } = useLocalization()\n\nconst operationTitle = computed(() => operation.summary || path || '')\nconst operationExtensions = computed(() => getXKeysFromObject(operation))\n\n/** Whether the operation requires any OAuth scopes, used to skip the empty card item. */\nconst hasRequiredScopes = computed(\n () => getRequiredScopeGroups(requiredSecurity).length > 0,\n)\n\n/** Track the selected request body content type so the code sample stays in sync */\nconst selectedRequestBodyContentType = ref<string | undefined>()\n\n/**\n * The example key actually shown in the request snippet for this operation.\n *\n * The test-request button lives in the accordion header, outside `OperationCodeSample`, so it\n * cannot read the resolved key from the footer slot like the modern layout does. We mirror it here\n * so the button opens the client with the same example the snippet displays, even when this\n * operation does not share the document-wide selection.\n */\nconst resolvedExampleKey = ref<string>('')\n\n/** Selected request body oneOf/anyOf variants; synced with schema dropdowns and code sample */\nconst requestBodyCompositionSelection = ref<RequestBodyCompositionSelection>({})\n\nconst requestBodyCompositionSelectionForCodeSample = computed(\n (): RequestBodyCompositionSelection => ({\n ...requestBodyCompositionSelection.value,\n }),\n)\n\nconst requestBodyCompositionSelectionKey = computed(() =>\n JSON.stringify(requestBodyCompositionSelectionForCodeSample.value),\n)\n\nprovide(REQUEST_BODY_COMPOSITION_INDEX_SYMBOL, requestBodyCompositionSelection)\n\nconst { copyToClipboard } = useClipboard()\n</script>\n<template>\n <SectionAccordion\n :id=\"id\"\n :aria-label=\"operationTitle\"\n class=\"reference-endpoint\"\n :modelValue=\"!isCollapsed\"\n transparent\n @update:modelValue=\"\n (value) => eventBus?.emit('toggle:nav-item', { id, open: value })\n \">\n <template #title>\n <div class=\"operation-title\">\n <div class=\"operation-details\">\n <HttpMethod\n class=\"endpoint-type\"\n :method=\"method\"\n short />\n <Anchor\n class=\"endpoint-anchor\"\n @copyAnchorUrl=\"() => eventBus?.emit('copy-url:nav-item', { id })\">\n <h3 class=\"endpoint-label\">\n <div class=\"endpoint-label-path\">\n <OperationPath\n :deprecated=\"isOperationDeprecated(operation)\"\n :path=\"path\" />\n </div>\n <div class=\"endpoint-label-name\">\n {{ operationTitle }}\n </div>\n <!-- Stability badge -->\n <Badge\n v-if=\"getOperationStability(operation)\"\n class=\"capitalize\"\n :class=\"getOperationStabilityColor(operation)\">\n {{ getOperationStability(operation) }}\n </Badge>\n\n <!-- Webhook badge -->\n <Badge\n v-if=\"isWebhook\"\n class=\"font-code text-green flex w-fit items-center justify-center gap-1\">\n <ScalarIconWebhooksLogo weight=\"bold\" />\n {{ translate('operation.webhook') }}\n </Badge>\n\n <!-- x-badges before -->\n <XBadges\n :badges=\"operation['x-badges']\"\n position=\"before\" />\n </h3>\n </Anchor>\n </div>\n </div>\n </template>\n <template #actions=\"{ active }\">\n <!-- Required auth indicator -->\n <SecurityRequirementBadge\n hideLabel\n :requiredSecurity />\n <!-- x-badges after -->\n <XBadges\n :badges=\"operation['x-badges']\"\n position=\"after\" />\n <template v-if=\"!options.hideTestRequestButton\">\n <TestRequestButton\n v-if=\"active && !isWebhook\"\n :id\n :eventBus\n :exampleName=\"resolvedExampleKey\"\n :method\n :path\n :requestBodyCompositionSelection=\"\n requestBodyCompositionSelectionForCodeSample\n \" />\n <ScalarIconPlay\n v-else\n class=\"endpoint-try-hint size-4.5\" />\n </template>\n <span\n v-if=\"options.showOperationId && operation.operationId\"\n class=\"font-code text-sm\">\n {{ operation.operationId }}\n </span>\n <ScalarIconButton\n class=\"endpoint-copy p-0.5\"\n :icon=\"ScalarIconCopy\"\n :label=\"translate('actions.copyEndpointUrl')\"\n size=\"xs\"\n variant=\"ghost\"\n @click.stop=\"copyToClipboard(path)\" />\n </template>\n <template\n v-if=\"operation.description\"\n #description>\n <ScalarMarkdown\n :anchorPrefix=\"id\"\n :aria-label=\"translate('common.description')\"\n role=\"group\"\n transformType=\"heading\"\n :value=\"operation.description\"\n withAnchors\n withImages />\n </template>\n <div class=\"endpoint-content\">\n <div class=\"operation-details-card\">\n <div\n v-if=\"Object.keys(operationExtensions).length > 0\"\n class=\"operation-details-card-item\">\n <SpecificationExtension :value=\"operationExtensions\" />\n </div>\n <div\n v-if=\"hasRequiredScopes\"\n class=\"operation-details-card-item\">\n <OperationScopes :requiredSecurity />\n </div>\n <div class=\"operation-details-card-item\">\n <OperationParameters\n v-model:selectedContentType=\"selectedRequestBodyContentType\"\n :document\n :eventBus\n :options\n :parameters=\"operation.parameters\"\n :requestBody=\"getResolvedRef(operation.requestBody)\" />\n </div>\n <div class=\"operation-details-card-item\">\n <OperationResponses\n :document\n :eventBus\n :options\n :responses=\"operation.responses\" />\n </div>\n\n <!-- Callbacks -->\n <div\n v-if=\"operation?.callbacks\"\n class=\"operation-details-card-item\">\n <Callbacks\n :callbacks=\"operation.callbacks\"\n :document\n :eventBus\n :options\n :path />\n </div>\n </div>\n\n <ExampleResponses\n v-if=\"operation.responses\"\n class=\"operation-example-card\"\n :eventBus\n :responses=\"operation.responses\"\n :selectedExample />\n\n <!-- New Example Request -->\n <div>\n <!-- External Docs -->\n <LinkList v-if=\"operation.externalDocs\">\n <ExternalDocs :value=\"operation.externalDocs\" />\n </LinkList>\n <!-- Request Example -->\n <ScalarErrorBoundary>\n <CodeExample\n :key=\"requestBodyCompositionSelectionKey\"\n class=\"operation-example-card\"\n :clientOptions\n :eventBus\n fallback\n :isWebhook\n :method\n :operation\n :path\n :requestBodyCompositionSelection=\"\n requestBodyCompositionSelectionForCodeSample\n \"\n :securitySchemes=\"selectedSecuritySchemes\"\n :selectedClient\n :selectedContentType=\"selectedRequestBodyContentType\"\n :selectedExample\n :selectedServer\n @update:exampleKey=\"resolvedExampleKey = $event\" />\n </ScalarErrorBoundary>\n </div>\n </div>\n </SectionAccordion>\n</template>\n\n<style scoped>\n@reference \"@/style.css\";\n\n.operation-title {\n display: flex;\n justify-content: space-between;\n}\n.operation-details {\n display: flex;\n align-items: center;\n margin-top: 0;\n gap: 9px;\n\n min-width: 0;\n flex-shrink: 1;\n}\n.operation-details :deep(.endpoint-anchor .scalar-button svg) {\n width: 16px;\n height: 16px;\n}\n.endpoint-type {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n\n position: relative;\n z-index: 0;\n\n width: 60px;\n padding: 6px;\n flex-shrink: 0;\n\n font-size: var(--scalar-small);\n\n text-transform: uppercase;\n font-weight: var(--scalar-bold);\n font-family: var(--scalar-font);\n}\n.endpoint-type::after {\n content: '';\n position: absolute;\n inset: 0;\n z-index: -1;\n\n background: currentColor;\n opacity: 0.15;\n\n border-radius: var(--scalar-radius);\n}\n\n.endpoint-anchor {\n display: flex;\n align-items: center;\n min-width: 0;\n flex-shrink: 1;\n}\n.endpoint-anchor.label {\n display: flex;\n}\n.endpoint-label {\n display: flex;\n align-items: baseline;\n gap: 9px;\n\n min-width: 0;\n flex-shrink: 1;\n\n color: var(--scalar-color-1);\n}\n\n.endpoint-label-path {\n font-family: var(--scalar-font-code);\n font-size: var(--scalar-mini);\n\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n}\n.endpoint-label-path :deep(em) {\n color: var(--scalar-color-2);\n}\n.endpoint-label-name {\n color: var(--scalar-color-2);\n font-size: var(--scalar-small);\n\n /* Concatenate the name before we shrink the path */\n flex-shrink: 1000000000;\n\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.endpoint-try-hint {\n padding: 2px;\n flex-shrink: 0;\n}\n.endpoint-copy {\n color: currentColor;\n}\n.endpoint-copy :deep(svg) {\n stroke-width: 2px;\n}\n\n.endpoint-content {\n display: grid;\n grid-auto-columns: 1fr;\n grid-auto-flow: row;\n gap: 9px;\n padding: 9px;\n}\n\n@variant lg {\n .endpoint-content {\n grid-auto-flow: column;\n }\n}\n\n@container (max-width: 900px) {\n .endpoint-content {\n grid-template-columns: 1fr;\n }\n}\n\n.endpoint-content > * {\n min-width: 0;\n}\n\n.operation-details-card {\n display: flex;\n flex-direction: column;\n gap: 12px;\n min-width: 0;\n}\n.operation-details-card-item :deep(.parameter-list),\n.operation-details-card-item :deep(.callbacks-list) {\n border: var(--scalar-border-width) solid var(--scalar-border-color);\n border-radius: var(--scalar-radius-lg);\n margin-top: 0;\n}\n\n.operation-details-card-item {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.operation-details-card-item :deep(.parameter-list-items) {\n margin-bottom: 0;\n}\n.operation-details-card :deep(.parameter-item:last-of-type .parameter-schema) {\n padding-bottom: 12px;\n}\n.operation-details-card :deep(.parameter-list .parameter-list) {\n margin-bottom: 12px;\n}\n.operation-details-card :deep(.parameter-item) {\n margin: 0;\n padding: 0;\n}\n.operation-details-card :deep(.property) {\n padding: 9px;\n margin: 0;\n}\n.operation-details-card :deep(.parameter-list-title),\n.operation-details-card :deep(.request-body-title),\n.operation-details-card :deep(.callbacks-title) {\n text-transform: uppercase;\n font-weight: var(--scalar-bold);\n font-size: var(--scalar-mini);\n color: var(--scalar-color-2);\n line-height: 1.33;\n padding: 9px;\n margin: 0;\n}\n\n.operation-details-card :deep(.callback-list-item-title) {\n padding-left: 28px;\n padding-right: 12px;\n}\n\n.operation-details-card :deep(.callback-list-item-icon) {\n left: 6px;\n}\n\n.operation-details-card :deep(.callback-operation-container) {\n padding-inline: 9px;\n padding-bottom: 9px;\n}\n\n.operation-details-card :deep(.callback-operation-container > .request-body),\n.operation-details-card :deep(.callback-operation-container > .parameter-list) {\n border: none;\n}\n\n.operation-details-card\n :deep(.callback-operation-container > .request-body > .request-body-header) {\n padding: 0;\n padding-bottom: 9px;\n border-bottom: var(--scalar-border-width) solid var(--scalar-border-color);\n}\n\n.operation-details-card :deep(.request-body-description) {\n margin-top: 0;\n padding: 9px 9px 0 9px;\n border-top: var(--scalar-border-width) solid var(--scalar-border-color);\n}\n\n.operation-details-card :deep(.request-body) {\n margin-top: 0;\n border-radius: var(--scalar-radius-lg);\n border: var(--scalar-border-width) solid var(--scalar-border-color);\n}\n.operation-details-card\n :deep(.request-body .schema-card--level-0 > .schema-card-description) {\n padding-inline: 9px;\n}\n\n.operation-details-card :deep(.request-body-header) {\n padding-bottom: 0;\n border-bottom: 0;\n}\n\n.operation-details-card :deep(.contents button) {\n margin-right: 9px;\n}\n\n.operation-details-card\n :deep(.schema-card--open + .schema-card:not(.schema-card--open)) {\n margin-inline: 9px;\n margin-bottom: 9px;\n}\n.operation-details-card :deep(.request-body-schema .property--level-0) {\n padding: 0;\n}\n.operation-details-card :deep(.request-body-schema .property--level-0) {\n padding: 0;\n}\n\n.operation-details-card :deep(.selected-content-type) {\n margin-right: 9px;\n}\n\n.operation-example-card {\n position: sticky;\n top: calc(var(--refs-viewport-offset) + 24px);\n max-height: calc(var(--refs-viewport-height) - 48px);\n}\n\n@media (max-width: 600px) {\n .operation-example-card {\n max-height: unset;\n position: static;\n }\n}\n</style>\n"],"mappings":""}