@scalar/api-client 3.19.2 → 3.19.3

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 (46) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/style.css +26 -26
  3. package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts +8 -1
  4. package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts.map +1 -1
  5. package/dist/v2/blocks/operation-block/OperationBlock.vue.js.map +1 -1
  6. package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js +38 -3
  7. package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js.map +1 -1
  8. package/dist/v2/blocks/operation-block/components/Header.vue.d.ts +2 -0
  9. package/dist/v2/blocks/operation-block/components/Header.vue.d.ts.map +1 -1
  10. package/dist/v2/blocks/operation-block/components/Header.vue.js +1 -1
  11. package/dist/v2/blocks/operation-block/components/Header.vue.js.map +1 -1
  12. package/dist/v2/blocks/operation-block/components/Header.vue.script.js +5 -2
  13. package/dist/v2/blocks/operation-block/components/Header.vue.script.js.map +1 -1
  14. package/dist/v2/blocks/request-block/helpers/create-parameter-rows.d.ts.map +1 -1
  15. package/dist/v2/blocks/request-block/helpers/create-parameter-rows.js +1 -1
  16. package/dist/v2/blocks/request-block/helpers/create-parameter-rows.js.map +1 -1
  17. package/dist/v2/blocks/response-block/ResponseBlock.vue.d.ts +2 -0
  18. package/dist/v2/blocks/response-block/ResponseBlock.vue.d.ts.map +1 -1
  19. package/dist/v2/blocks/response-block/ResponseBlock.vue.js +1 -1
  20. package/dist/v2/blocks/response-block/ResponseBlock.vue.js.map +1 -1
  21. package/dist/v2/blocks/response-block/ResponseBlock.vue.script.js +3 -0
  22. package/dist/v2/blocks/response-block/ResponseBlock.vue.script.js.map +1 -1
  23. package/dist/v2/blocks/response-block/components/ResponseEmpty.vue.d.ts +2 -0
  24. package/dist/v2/blocks/response-block/components/ResponseEmpty.vue.d.ts.map +1 -1
  25. package/dist/v2/blocks/response-block/components/ResponseEmpty.vue.js +1 -1
  26. package/dist/v2/blocks/response-block/components/ResponseEmpty.vue.js.map +1 -1
  27. package/dist/v2/blocks/response-block/components/ResponseEmpty.vue.script.js +4 -1
  28. package/dist/v2/blocks/response-block/components/ResponseEmpty.vue.script.js.map +1 -1
  29. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.d.ts +2 -0
  30. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.d.ts.map +1 -1
  31. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.js +1 -1
  32. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.js.map +1 -1
  33. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.script.js +3 -2
  34. package/dist/v2/blocks/scalar-address-bar-block/components/AddressBar.vue.script.js.map +1 -1
  35. package/dist/v2/constants.js +1 -1
  36. package/dist/v2/features/modal/Modal.vue.d.ts.map +1 -1
  37. package/dist/v2/features/modal/Modal.vue.js.map +1 -1
  38. package/dist/v2/features/modal/Modal.vue.script.js +2 -0
  39. package/dist/v2/features/modal/Modal.vue.script.js.map +1 -1
  40. package/dist/v2/features/operation/Operation.vue.d.ts +2 -0
  41. package/dist/v2/features/operation/Operation.vue.d.ts.map +1 -1
  42. package/dist/v2/features/operation/Operation.vue.js.map +1 -1
  43. package/dist/v2/features/operation/Operation.vue.script.js +29 -7
  44. package/dist/v2/features/operation/Operation.vue.script.js.map +1 -1
  45. package/dist/vue-styles.css +26 -26
  46. package/package.json +8 -8
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @scalar/api-client
2
2
 
3
+ ## 3.19.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#10255](https://github.com/scalar/scalar/pull/10255): fix(api-client): auto-enable optional header/query/cookie rows that have a pre-populated value
8
+
9
+ Optional parameters (headers, query params, cookies) start disabled by default. When the API
10
+ description provides a default or enum value for such a parameter (e.g. `x-scenario-id` with an enum),
11
+ the row was rendered with its checkbox unchecked even though a value was already selected — so the
12
+ parameter was silently dropped from every request until the user manually checked it.
13
+
14
+ The fix auto-enables any row that is only disabled by default (no explicit `x-disabled: true`) and
15
+ already carries a non-empty value, mirroring the existing behaviour when a user types a value into
16
+ a previously-empty row.
17
+
18
+ Use the same enablement rules for the parameter editor, outgoing requests, and generated code snippets.
19
+
20
+ - [#10240](https://github.com/scalar/scalar/pull/10240): Load external examples on demand when their selected preview is visible or Test Request opens, instead of downloading every payload while loading the API description. Share and cache downloads, preserve relative URL origins, and show loading and retry states while preventing incomplete requests from being sent.
21
+
3
22
  ## 3.19.2
4
23
 
5
24
  ## 3.19.1
package/dist/style.css CHANGED
@@ -6563,7 +6563,7 @@ input[data-v-a6f4752a]::placeholder {
6563
6563
  flex-grow: 1;
6564
6564
  }
6565
6565
 
6566
- .scalar-version-number[data-v-0895623d] {
6566
+ .scalar-version-number[data-v-1c2fb5fe] {
6567
6567
  transform: skew(0deg, 13deg);
6568
6568
  width: 76px;
6569
6569
  height: 76px;
@@ -6583,7 +6583,7 @@ input[data-v-a6f4752a]::placeholder {
6583
6583
  text-transform: initial;
6584
6584
  text-decoration-color: var(--scalar-color-3);
6585
6585
  }
6586
- .scalar-version-number a[data-v-0895623d] {
6586
+ .scalar-version-number a[data-v-1c2fb5fe] {
6587
6587
  font-weight: bold;
6588
6588
  font-weight: bold;
6589
6589
  background: var(--scalar-background-2);
@@ -6592,7 +6592,7 @@ input[data-v-a6f4752a]::placeholder {
6592
6592
  text-decoration: none;
6593
6593
  border: 0.5px solid var(--scalar-border-color);
6594
6594
  }
6595
- .gitbook-show[data-v-0895623d] {
6595
+ .gitbook-show[data-v-1c2fb5fe] {
6596
6596
  display: none;
6597
6597
  }
6598
6598
 
@@ -6603,11 +6603,11 @@ input[data-v-a6f4752a]::placeholder {
6603
6603
  opacity: 0;
6604
6604
  }
6605
6605
 
6606
- .animate-response-heading .response-heading[data-v-b969ac76] {
6607
- animation: push-response-b969ac76 0.2s ease-in-out forwards;
6606
+ .animate-response-heading .response-heading[data-v-e6c572c3] {
6607
+ animation: push-response-e6c572c3 0.2s ease-in-out forwards;
6608
6608
  opacity: 1;
6609
6609
  }
6610
- @keyframes push-response-b969ac76 {
6610
+ @keyframes push-response-e6c572c3 {
6611
6611
  from {
6612
6612
  opacity: 1;
6613
6613
  transform: translateY(0);
@@ -6617,11 +6617,11 @@ to {
6617
6617
  transform: translateY(-4px);
6618
6618
  }
6619
6619
  }
6620
- .animate-response-heading .animate-response-children[data-v-b969ac76] {
6621
- animation: response-spans-b969ac76 0.2s ease-in-out forwards 0.05s;
6620
+ .animate-response-heading .animate-response-children[data-v-e6c572c3] {
6621
+ animation: response-spans-e6c572c3 0.2s ease-in-out forwards 0.05s;
6622
6622
  opacity: 0;
6623
6623
  }
6624
- @keyframes response-spans-b969ac76 {
6624
+ @keyframes response-spans-e6c572c3 {
6625
6625
  from {
6626
6626
  opacity: 0;
6627
6627
  transform: translateY(4px);
@@ -6649,21 +6649,21 @@ to {
6649
6649
  background: var(--scalar-background-2);
6650
6650
  }
6651
6651
 
6652
- [data-v-1f68de05] .cm-editor {
6652
+ [data-v-3f5b6752] .cm-editor {
6653
6653
  height: 100%;
6654
6654
  outline: none;
6655
6655
  width: 100%;
6656
6656
  }
6657
- [data-v-1f68de05] .cm-line {
6657
+ [data-v-3f5b6752] .cm-line {
6658
6658
  padding: 0;
6659
6659
  }
6660
- [data-v-1f68de05] .cm-content {
6660
+ [data-v-3f5b6752] .cm-content {
6661
6661
  padding: 0;
6662
6662
  display: flex;
6663
6663
  align-items: center;
6664
6664
  font-size: var(--scalar-small);
6665
6665
  }
6666
- .scroll-timeline-x[data-v-1f68de05] {
6666
+ .scroll-timeline-x[data-v-3f5b6752] {
6667
6667
  -ms-overflow-style: none;
6668
6668
  /* Fade the URL at the viewport edges. Mask lives on the scrollport (this
6669
6669
  element) rather than on `.cm-scroller`, whose width follows the URL's
@@ -6676,31 +6676,31 @@ to {
6676
6676
  transparent 100%
6677
6677
  );
6678
6678
  }
6679
- .scroll-timeline-x-hidden[data-v-1f68de05] {
6679
+ .scroll-timeline-x-hidden[data-v-3f5b6752] {
6680
6680
  overflow-x: auto;
6681
6681
  }
6682
- .scroll-timeline-x-hidden[data-v-1f68de05] .cm-scroller {
6682
+ .scroll-timeline-x-hidden[data-v-3f5b6752] .cm-scroller {
6683
6683
  scrollbar-width: none;
6684
6684
  -ms-overflow-style: none;
6685
6685
  padding-right: 20px;
6686
6686
  overflow: auto;
6687
6687
  }
6688
- .scroll-timeline-x-hidden[data-v-1f68de05]::-webkit-scrollbar {
6688
+ .scroll-timeline-x-hidden[data-v-3f5b6752]::-webkit-scrollbar {
6689
6689
  width: 0;
6690
6690
  height: 0;
6691
6691
  display: none;
6692
6692
  }
6693
- .scroll-timeline-x-hidden[data-v-1f68de05] .cm-scroller::-webkit-scrollbar {
6693
+ .scroll-timeline-x-hidden[data-v-3f5b6752] .cm-scroller::-webkit-scrollbar {
6694
6694
  width: 0;
6695
6695
  height: 0;
6696
6696
  display: none;
6697
6697
  }
6698
- .scroll-timeline-x-address[data-v-1f68de05] {
6698
+ .scroll-timeline-x-address[data-v-3f5b6752] {
6699
6699
  line-height: 27px;
6700
6700
  scrollbar-width: none; /* Firefox */
6701
6701
  }
6702
6702
  /* make clickable are to left of send button */
6703
- .scroll-timeline-x-address[data-v-1f68de05]:after {
6703
+ .scroll-timeline-x-address[data-v-3f5b6752]:after {
6704
6704
  content: '';
6705
6705
  position: absolute;
6706
6706
  height: 100%;
@@ -6708,12 +6708,12 @@ to {
6708
6708
  right: 0;
6709
6709
  cursor: text;
6710
6710
  }
6711
- .scroll-timeline-x-address[data-v-1f68de05]:empty:before {
6711
+ .scroll-timeline-x-address[data-v-3f5b6752]:empty:before {
6712
6712
  content: 'Enter URL or cURL request';
6713
6713
  color: var(--scalar-color-3);
6714
6714
  pointer-events: none;
6715
6715
  }
6716
- .address-bar-bg-states[data-v-1f68de05] {
6716
+ .address-bar-bg-states[data-v-3f5b6752] {
6717
6717
  --scalar-address-bar-bg: color-mix(
6718
6718
  in srgb,
6719
6719
  var(--scalar-background-1),
@@ -6721,22 +6721,22 @@ to {
6721
6721
  );
6722
6722
  background: var(--scalar-address-bar-bg);
6723
6723
  }
6724
- .address-bar-bg-states[data-v-1f68de05]:has(.cm-focused) {
6724
+ .address-bar-bg-states[data-v-3f5b6752]:has(.cm-focused) {
6725
6725
  --scalar-address-bar-bg: var(--scalar-background-1);
6726
6726
  border-color: var(--scalar-border-color);
6727
6727
  outline-width: 1px;
6728
6728
  outline-style: solid;
6729
6729
  }
6730
- .address-bar-bg-states:has(.cm-focused) .fade-left[data-v-1f68de05],
6731
- .address-bar-bg-states:has(.cm-focused) .fade-right[data-v-1f68de05] {
6730
+ .address-bar-bg-states:has(.cm-focused) .fade-left[data-v-3f5b6752],
6731
+ .address-bar-bg-states:has(.cm-focused) .fade-right[data-v-3f5b6752] {
6732
6732
  --scalar-address-bar-bg: var(--scalar-background-1);
6733
6733
  }
6734
6734
 
6735
- .app-exit-button[data-v-821957c1] {
6735
+ .app-exit-button[data-v-57d0a8d2] {
6736
6736
  color: white;
6737
6737
  background: rgba(0, 0, 0, 0.1);
6738
6738
  }
6739
- .app-exit-button[data-v-821957c1]:hover {
6739
+ .app-exit-button[data-v-57d0a8d2]:hover {
6740
6740
  background: rgba(255, 255, 255, 0.1);
6741
6741
  }
6742
6742
  /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
@@ -28,6 +28,9 @@ import type { ClientLayout } from '../../../v2/types/layout';
28
28
  declare const _default: typeof __VLS_export;
29
29
  export default _default;
30
30
  export type OperationBlockProps = {
31
+ /** Keep execution and editing unavailable until the selected payload is ready. */
32
+ externalExamplesPending?: boolean;
33
+ externalExamplesFailed?: boolean;
31
34
  /** Event bus */
32
35
  eventBus: WorkspaceEventBus;
33
36
  /** Application version */
@@ -99,5 +102,9 @@ export type OperationBlockProps = {
99
102
  /** Subset of config options for the modal */
100
103
  options?: ModalProps['options'];
101
104
  };
102
- declare const __VLS_export: import("vue").DefineComponent<OperationBlockProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<OperationBlockProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
105
+ declare const __VLS_export: import("vue").DefineComponent<OperationBlockProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
106
+ "retry:externalExamples": () => any;
107
+ }, string, import("vue").PublicProps, Readonly<OperationBlockProps> & Readonly<{
108
+ "onRetry:externalExamples"?: (() => any) | undefined;
109
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
103
110
  //# sourceMappingURL=OperationBlock.vue.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"OperationBlock.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/blocks/operation-block/OperationBlock.vue"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"OperationBlock.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/blocks/operation-block/OperationBlock.vue"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"OperationBlock.vue.js","names":[],"sources":["../../../../src/v2/blocks/operation-block/OperationBlock.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * OperationBlock\n *\n * Orchestrates the operation view by wiring together the Header, OperationBlock,\n * and ResponseBlock. Forwards user interactions to the workspace event bus and\n * passes through configuration such as auth, servers, plugins, and environment.\n * This component keeps the Operation page lean by centralizing event emission\n * and prop wiring between the blocks.\n *\n * Notable behavior:\n * - Uses operation['x-scalar-method'] and operation['x-scalar-path'] to provide\n * draft overrides for the UI when present.\n */\nexport default {\n name: 'OperationBlock',\n}\n\nexport type OperationBlockProps = {\n /** Event bus */\n eventBus: WorkspaceEventBus\n /** Application version */\n appVersion: string\n /** Openapi document */\n document: OpenApiDocument\n /** Openapi document slug */\n documentSlug: string\n /** Workspace cookies */\n workspaceCookies: XScalarCookie[]\n /** Document cookies */\n documentCookies: XScalarCookie[]\n /** Current request path */\n path: string\n /** Current request method */\n method: HttpMethodType\n /** Whether `path` identifies an OpenAPI webhook. */\n isWebhook?: boolean\n /** HTTP clients */\n httpClients: AvailableClients\n /** The history for the operation */\n history?: HistoryEntry[]\n /** Client layout */\n layout: ClientLayout\n /** Currently selected server */\n server: ServerObject | null\n /** Currently selected client */\n selectedClient: WorkspaceStore['workspace']['x-scalar-default-client']\n /** Server list available for operation/document */\n servers: ServerObject[]\n /** Meta information for the server */\n serverMeta: ServerMeta\n /** Hides the client button on the header */\n hideClientButton?: boolean\n /** Client integration */\n integration?: string | null\n /** Openapi document url for `modal` mode to open the client app */\n documentUrl?: string\n /** Client source */\n source?: 'gitbook' | 'api-reference'\n /** Operation object */\n operation: OperationObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Meta information for the auth update */\n authMeta: AuthMeta\n /** Document defined security schemes */\n securitySchemes: MergedSecuritySchemes\n /** Client plugins */\n plugins: ClientPlugin[]\n /** Environment list */\n environments?: string[]\n /** Currently selected environment */\n activeEnvironment?: string\n /** For environment variables in the inputs */\n environment: XScalarEnvironment\n /** The proxy URL for sending requests */\n proxyUrl: string\n /** Currently selected security */\n selectedSecurity: SelectedSecurity\n /** Currently selected security schemes */\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n /** Security requirements */\n securityRequirements: OpenApiDocument['security']\n /** Default headers */\n defaultHeaders: Record<string, string>\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n /** Subset of config options for the modal */\n options?: ModalProps['options']\n}\n</script>\n<script setup lang=\"ts\">\nimport { generateClientOptions } from '@scalar/blocks/code-example'\nimport { ERRORS } from '@scalar/helpers/errors/normalize-error'\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport { buildSafeBodyRequest } from '@scalar/helpers/http/can-method-have-body'\nimport type { HttpMethod as HttpMethodType } from '@scalar/helpers/http/http-methods'\nimport {\n executeHook,\n executeResponseHook,\n type ClientPlugin,\n} from '@scalar/oas-utils/helpers'\nimport {\n AVAILABLE_CLIENTS,\n type AvailableClients,\n} from '@scalar/types/snippetz'\nimport { useClipboard } from '@scalar/use-hooks/useClipboard'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type { HistoryEntry } from '@scalar/workspace-store/entities/history/schema'\nimport type {\n AuthMeta,\n ServerMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n buildRequest,\n createVariablesStoreForRequest,\n getEnvironmentVariables,\n requestFactory,\n resolveExecutableRequestUrl,\n type MergedSecuritySchemes,\n type RequestPayload,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OpenApiDocument,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport type { OperationObject } from '@scalar/workspace-store/schemas/v3.2/strict/operation'\nimport { computed, onBeforeUnmount, onMounted, ref, toValue, watch } from 'vue'\n\nimport ViewLayout from '@/components/ViewLayout/ViewLayout.vue'\nimport ViewLayoutContent from '@/components/ViewLayout/ViewLayoutContent.vue'\nimport { harToFetchRequest } from '@/v2/blocks/operation-block/helpers/har-to-fetch-request'\nimport { harToFetchResponse } from '@/v2/blocks/operation-block/helpers/har-to-fetch-response'\nimport {\n getCookieRequestUrl,\n getResponseCookieActions,\n} from '@/v2/blocks/operation-block/helpers/persist-response-cookies'\nimport { getEnvironmentPersistenceActions } from '@/v2/blocks/operation-block/helpers/persist-script-environment'\nimport {\n getOperationExampleKey,\n isStreamingResponse,\n responseCache,\n} from '@/v2/blocks/operation-block/helpers/response-cache'\nimport {\n sendRequest,\n type ResponseInstance,\n} from '@/v2/blocks/operation-block/helpers/send-request'\nimport { validatePathParameters } from '@/v2/blocks/operation-block/helpers/validate-path-parameters'\nimport { RequestBlock } from '@/v2/blocks/request-block'\nimport { ResponseBlock } from '@/v2/blocks/response-block'\nimport { type History } from '@/v2/blocks/scalar-address-bar-block'\nimport type { ModalProps } from '@/v2/features/modal/Modal.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport Header from './components/Header.vue'\n\nconst {\n authMeta,\n environment,\n eventBus,\n exampleKey,\n document,\n documentSlug,\n workspaceCookies = [],\n documentCookies = [],\n hideClientButton,\n httpClients = AVAILABLE_CLIENTS,\n history = [],\n layout,\n method,\n isWebhook = false,\n operation,\n path,\n plugins = [],\n proxyUrl,\n requestBodyCompositionSelection,\n securitySchemes,\n selectedClient,\n server,\n servers,\n environments,\n options,\n activeEnvironment,\n serverMeta,\n selectedSecurity,\n selectedSecuritySchemes,\n securityRequirements,\n defaultHeaders,\n} = defineProps<OperationBlockProps>()\n\n/** Hoist up client generation so it doesn't get re-generated on every operation */\nconst clientOptions = computed(() => generateClientOptions(httpClients))\n\nconst { toast } = useToasts()\nconst { copyToClipboard } = useClipboard()\n\n// Refs\nconst abortController = ref<AbortController | null>(null)\nconst response = ref<ResponseInstance | null>(null)\nconst requestPayload = ref<RequestPayload | null>(null)\n\n/**\n * A webhook has no OpenAPI server, so its destination is the full URL the user\n * enters at runtime. The field holds that whole URL (not a server-relative path),\n * and the request is sent to it directly with no separate server base.\n */\nconst webhookUrl = ref('')\n\nwatch(\n [() => path, () => method, () => isWebhook],\n () => {\n webhookUrl.value = ''\n },\n { immediate: true },\n)\n\nconst requestPath = computed(() => (isWebhook ? webhookUrl.value : path))\nconst requestServer = computed<ServerObject | null>(() =>\n isWebhook ? null : server,\n)\n\n/** Cancel the request */\nconst cancelRequest = () => abortController.value?.abort(ERRORS.REQUEST_ABORTED)\n\n/**\n * Persist server-set cookies from a response into the document cookie jar.\n *\n * Scalar keeps its own cookie jar because browsers hide `Set-Cookie` from `fetch`.\n * Mirroring browser behavior, cookies are stored scoped to the request host and\n * path and removed when the server expires them, so a value like a Django CSRF\n * token stays available for later PUT/PATCH requests after a page reload.\n */\nconst persistResponseCookies = (sendResult: {\n response: ResponseInstance\n requestPayload: RequestPayload\n}) => {\n const actions = getResponseCookieActions({\n cookieHeaderKeys: sendResult.response.cookieHeaderKeys ?? [],\n documentCookies,\n requestUrl: getCookieRequestUrl(String(sendResult.requestPayload[0])),\n })\n\n for (const action of actions) {\n if (action.type === 'delete') {\n eventBus.emit('cookie:delete:cookie', {\n collectionType: 'document',\n cookieName: action.cookieName,\n index: action.index,\n })\n continue\n }\n\n eventBus.emit('cookie:upsert:cookie', {\n collectionType: 'document',\n payload: action.cookie,\n ...(action.index === undefined ? {} : { index: action.index }),\n })\n }\n}\n\n/**\n * Copy the executable URL — same pipeline as Send (`requestFactory` +\n * `resolveExecutableRequestUrl`), including security query params.\n */\nconst copyAddressBarUrl = async (): Promise<void> => {\n const { request } = requestFactory({\n defaultHeaders,\n environment,\n exampleName: exampleKey,\n globalCookies: [...workspaceCookies, ...documentCookies],\n method,\n operation,\n path: requestPath.value,\n proxyUrl,\n server: requestServer.value,\n selectedSecuritySchemes,\n isElectron: isElectron(),\n requestBodyCompositionSelection,\n })\n\n await copyToClipboard(\n resolveExecutableRequestUrl(request, getEnvironmentVariables(environment)),\n )\n}\n\n/** Execute the current operation example */\nconst handleExecute = async () => {\n eventBus.flushDebouncedEmits?.()\n\n if (isWebhook && !requestPath.value.trim()) {\n toast('Webhook URL required. Enter a destination first.', 'error')\n return\n }\n\n const pathValidation = validatePathParameters(\n operation.parameters ?? [],\n exampleKey,\n )\n if (pathValidation.ok === false) {\n toast('Path parameters must have values.', 'error')\n return\n }\n\n const globalCookies = [...workspaceCookies, ...documentCookies]\n\n const { request: requestBuilder } = requestFactory({\n defaultHeaders,\n environment,\n exampleName: exampleKey,\n globalCookies,\n method,\n operation,\n path: requestPath.value,\n proxyUrl,\n server: requestServer.value,\n selectedSecuritySchemes,\n isElectron: isElectron(),\n requestBodyCompositionSelection,\n })\n\n // Stop any previous streaming response\n if (response.value && 'reader' in response.value) {\n response.value.reader.cancel()\n }\n\n const variablesStore = createVariablesStoreForRequest()\n\n // Seed the script variable store with the active environment so pm.environment.get()\n // and pm.variables.get() resolve to the same values as {{…}} placeholders. Without\n // seeding, the store starts empty and every scripted read returns undefined.\n const seededEnvironment = getEnvironmentVariables(environment)\n variablesStore.setEnvironment?.(\n Object.entries(seededEnvironment).map(([key, value]) => ({ key, value })),\n )\n\n // Snapshot the persistence target at request start, alongside the seed. Persistence runs after\n // the request completes (awaits below), and the environment props are reactive — if the active\n // environment is switched mid-flight, or a concurrent request splices these arrays, reading\n // them at persist time would apply the script's writes to the wrong environment or resolve\n // workspace/document indexes against a shifted list. Copy the arrays (not just the reference)\n // so the seeded values and these targets stay fixed to the same point in time.\n const persistenceTarget = activeEnvironment\n ? {\n environmentName: activeEnvironment,\n mergedVariables: [...environment.variables],\n documentVariables: [\n ...(document['x-scalar-environments']?.[activeEnvironment]\n ?.variables ?? []),\n ],\n environmentExistsOnDocument: Boolean(\n document['x-scalar-environments']?.[activeEnvironment],\n ),\n }\n : null\n\n // Execute the beforeRequest hook (plugins receive RequestFactory, not fetch Request)\n await executeHook(\n {\n requestBuilder,\n document,\n operation,\n variablesStore,\n server: requestServer.value,\n customFetch: toValue(options)?.customFetch,\n },\n 'beforeRequest',\n plugins,\n )\n\n // Persist environment variables set by scripts (pm.environment.set / unset) back to the active\n // environment so they survive to the next request, mirroring the Environment tab. Scope and\n // index are resolved from the seed-time environment so updates mutate in place. Defined here so\n // it can run on every exit path after the pre-request scripts — including a build failure or a\n // failed send — so a pre-request set, like a token stored before a flaky call, is not lost.\n const persistScriptEnvironment = () => {\n if (!persistenceTarget) {\n return\n }\n\n const environmentActions = getEnvironmentPersistenceActions({\n ...persistenceTarget,\n seededVariables: seededEnvironment,\n scriptVariables: variablesStore.getEnvironment(),\n })\n\n for (const action of environmentActions) {\n if (action.type === 'delete') {\n eventBus.emit('environment:delete:environment-variable', {\n environmentName: action.environmentName,\n index: action.index,\n collectionType: action.collectionType,\n })\n } else {\n eventBus.emit('environment:upsert:environment-variable', {\n environmentName: action.environmentName,\n variable: action.variable,\n index: action.index,\n collectionType: action.collectionType,\n })\n }\n }\n }\n\n // Resolve {{…}} placeholders from the script store so pre-request pm.environment.set() and\n // unset() take effect on this request. The store was seeded from the active environment, so\n // it already holds every value spreading seededEnvironment would add — minus the keys a script\n // unset, which must stay dropped (an object spread cannot remove them again).\n const envVariables = variablesStore.getVariables()\n\n // Build the fetch Request after hooks may have mutated the factory\n const built = buildRequest(requestBuilder, {\n envVariables,\n allowMissingRequestServerBase: layout === 'modal',\n })\n if (!built.ok) {\n // Save any pre-request script writes before bailing out on a build failure.\n persistScriptEnvironment()\n toast(built.message ?? built.error, 'error')\n return\n }\n\n // Store the abort controller for cancellation\n abortController.value = built.data.controller\n\n // Build the fetch Request once so the requestBuilt hook observes the exact bytes that are\n // sent. Rebuilding it later would generate a different multipart boundary, which breaks\n // plugins that hash the body (for example, request signing).\n const request = buildSafeBodyRequest(...built.data.requestPayload)\n\n // Execute the requestBuilt hook (plugins receive the exact fetch Request that will be sent)\n await executeHook(\n {\n request,\n requestBuilder,\n document,\n operation,\n variablesStore,\n },\n 'requestBuilt',\n plugins,\n )\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:sent', {\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n /** Execute the request */\n const [sendError, sendResult] = await sendRequest({\n isUsingProxy: built.data.isUsingProxy,\n requestPayload: built.data.requestPayload,\n request,\n plugins,\n customFetch: toValue(options)?.customFetch,\n onResponseReceived: async (response, responseDuration) => {\n const result = await executeResponseHook(\n {\n response,\n responseDuration,\n requestBuilder,\n request: buildSafeBodyRequest(...built.data.requestPayload),\n document,\n operation,\n variablesStore,\n },\n plugins,\n )\n return result.response\n },\n })\n\n // Save script environment writes (pre-request and, on success, post-response) back to the\n // active environment. Runs even when the send fails so a pre-request set is not lost.\n persistScriptEnvironment()\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:complete', {\n payload: sendResult\n ? {\n response: sendResult.originalResponse.clone(),\n requestPayload: sendResult.requestPayload,\n duration: sendResult.response.duration,\n timestamp: sendResult.timestamp,\n }\n : undefined,\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n if (sendError) {\n // clean up the response and request\n response.value = null\n requestPayload.value = null\n abortController.value = null\n\n toast(sendError.message, 'error')\n return\n }\n\n // Store the response\n response.value = sendResult.response\n requestPayload.value = sendResult.requestPayload\n\n // Persist server-set cookies into the document jar so values like a CSRF token\n // survive a page reload and get replayed on the next request, like a browser would.\n persistResponseCookies(sendResult)\n\n // Cache non-streaming responses so they can be restored when navigating back\n if (!isStreamingResponse(sendResult.response)) {\n responseCache.set(getOperationExampleKey(method, path, exampleKey), {\n response: sendResult.response,\n requestPayload: sendResult.requestPayload,\n })\n }\n}\n\nonMounted(() => {\n eventBus.on('operation:send:request:hotkey', handleExecute)\n eventBus.on('operation:cancel:request', cancelRequest)\n eventBus.on('copy-url:address-bar', copyAddressBarUrl)\n\n // Let plugins warm up per-operation resources (e.g. the scripts sandbox) so the first request\n // does not pay their cold-start cost.\n void executeHook({ document, operation }, 'onRequestMount', plugins)\n})\nonBeforeUnmount(() => {\n eventBus.off('operation:send:request:hotkey', handleExecute)\n eventBus.off('operation:cancel:request', cancelRequest)\n eventBus.off('copy-url:address-bar', copyAddressBarUrl)\n})\n\nconst operationHistory = computed<History[]>(() =>\n history\n .map((entry) => ({\n method: entry.request.method as HttpMethodType,\n path: entry.request.url,\n duration: entry.time,\n status: entry.response.status,\n }))\n .reverse(),\n)\n\nconst handleSelectHistoryItem = ({ index }: { index: number }) => {\n const transformedIndex = (history.length ?? 0) - index - 1\n const historyItem = history[transformedIndex]\n if (!historyItem) {\n return\n }\n\n const navigate = () =>\n eventBus.emit('ui:navigate', {\n page: 'example',\n method,\n path,\n exampleName: 'draft',\n callback: (status) => {\n // Do not replace the response if the navigation was not successful\n if (status !== 'success') {\n return\n }\n // Reconstruct the response\n const fetchResponse = harToFetchResponse({\n harResponse: historyItem.response,\n url: historyItem.request.url,\n method,\n path,\n duration: historyItem.time,\n })\n\n // Reconstruct the request\n const fetchRequest = harToFetchRequest({\n harRequest: historyItem.request,\n })\n\n // Update the response and request\n response.value = fetchResponse\n requestPayload.value = fetchRequest\n },\n })\n\n eventBus.emit('operation:reload:history', {\n meta: {\n path,\n method,\n },\n index: transformedIndex,\n callback: navigate,\n })\n}\n\nconst handleNavigateSettings = () => {\n eventBus.emit('ui:navigate', {\n page: 'operation',\n path: 'overview',\n operationPath: path,\n method,\n })\n}\n\n/**\n * When the path, method, or example key changes, restore the response panel\n * for the new operation from the best available source:\n *\n * 1. `responseCache` — in-memory, populated on every successful send.\n * Has the live response object (including streams) so it wins.\n * 2. `history` — persisted in the workspace store. Used as a fallback when\n * the in-memory cache is empty (page reload, fresh app session, etc.)\n * so navigating to an operation that has been called before shows the\n * last response instead of an empty panel.\n * 3. Otherwise clear.\n *\n * Only the response is restored from history — the user's request inputs are\n * left alone, so we never silently overwrite an in-progress draft.\n */\nwatch(\n [() => path, () => method, () => exampleKey],\n ([newPath, newMethod, newExampleKey]) => {\n const cached = responseCache.get(\n getOperationExampleKey(newMethod, newPath, newExampleKey),\n )\n\n if (cached) {\n response.value = cached.response\n requestPayload.value = cached.requestPayload\n } else {\n // History is keyed only by document/path/method but each entry carries\n // the example it came from, so we walk from the end and pick the most\n // recent entry that matches the active example. Otherwise a cache miss\n // on example B would restore example A's response. Only runs on a\n // cache miss — the common case (in-session navigation) skips it.\n const latest = (() => {\n for (let i = history.length - 1; i >= 0; i--) {\n const entry = history[i]\n if (entry?.meta.example === newExampleKey) {\n return entry\n }\n }\n return undefined\n })()\n\n if (latest) {\n response.value = harToFetchResponse({\n harResponse: latest.response,\n url: latest.request.url,\n method: newMethod,\n path: newPath,\n duration: latest.time,\n })\n requestPayload.value = null\n } else {\n response.value = null\n requestPayload.value = null\n }\n }\n\n // Cancel any in-flight request\n cancelRequest()\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => {\n // We cancel the request if the component is unmounted\n cancelRequest()\n})\n</script>\n<template>\n <div class=\"bg-b-1 flex h-full flex-col\">\n <div\n class=\"lg:min-h-header flex w-full flex-wrap items-center justify-center p-2 lg:p-0\">\n <!-- Address Bar -->\n <Header\n :activeEnvironment\n :documentSlug\n :documentUrl\n :environment\n :environments\n :eventBus\n :exampleKey\n :hideClientButton\n :history=\"operationHistory\"\n :integration\n :isWebhook\n :layout\n :method\n :path=\"requestPath\"\n :server=\"requestServer\"\n :serverMeta\n :servers\n :source\n @execute=\"handleExecute\"\n @navigate:settings=\"handleNavigateSettings\"\n @select:history:item=\"handleSelectHistoryItem\"\n @update:webhook-url=\"(value) => (webhookUrl = value)\" />\n </div>\n\n <ViewLayout class=\"border-t\">\n <ViewLayoutContent class=\"flex-1\">\n <!-- Request Section -->\n <RequestBlock\n :authMeta\n :clientOptions\n :defaultHeaders\n :defaultRequestBodyView=\"\n document['x-scalar-default-request-body-view']\n \"\n :documentCookies\n :documentSlug\n :environment\n :eventBus\n :exampleKey\n :layout\n :method\n :operation\n :options=\"toValue(options)\"\n :path=\"requestPath\"\n :plugins\n :proxyUrl\n :requestBodyCompositionSelection\n :securityRequirements\n :securitySchemes\n :selectedClient\n :selectedSecurity\n :selectedSecuritySchemes\n :server=\"requestServer\"\n :workspaceCookies />\n\n <!-- Response Section -->\n <ResponseBlock\n :appVersion\n :eventBus\n :layout\n :plugins\n :requestPayload\n :response\n :totalPerformedRequests=\"operationHistory.length\" />\n </ViewLayoutContent>\n </ViewLayout>\n </div>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"OperationBlock.vue.js","names":[],"sources":["../../../../src/v2/blocks/operation-block/OperationBlock.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * OperationBlock\n *\n * Orchestrates the operation view by wiring together the Header, OperationBlock,\n * and ResponseBlock. Forwards user interactions to the workspace event bus and\n * passes through configuration such as auth, servers, plugins, and environment.\n * This component keeps the Operation page lean by centralizing event emission\n * and prop wiring between the blocks.\n *\n * Notable behavior:\n * - Uses operation['x-scalar-method'] and operation['x-scalar-path'] to provide\n * draft overrides for the UI when present.\n */\nexport default {\n name: 'OperationBlock',\n}\n\nexport type OperationBlockProps = {\n /** Keep execution and editing unavailable until the selected payload is ready. */\n externalExamplesPending?: boolean\n externalExamplesFailed?: boolean\n /** Event bus */\n eventBus: WorkspaceEventBus\n /** Application version */\n appVersion: string\n /** Openapi document */\n document: OpenApiDocument\n /** Openapi document slug */\n documentSlug: string\n /** Workspace cookies */\n workspaceCookies: XScalarCookie[]\n /** Document cookies */\n documentCookies: XScalarCookie[]\n /** Current request path */\n path: string\n /** Current request method */\n method: HttpMethodType\n /** Whether `path` identifies an OpenAPI webhook. */\n isWebhook?: boolean\n /** HTTP clients */\n httpClients: AvailableClients\n /** The history for the operation */\n history?: HistoryEntry[]\n /** Client layout */\n layout: ClientLayout\n /** Currently selected server */\n server: ServerObject | null\n /** Currently selected client */\n selectedClient: WorkspaceStore['workspace']['x-scalar-default-client']\n /** Server list available for operation/document */\n servers: ServerObject[]\n /** Meta information for the server */\n serverMeta: ServerMeta\n /** Hides the client button on the header */\n hideClientButton?: boolean\n /** Client integration */\n integration?: string | null\n /** Openapi document url for `modal` mode to open the client app */\n documentUrl?: string\n /** Client source */\n source?: 'gitbook' | 'api-reference'\n /** Operation object */\n operation: OperationObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Meta information for the auth update */\n authMeta: AuthMeta\n /** Document defined security schemes */\n securitySchemes: MergedSecuritySchemes\n /** Client plugins */\n plugins: ClientPlugin[]\n /** Environment list */\n environments?: string[]\n /** Currently selected environment */\n activeEnvironment?: string\n /** For environment variables in the inputs */\n environment: XScalarEnvironment\n /** The proxy URL for sending requests */\n proxyUrl: string\n /** Currently selected security */\n selectedSecurity: SelectedSecurity\n /** Currently selected security schemes */\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n /** Security requirements */\n securityRequirements: OpenApiDocument['security']\n /** Default headers */\n defaultHeaders: Record<string, string>\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n /** Subset of config options for the modal */\n options?: ModalProps['options']\n}\n</script>\n<script setup lang=\"ts\">\nimport { generateClientOptions } from '@scalar/blocks/code-example'\nimport { ScalarButton } from '@scalar/components/button'\nimport { ERRORS } from '@scalar/helpers/errors/normalize-error'\nimport { isElectron } from '@scalar/helpers/general/is-electron'\nimport { buildSafeBodyRequest } from '@scalar/helpers/http/can-method-have-body'\nimport type { HttpMethod as HttpMethodType } from '@scalar/helpers/http/http-methods'\nimport {\n executeHook,\n executeResponseHook,\n type ClientPlugin,\n} from '@scalar/oas-utils/helpers'\nimport {\n AVAILABLE_CLIENTS,\n type AvailableClients,\n} from '@scalar/types/snippetz'\nimport { useClipboard } from '@scalar/use-hooks/useClipboard'\nimport { useToasts } from '@scalar/use-toasts'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type { HistoryEntry } from '@scalar/workspace-store/entities/history/schema'\nimport type {\n AuthMeta,\n ServerMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport {\n buildRequest,\n createVariablesStoreForRequest,\n getEnvironmentVariables,\n requestFactory,\n resolveExecutableRequestUrl,\n type MergedSecuritySchemes,\n type RequestPayload,\n type SecuritySchemeObjectSecret,\n} from '@scalar/workspace-store/request-example'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type { XScalarCookie } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type {\n OpenApiDocument,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport type { OperationObject } from '@scalar/workspace-store/schemas/v3.2/strict/operation'\nimport { computed, onBeforeUnmount, onMounted, ref, toValue, watch } from 'vue'\n\nimport ViewLayout from '@/components/ViewLayout/ViewLayout.vue'\nimport ViewLayoutContent from '@/components/ViewLayout/ViewLayoutContent.vue'\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport { harToFetchRequest } from '@/v2/blocks/operation-block/helpers/har-to-fetch-request'\nimport { harToFetchResponse } from '@/v2/blocks/operation-block/helpers/har-to-fetch-response'\nimport {\n getCookieRequestUrl,\n getResponseCookieActions,\n} from '@/v2/blocks/operation-block/helpers/persist-response-cookies'\nimport { getEnvironmentPersistenceActions } from '@/v2/blocks/operation-block/helpers/persist-script-environment'\nimport {\n getOperationExampleKey,\n isStreamingResponse,\n responseCache,\n} from '@/v2/blocks/operation-block/helpers/response-cache'\nimport {\n sendRequest,\n type ResponseInstance,\n} from '@/v2/blocks/operation-block/helpers/send-request'\nimport { validatePathParameters } from '@/v2/blocks/operation-block/helpers/validate-path-parameters'\nimport { RequestBlock } from '@/v2/blocks/request-block'\nimport { ResponseBlock } from '@/v2/blocks/response-block'\nimport { type History } from '@/v2/blocks/scalar-address-bar-block'\nimport type { ModalProps } from '@/v2/features/modal/Modal.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\nimport Header from './components/Header.vue'\n\nconst {\n externalExamplesPending = false,\n externalExamplesFailed = false,\n authMeta,\n environment,\n eventBus,\n exampleKey,\n document,\n documentSlug,\n workspaceCookies = [],\n documentCookies = [],\n hideClientButton,\n httpClients = AVAILABLE_CLIENTS,\n history = [],\n layout,\n method,\n isWebhook = false,\n operation,\n path,\n plugins = [],\n proxyUrl,\n requestBodyCompositionSelection,\n securitySchemes,\n selectedClient,\n server,\n servers,\n environments,\n options,\n activeEnvironment,\n serverMeta,\n selectedSecurity,\n selectedSecuritySchemes,\n securityRequirements,\n defaultHeaders,\n} = defineProps<OperationBlockProps>()\n\ndefineEmits<{ (e: 'retry:externalExamples'): void }>()\n\n/** Hoist up client generation so it doesn't get re-generated on every operation */\nconst clientOptions = computed(() => generateClientOptions(httpClients))\n\nconst { toast } = useToasts()\nconst { copyToClipboard } = useClipboard()\n\n// Refs\nconst abortController = ref<AbortController | null>(null)\nconst response = ref<ResponseInstance | null>(null)\nconst requestPayload = ref<RequestPayload | null>(null)\n\n/**\n * A webhook has no OpenAPI server, so its destination is the full URL the user\n * enters at runtime. The field holds that whole URL (not a server-relative path),\n * and the request is sent to it directly with no separate server base.\n */\nconst webhookUrl = ref('')\n\nwatch(\n [() => path, () => method, () => isWebhook],\n () => {\n webhookUrl.value = ''\n },\n { immediate: true },\n)\n\nconst requestPath = computed(() => (isWebhook ? webhookUrl.value : path))\nconst requestServer = computed<ServerObject | null>(() =>\n isWebhook ? null : server,\n)\n\n/** Cancel the request */\nconst cancelRequest = () => abortController.value?.abort(ERRORS.REQUEST_ABORTED)\n\n/**\n * Persist server-set cookies from a response into the document cookie jar.\n *\n * Scalar keeps its own cookie jar because browsers hide `Set-Cookie` from `fetch`.\n * Mirroring browser behavior, cookies are stored scoped to the request host and\n * path and removed when the server expires them, so a value like a Django CSRF\n * token stays available for later PUT/PATCH requests after a page reload.\n */\nconst persistResponseCookies = (sendResult: {\n response: ResponseInstance\n requestPayload: RequestPayload\n}) => {\n const actions = getResponseCookieActions({\n cookieHeaderKeys: sendResult.response.cookieHeaderKeys ?? [],\n documentCookies,\n requestUrl: getCookieRequestUrl(String(sendResult.requestPayload[0])),\n })\n\n for (const action of actions) {\n if (action.type === 'delete') {\n eventBus.emit('cookie:delete:cookie', {\n collectionType: 'document',\n cookieName: action.cookieName,\n index: action.index,\n })\n continue\n }\n\n eventBus.emit('cookie:upsert:cookie', {\n collectionType: 'document',\n payload: action.cookie,\n ...(action.index === undefined ? {} : { index: action.index }),\n })\n }\n}\n\n/**\n * Copy the executable URL — same pipeline as Send (`requestFactory` +\n * `resolveExecutableRequestUrl`), including security query params.\n */\nconst copyAddressBarUrl = async (): Promise<void> => {\n const { request } = requestFactory({\n defaultHeaders,\n environment,\n exampleName: exampleKey,\n globalCookies: [...workspaceCookies, ...documentCookies],\n method,\n operation,\n path: requestPath.value,\n proxyUrl,\n server: requestServer.value,\n selectedSecuritySchemes,\n isElectron: isElectron(),\n requestBodyCompositionSelection,\n })\n\n await copyToClipboard(\n resolveExecutableRequestUrl(request, getEnvironmentVariables(environment)),\n )\n}\n\n/** Execute the current operation example */\nconst handleExecute = async () => {\n if (externalExamplesPending) return\n eventBus.flushDebouncedEmits?.()\n\n if (isWebhook && !requestPath.value.trim()) {\n toast('Webhook URL required. Enter a destination first.', 'error')\n return\n }\n\n const pathValidation = validatePathParameters(\n operation.parameters ?? [],\n exampleKey,\n )\n if (pathValidation.ok === false) {\n toast('Path parameters must have values.', 'error')\n return\n }\n\n const globalCookies = [...workspaceCookies, ...documentCookies]\n\n const { request: requestBuilder } = requestFactory({\n defaultHeaders,\n environment,\n exampleName: exampleKey,\n globalCookies,\n method,\n operation,\n path: requestPath.value,\n proxyUrl,\n server: requestServer.value,\n selectedSecuritySchemes,\n isElectron: isElectron(),\n requestBodyCompositionSelection,\n })\n\n // Stop any previous streaming response\n if (response.value && 'reader' in response.value) {\n response.value.reader.cancel()\n }\n\n const variablesStore = createVariablesStoreForRequest()\n\n // Seed the script variable store with the active environment so pm.environment.get()\n // and pm.variables.get() resolve to the same values as {{…}} placeholders. Without\n // seeding, the store starts empty and every scripted read returns undefined.\n const seededEnvironment = getEnvironmentVariables(environment)\n variablesStore.setEnvironment?.(\n Object.entries(seededEnvironment).map(([key, value]) => ({ key, value })),\n )\n\n // Snapshot the persistence target at request start, alongside the seed. Persistence runs after\n // the request completes (awaits below), and the environment props are reactive — if the active\n // environment is switched mid-flight, or a concurrent request splices these arrays, reading\n // them at persist time would apply the script's writes to the wrong environment or resolve\n // workspace/document indexes against a shifted list. Copy the arrays (not just the reference)\n // so the seeded values and these targets stay fixed to the same point in time.\n const persistenceTarget = activeEnvironment\n ? {\n environmentName: activeEnvironment,\n mergedVariables: [...environment.variables],\n documentVariables: [\n ...(document['x-scalar-environments']?.[activeEnvironment]\n ?.variables ?? []),\n ],\n environmentExistsOnDocument: Boolean(\n document['x-scalar-environments']?.[activeEnvironment],\n ),\n }\n : null\n\n // Execute the beforeRequest hook (plugins receive RequestFactory, not fetch Request)\n await executeHook(\n {\n requestBuilder,\n document,\n operation,\n variablesStore,\n server: requestServer.value,\n customFetch: toValue(options)?.customFetch,\n },\n 'beforeRequest',\n plugins,\n )\n\n // Persist environment variables set by scripts (pm.environment.set / unset) back to the active\n // environment so they survive to the next request, mirroring the Environment tab. Scope and\n // index are resolved from the seed-time environment so updates mutate in place. Defined here so\n // it can run on every exit path after the pre-request scripts — including a build failure or a\n // failed send — so a pre-request set, like a token stored before a flaky call, is not lost.\n const persistScriptEnvironment = () => {\n if (!persistenceTarget) {\n return\n }\n\n const environmentActions = getEnvironmentPersistenceActions({\n ...persistenceTarget,\n seededVariables: seededEnvironment,\n scriptVariables: variablesStore.getEnvironment(),\n })\n\n for (const action of environmentActions) {\n if (action.type === 'delete') {\n eventBus.emit('environment:delete:environment-variable', {\n environmentName: action.environmentName,\n index: action.index,\n collectionType: action.collectionType,\n })\n } else {\n eventBus.emit('environment:upsert:environment-variable', {\n environmentName: action.environmentName,\n variable: action.variable,\n index: action.index,\n collectionType: action.collectionType,\n })\n }\n }\n }\n\n // Resolve {{…}} placeholders from the script store so pre-request pm.environment.set() and\n // unset() take effect on this request. The store was seeded from the active environment, so\n // it already holds every value spreading seededEnvironment would add — minus the keys a script\n // unset, which must stay dropped (an object spread cannot remove them again).\n const envVariables = variablesStore.getVariables()\n\n // Build the fetch Request after hooks may have mutated the factory\n const built = buildRequest(requestBuilder, {\n envVariables,\n allowMissingRequestServerBase: layout === 'modal',\n })\n if (!built.ok) {\n // Save any pre-request script writes before bailing out on a build failure.\n persistScriptEnvironment()\n toast(built.message ?? built.error, 'error')\n return\n }\n\n // Store the abort controller for cancellation\n abortController.value = built.data.controller\n\n // Build the fetch Request once so the requestBuilt hook observes the exact bytes that are\n // sent. Rebuilding it later would generate a different multipart boundary, which breaks\n // plugins that hash the body (for example, request signing).\n const request = buildSafeBodyRequest(...built.data.requestPayload)\n\n // Execute the requestBuilt hook (plugins receive the exact fetch Request that will be sent)\n await executeHook(\n {\n request,\n requestBuilder,\n document,\n operation,\n variablesStore,\n },\n 'requestBuilt',\n plugins,\n )\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:sent', {\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n /** Execute the request */\n const [sendError, sendResult] = await sendRequest({\n isUsingProxy: built.data.isUsingProxy,\n requestPayload: built.data.requestPayload,\n request,\n plugins,\n customFetch: toValue(options)?.customFetch,\n onResponseReceived: async (response, responseDuration) => {\n const result = await executeResponseHook(\n {\n response,\n responseDuration,\n requestBuilder,\n request: buildSafeBodyRequest(...built.data.requestPayload),\n document,\n operation,\n variablesStore,\n },\n plugins,\n )\n return result.response\n },\n })\n\n // Save script environment writes (pre-request and, on success, post-response) back to the\n // active environment. Runs even when the send fails so a pre-request set is not lost.\n persistScriptEnvironment()\n\n // Execute the hooks\n eventBus.emit('hooks:on:request:complete', {\n payload: sendResult\n ? {\n response: sendResult.originalResponse.clone(),\n requestPayload: sendResult.requestPayload,\n duration: sendResult.response.duration,\n timestamp: sendResult.timestamp,\n }\n : undefined,\n meta: {\n method,\n path,\n exampleKey,\n },\n })\n\n if (sendError) {\n // clean up the response and request\n response.value = null\n requestPayload.value = null\n abortController.value = null\n\n toast(sendError.message, 'error')\n return\n }\n\n // Store the response\n response.value = sendResult.response\n requestPayload.value = sendResult.requestPayload\n\n // Persist server-set cookies into the document jar so values like a CSRF token\n // survive a page reload and get replayed on the next request, like a browser would.\n persistResponseCookies(sendResult)\n\n // Cache non-streaming responses so they can be restored when navigating back\n if (!isStreamingResponse(sendResult.response)) {\n responseCache.set(getOperationExampleKey(method, path, exampleKey), {\n response: sendResult.response,\n requestPayload: sendResult.requestPayload,\n })\n }\n}\n\nonMounted(() => {\n eventBus.on('operation:send:request:hotkey', handleExecute)\n eventBus.on('operation:cancel:request', cancelRequest)\n eventBus.on('copy-url:address-bar', copyAddressBarUrl)\n\n // Let plugins warm up per-operation resources (e.g. the scripts sandbox) so the first request\n // does not pay their cold-start cost.\n void executeHook({ document, operation }, 'onRequestMount', plugins)\n})\nonBeforeUnmount(() => {\n eventBus.off('operation:send:request:hotkey', handleExecute)\n eventBus.off('operation:cancel:request', cancelRequest)\n eventBus.off('copy-url:address-bar', copyAddressBarUrl)\n})\n\nconst operationHistory = computed<History[]>(() =>\n history\n .map((entry) => ({\n method: entry.request.method as HttpMethodType,\n path: entry.request.url,\n duration: entry.time,\n status: entry.response.status,\n }))\n .reverse(),\n)\n\nconst handleSelectHistoryItem = ({ index }: { index: number }) => {\n const transformedIndex = (history.length ?? 0) - index - 1\n const historyItem = history[transformedIndex]\n if (!historyItem) {\n return\n }\n\n const navigate = () =>\n eventBus.emit('ui:navigate', {\n page: 'example',\n method,\n path,\n exampleName: 'draft',\n callback: (status) => {\n // Do not replace the response if the navigation was not successful\n if (status !== 'success') {\n return\n }\n // Reconstruct the response\n const fetchResponse = harToFetchResponse({\n harResponse: historyItem.response,\n url: historyItem.request.url,\n method,\n path,\n duration: historyItem.time,\n })\n\n // Reconstruct the request\n const fetchRequest = harToFetchRequest({\n harRequest: historyItem.request,\n })\n\n // Update the response and request\n response.value = fetchResponse\n requestPayload.value = fetchRequest\n },\n })\n\n eventBus.emit('operation:reload:history', {\n meta: {\n path,\n method,\n },\n index: transformedIndex,\n callback: navigate,\n })\n}\n\nconst handleNavigateSettings = () => {\n eventBus.emit('ui:navigate', {\n page: 'operation',\n path: 'overview',\n operationPath: path,\n method,\n })\n}\n\n/**\n * When the path, method, or example key changes, restore the response panel\n * for the new operation from the best available source:\n *\n * 1. `responseCache` — in-memory, populated on every successful send.\n * Has the live response object (including streams) so it wins.\n * 2. `history` — persisted in the workspace store. Used as a fallback when\n * the in-memory cache is empty (page reload, fresh app session, etc.)\n * so navigating to an operation that has been called before shows the\n * last response instead of an empty panel.\n * 3. Otherwise clear.\n *\n * Only the response is restored from history — the user's request inputs are\n * left alone, so we never silently overwrite an in-progress draft.\n */\nwatch(\n [() => path, () => method, () => exampleKey],\n ([newPath, newMethod, newExampleKey]) => {\n const cached = responseCache.get(\n getOperationExampleKey(newMethod, newPath, newExampleKey),\n )\n\n if (cached) {\n response.value = cached.response\n requestPayload.value = cached.requestPayload\n } else {\n // History is keyed only by document/path/method but each entry carries\n // the example it came from, so we walk from the end and pick the most\n // recent entry that matches the active example. Otherwise a cache miss\n // on example B would restore example A's response. Only runs on a\n // cache miss — the common case (in-session navigation) skips it.\n const latest = (() => {\n for (let i = history.length - 1; i >= 0; i--) {\n const entry = history[i]\n if (entry?.meta.example === newExampleKey) {\n return entry\n }\n }\n return undefined\n })()\n\n if (latest) {\n response.value = harToFetchResponse({\n harResponse: latest.response,\n url: latest.request.url,\n method: newMethod,\n path: newPath,\n duration: latest.time,\n })\n requestPayload.value = null\n } else {\n response.value = null\n requestPayload.value = null\n }\n }\n\n // Cancel any in-flight request\n cancelRequest()\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => {\n // We cancel the request if the component is unmounted\n cancelRequest()\n})\n</script>\n<template>\n <div class=\"bg-b-1 flex h-full flex-col\">\n <div\n class=\"lg:min-h-header flex w-full flex-wrap items-center justify-center p-2 lg:p-0\">\n <!-- Address Bar -->\n <Header\n :activeEnvironment\n :documentSlug\n :documentUrl\n :environment\n :environments\n :eventBus\n :exampleKey\n :executionDisabled=\"externalExamplesPending\"\n :hideClientButton\n :history=\"operationHistory\"\n :integration\n :isWebhook\n :layout\n :method\n :path=\"requestPath\"\n :server=\"requestServer\"\n :serverMeta\n :servers\n :source\n @execute=\"handleExecute\"\n @navigate:settings=\"handleNavigateSettings\"\n @select:history:item=\"handleSelectHistoryItem\"\n @update:webhook-url=\"(value) => (webhookUrl = value)\" />\n </div>\n\n <ViewLayout class=\"border-t\">\n <ViewLayoutContent class=\"flex-1\">\n <!-- Request Section -->\n <ViewLayoutSection\n v-if=\"externalExamplesPending\"\n aria-label=\"Request\">\n <template #title>Request</template>\n <div\n class=\"text-c-2 p-4\"\n role=\"status\">\n <template v-if=\"externalExamplesFailed\">\n Could not load this example.\n <ScalarButton\n size=\"sm\"\n variant=\"ghost\"\n @click=\"$emit('retry:externalExamples')\">\n Retry\n </ScalarButton>\n </template>\n <template v-else>Loading example…</template>\n </div>\n </ViewLayoutSection>\n <RequestBlock\n v-else\n :authMeta\n :clientOptions\n :defaultHeaders\n :defaultRequestBodyView=\"\n document['x-scalar-default-request-body-view']\n \"\n :documentCookies\n :documentSlug\n :environment\n :eventBus\n :exampleKey\n :layout\n :method\n :operation\n :options=\"toValue(options)\"\n :path=\"requestPath\"\n :plugins\n :proxyUrl\n :requestBodyCompositionSelection\n :securityRequirements\n :securitySchemes\n :selectedClient\n :selectedSecurity\n :selectedSecuritySchemes\n :server=\"requestServer\"\n :workspaceCookies />\n\n <!-- Response Section -->\n <ResponseBlock\n :appVersion\n :eventBus\n :executionDisabled=\"externalExamplesPending\"\n :layout\n :plugins\n :requestPayload\n :response\n :totalPerformedRequests=\"operationHistory.length\" />\n </ViewLayoutContent>\n </ViewLayout>\n </div>\n</template>\n"],"mappings":""}
@@ -1,5 +1,6 @@
1
1
  import ViewLayout_default from "../../../components/ViewLayout/ViewLayout.vue.js";
2
2
  import ViewLayoutContent_default from "../../../components/ViewLayout/ViewLayoutContent.vue.js";
3
+ import ViewLayoutSection_default from "../../../components/ViewLayout/ViewLayoutSection.vue.js";
3
4
  import { sendRequest } from "./helpers/send-request.js";
4
5
  import { harToFetchRequest } from "./helpers/har-to-fetch-request.js";
5
6
  import { harToFetchResponse } from "./helpers/har-to-fetch-response.js";
@@ -10,7 +11,8 @@ import { validatePathParameters } from "./helpers/validate-path-parameters.js";
10
11
  import RequestBlock_default from "../request-block/RequestBlock.vue.js";
11
12
  import ResponseBlock_default from "../response-block/ResponseBlock.vue.js";
12
13
  import Header_default from "./components/Header.vue.js";
13
- import { computed, createElementBlock, createElementVNode, createVNode, defineComponent, onBeforeUnmount, onMounted, openBlock, ref, toValue, unref, watch, withCtx } from "vue";
14
+ import { Fragment, computed, createBlock, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, onBeforeUnmount, onMounted, openBlock, ref, toValue, unref, watch, withCtx } from "vue";
15
+ import { ScalarButton } from "@scalar/components/button";
14
16
  import { buildRequest, createVariablesStoreForRequest, getEnvironmentVariables, requestFactory, resolveExecutableRequestUrl } from "@scalar/workspace-store/request-example";
15
17
  import { ERRORS } from "@scalar/helpers/errors/normalize-error";
16
18
  import { isElectron } from "@scalar/helpers/general/is-electron";
@@ -23,9 +25,21 @@ import { useToasts } from "@scalar/use-toasts";
23
25
  //#region src/v2/blocks/operation-block/OperationBlock.vue?vue&type=script&setup=true&lang.ts
24
26
  var _hoisted_1 = { class: "bg-b-1 flex h-full flex-col" };
25
27
  var _hoisted_2 = { class: "lg:min-h-header flex w-full flex-wrap items-center justify-center p-2 lg:p-0" };
28
+ var _hoisted_3 = {
29
+ class: "text-c-2 p-4",
30
+ role: "status"
31
+ };
26
32
  var OperationBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
27
33
  name: "OperationBlock",
28
34
  props: {
35
+ externalExamplesPending: {
36
+ type: Boolean,
37
+ default: false
38
+ },
39
+ externalExamplesFailed: {
40
+ type: Boolean,
41
+ default: false
42
+ },
29
43
  eventBus: {},
30
44
  appVersion: {},
31
45
  document: {},
@@ -65,6 +79,7 @@ var OperationBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
65
79
  requestBodyCompositionSelection: {},
66
80
  options: {}
67
81
  },
82
+ emits: ["retry:externalExamples"],
68
83
  setup(__props) {
69
84
  /** Hoist up client generation so it doesn't get re-generated on every operation */
70
85
  const clientOptions = computed(() => generateClientOptions(__props.httpClients));
@@ -143,6 +158,7 @@ var OperationBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
143
158
  };
144
159
  /** Execute the current operation example */
145
160
  const handleExecute = async () => {
161
+ if (__props.externalExamplesPending) return;
146
162
  __props.eventBus.flushDebouncedEmits?.();
147
163
  if (__props.isWebhook && !requestPath.value.trim()) {
148
164
  toast("Webhook URL required. Enter a destination first.", "error");
@@ -397,6 +413,7 @@ var OperationBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
397
413
  environments: __props.environments,
398
414
  eventBus: __props.eventBus,
399
415
  exampleKey: __props.exampleKey,
416
+ executionDisabled: __props.externalExamplesPending,
400
417
  hideClientButton: __props.hideClientButton,
401
418
  history: operationHistory.value,
402
419
  integration: __props.integration,
@@ -420,6 +437,7 @@ var OperationBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
420
437
  "environments",
421
438
  "eventBus",
422
439
  "exampleKey",
440
+ "executionDisabled",
423
441
  "hideClientButton",
424
442
  "history",
425
443
  "integration",
@@ -433,7 +451,22 @@ var OperationBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
433
451
  "source"
434
452
  ])]), createVNode(ViewLayout_default, { class: "border-t" }, {
435
453
  default: withCtx(() => [createVNode(ViewLayoutContent_default, { class: "flex-1" }, {
436
- default: withCtx(() => [createVNode(unref(RequestBlock_default), {
454
+ default: withCtx(() => [__props.externalExamplesPending ? (openBlock(), createBlock(ViewLayoutSection_default, {
455
+ key: 0,
456
+ "aria-label": "Request"
457
+ }, {
458
+ title: withCtx(() => [..._cache[2] || (_cache[2] = [createTextVNode("Request", -1)])]),
459
+ default: withCtx(() => [createElementVNode("div", _hoisted_3, [__props.externalExamplesFailed ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [_cache[4] || (_cache[4] = createTextVNode(" Could not load this example. ", -1)), createVNode(unref(ScalarButton), {
460
+ size: "sm",
461
+ variant: "ghost",
462
+ onClick: _cache[1] || (_cache[1] = ($event) => _ctx.$emit("retry:externalExamples"))
463
+ }, {
464
+ default: withCtx(() => [..._cache[3] || (_cache[3] = [createTextVNode(" Retry ", -1)])]),
465
+ _: 1
466
+ })], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode("Loading example…")], 64))])]),
467
+ _: 1
468
+ })) : (openBlock(), createBlock(unref(RequestBlock_default), {
469
+ key: 1,
437
470
  authMeta: __props.authMeta,
438
471
  clientOptions: clientOptions.value,
439
472
  defaultHeaders: __props.defaultHeaders,
@@ -483,9 +516,10 @@ var OperationBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
483
516
  "selectedSecuritySchemes",
484
517
  "server",
485
518
  "workspaceCookies"
486
- ]), createVNode(unref(ResponseBlock_default), {
519
+ ])), createVNode(unref(ResponseBlock_default), {
487
520
  appVersion: __props.appVersion,
488
521
  eventBus: __props.eventBus,
522
+ executionDisabled: __props.externalExamplesPending,
489
523
  layout: __props.layout,
490
524
  plugins: __props.plugins,
491
525
  requestPayload: requestPayload.value,
@@ -494,6 +528,7 @@ var OperationBlock_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ d
494
528
  }, null, 8, [
495
529
  "appVersion",
496
530
  "eventBus",
531
+ "executionDisabled",
497
532
  "layout",
498
533
  "plugins",
499
534
  "requestPayload",