@scalar/api-client 3.21.3 → 3.21.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/dist/plugins/posthog/sanitize-event-payload.d.ts.map +1 -1
- package/dist/plugins/posthog/sanitize-event-payload.js +1 -0
- package/dist/plugins/posthog/sanitize-event-payload.js.map +1 -1
- package/dist/style.css +59 -49
- package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts.map +1 -1
- package/dist/v2/blocks/operation-block/OperationBlock.vue.js.map +1 -1
- package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js +1 -1
- package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestBody.vue.d.ts.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestBody.vue.js +1 -1
- package/dist/v2/blocks/request-block/components/RequestBody.vue.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestBody.vue.script.js +1 -1
- package/dist/v2/blocks/request-block/components/RequestBody.vue.script.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.d.ts.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.js.map +1 -1
- package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.script.js +3 -0
- package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.script.js.map +1 -1
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.d.ts.map +1 -1
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.js +1 -1
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.js.map +1 -1
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.script.js +1 -1
- package/dist/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue.script.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.script.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.d.ts.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.script.js +53 -22
- package/dist/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue.script.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTableInput.vue.d.ts +4 -0
- package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTableInput.vue.d.ts.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTableInput.vue.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTableInput.vue.script.js +23 -12
- package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthDataTableInput.vue.script.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.d.ts.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.script.js +30 -6
- package/dist/v2/blocks/scalar-auth-selector-block/components/RequestAuthTab.vue.script.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth-device-authorization.d.ts.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth-device-authorization.js +3 -1
- package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth-device-authorization.js.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.d.ts.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.js +9 -3
- package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.js.map +1 -1
- package/dist/v2/components/code-input/CodeInput.vue.d.ts.map +1 -1
- package/dist/v2/components/code-input/CodeInput.vue.js +1 -1
- package/dist/v2/components/code-input/CodeInput.vue.js.map +1 -1
- package/dist/v2/components/code-input/CodeInput.vue.script.js.map +1 -1
- package/dist/v2/components/data-table/DataTableInput.vue.d.ts.map +1 -1
- package/dist/v2/components/data-table/DataTableInput.vue.js +1 -1
- package/dist/v2/components/data-table/DataTableInput.vue.js.map +1 -1
- package/dist/v2/components/data-table/DataTableInput.vue.script.js +15 -11
- package/dist/v2/components/data-table/DataTableInput.vue.script.js.map +1 -1
- package/dist/v2/components/server/ServerDropdown.vue.d.ts.map +1 -1
- package/dist/v2/components/server/ServerDropdown.vue.js.map +1 -1
- package/dist/v2/components/server/ServerDropdown.vue.script.js +1 -1
- package/dist/v2/components/server/ServerDropdown.vue.script.js.map +1 -1
- package/dist/v2/constants.js +1 -1
- package/dist/v2/features/localization/locales/ar.d.ts +3 -0
- package/dist/v2/features/localization/locales/ar.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/ar.js +4 -1
- package/dist/v2/features/localization/locales/ar.js.map +1 -1
- package/dist/v2/features/localization/locales/de.d.ts +3 -0
- package/dist/v2/features/localization/locales/de.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/de.js +4 -1
- package/dist/v2/features/localization/locales/de.js.map +1 -1
- package/dist/v2/features/localization/locales/es.d.ts +3 -0
- package/dist/v2/features/localization/locales/es.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/es.js +4 -1
- package/dist/v2/features/localization/locales/es.js.map +1 -1
- package/dist/v2/features/localization/locales/fr.d.ts +3 -0
- package/dist/v2/features/localization/locales/fr.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/fr.js +4 -1
- package/dist/v2/features/localization/locales/fr.js.map +1 -1
- package/dist/v2/features/localization/locales/pt.d.ts +3 -0
- package/dist/v2/features/localization/locales/pt.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/pt.js +4 -1
- package/dist/v2/features/localization/locales/pt.js.map +1 -1
- package/dist/v2/features/localization/locales/ru.d.ts +3 -0
- package/dist/v2/features/localization/locales/ru.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/ru.js +4 -1
- package/dist/v2/features/localization/locales/ru.js.map +1 -1
- package/dist/v2/features/localization/locales/zh-cn.d.ts +3 -0
- package/dist/v2/features/localization/locales/zh-cn.d.ts.map +1 -1
- package/dist/v2/features/localization/locales/zh-cn.js +4 -1
- package/dist/v2/features/localization/locales/zh-cn.js.map +1 -1
- package/dist/v2/features/localization/translations.d.ts +3 -0
- package/dist/v2/features/localization/translations.d.ts.map +1 -1
- package/dist/v2/features/localization/translations.js +4 -1
- package/dist/v2/features/localization/translations.js.map +1 -1
- package/dist/v2/workspace-events.d.ts.map +1 -1
- package/dist/v2/workspace-events.js +1 -0
- package/dist/v2/workspace-events.js.map +1 -1
- package/dist/vue-styles.css +29 -31
- package/package.json +11 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OperationBlock.vue.script.js","names":["$emit"],"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: string\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 /** Operation before downloaded examples are overlaid, for parameter edit targets. */\n sourceOperation?: 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 { isForbiddenHttpMethod } from '@scalar/helpers/http/is-forbidden-http-method'\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 {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n ref,\n toValue,\n watch,\n} 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 { useLocalization } from '@/v2/features/localization'\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 sourceOperation,\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\nconst { translate } = useLocalization()\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 requestError = ref<Error | 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 openapiVersion: document.openapi,\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 requestError.value = null\n eventBus.flushDebouncedEmits?.()\n // Source edits must reach the overlaid operation prop before building the request.\n await nextTick()\n\n if (isWebhook && !requestPath.value.trim()) {\n toast(translate('apiClient.operationBlock.webhookUrlRequired'), 'error')\n return\n }\n\n const pathValidation = validatePathParameters(\n operation.parameters ?? [],\n exampleKey,\n )\n if (pathValidation.ok === false) {\n toast(translate('apiClient.operationBlock.pathParametersRequired'), '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 openapiVersion: document.openapi,\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 // Check the final method because pre-request scripts can change it.\n const requestMethod = built.data.requestPayload[1].method ?? 'GET'\n if (isForbiddenHttpMethod(requestMethod)) {\n persistScriptEnvironment()\n toast(\n translate('apiClient.operationBlock.forbiddenMethod', {\n method: requestMethod.toUpperCase(),\n }),\n 'error',\n )\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 // Cancellation also happens when navigating away; keep the new operation intact.\n if (built.data.controller.signal.aborted) {\n if (abortController.value === built.data.controller) {\n abortController.value = null\n }\n return\n }\n requestError.value = 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 string,\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 requestError.value = null\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 requestError.value = null\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 :openapiVersion=\"document.openapi\"\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 :sourceOperation\n :workspaceCookies />\n\n <!-- Response Section -->\n <ResponseBlock\n :appVersion\n :eventBus\n :executionDisabled=\"externalExamplesPending\"\n :layout\n :plugins\n :requestError\n :requestPayload\n :response\n :totalPerformedRequests=\"operationHistory.length\" />\n </ViewLayoutContent>\n </ViewLayout>\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"OperationBlock.vue.script.js","names":["$emit"],"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: string\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 /** Operation before downloaded examples are overlaid, for parameter edit targets. */\n sourceOperation?: 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 { isForbiddenHttpMethod } from '@scalar/helpers/http/is-forbidden-http-method'\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 {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n ref,\n toValue,\n watch,\n} 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 { useLocalization } from '@/v2/features/localization'\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 sourceOperation,\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\nconst { translate } = useLocalization()\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 requestError = ref<Error | 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 openapiVersion: document.openapi,\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 requestError.value = null\n eventBus.flushDebouncedEmits?.()\n // Source edits must reach the overlaid operation prop before building the request.\n await nextTick()\n\n if (isWebhook && !requestPath.value.trim()) {\n toast(translate('apiClient.operationBlock.webhookUrlRequired'), 'error')\n return\n }\n\n const pathValidation = validatePathParameters(\n operation.parameters ?? [],\n exampleKey,\n )\n if (pathValidation.ok === false) {\n toast(translate('apiClient.operationBlock.pathParametersRequired'), '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 openapiVersion: document.openapi,\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 // Check the final method because pre-request scripts can change it.\n const requestMethod = built.data.requestPayload[1].method ?? 'GET'\n if (isForbiddenHttpMethod(requestMethod)) {\n persistScriptEnvironment()\n toast(\n translate('apiClient.operationBlock.forbiddenMethod', {\n method: requestMethod.toUpperCase(),\n }),\n 'error',\n )\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 // Cancellation also happens when navigating away; keep the new operation intact.\n if (built.data.controller.signal.aborted) {\n if (abortController.value === built.data.controller) {\n abortController.value = null\n }\n return\n }\n requestError.value = 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 string,\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 requestError.value = null\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 requestError.value = null\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 min-w-0 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 :openapiVersion=\"document.openapi\"\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 :sourceOperation\n :workspaceCookies />\n\n <!-- Response Section -->\n <ResponseBlock\n :appVersion\n :eventBus\n :executionDisabled=\"externalExamplesPending\"\n :layout\n :plugins\n :requestError\n :requestPayload\n :response\n :totalPerformedRequests=\"operationHistory.length\" />\n </ViewLayoutContent>\n </ViewLayout>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestBody.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestBody.vue"],"names":[],"mappings":"AAmmBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AACnH,OAAO,KAAK,EACV,iBAAiB,EAElB,MAAM,8DAA8D,CAAA;AAmBrE,KAAK,WAAW,GAAG;IACjB,mBAAmB;IACnB,WAAW,CAAC,EAAE,iBAAiB,CAAA;IAC/B,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAA;IAClB,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,2BAA2B;IAC3B,WAAW,EAAE,kBAAkB,CAAA;IAC/B,+DAA+D;IAC/D,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,sEAAsE;IACtE,+BAA+B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACxD;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;CAC7B,CAAC;
|
|
1
|
+
{"version":3,"file":"RequestBody.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestBody.vue"],"names":[],"mappings":"AAmmBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2EAA2E,CAAA;AACnH,OAAO,KAAK,EACV,iBAAiB,EAElB,MAAM,8DAA8D,CAAA;AAmBrE,KAAK,WAAW,GAAG;IACjB,mBAAmB;IACnB,WAAW,CAAC,EAAE,iBAAiB,CAAA;IAC/B,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAA;IAClB,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,2BAA2B;IAC3B,WAAW,EAAE,kBAAkB,CAAA;IAC/B,+DAA+D;IAC/D,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,sEAAsE;IACtE,+BAA+B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACxD;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;CAC7B,CAAC;AA83BF,QAAA,MAAM,YAAY;;;;;;+BAh8BlB,CAxRwD;mBAwRxD,CAvRA;;;;;;;;;;;eAsW8C,MAAM;;;qBAuBF,MAAM;;;;;;;;+BAtGxD,CAxRwD;mBAwRxD,CAvRA;;;;;;;;;;;eAsW8C,MAAM;;;qBAuBF,MAAM;;kFA61BtD,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -2,7 +2,7 @@ import _plugin_vue_export_helper_default from "../../../../_virtual/_plugin-vue_
|
|
|
2
2
|
import RequestBody_vue_vue_type_script_setup_true_lang_default from "./RequestBody.vue.script.js";
|
|
3
3
|
/* empty css */
|
|
4
4
|
//#region src/v2/blocks/request-block/components/RequestBody.vue
|
|
5
|
-
var RequestBody_default = /*#__PURE__*/ _plugin_vue_export_helper_default(RequestBody_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-
|
|
5
|
+
var RequestBody_default = /*#__PURE__*/ _plugin_vue_export_helper_default(RequestBody_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-bf90c7e1"]]);
|
|
6
6
|
//#endregion
|
|
7
7
|
export { RequestBody_default as default };
|
|
8
8
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestBody.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestBody.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarCodeBlockCopy } from '@scalar/components/code-block'\nimport { ScalarCopyBackdrop } from '@scalar/components/copy'\nimport { ScalarIcon } from '@scalar/components/icon'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarListbox } from '@scalar/components/listbox'\nimport { CONTENT_TYPES } from '@scalar/helpers/http/content-types'\nimport { isXmlMediaType } from '@scalar/helpers/http/is-xml-media-type'\nimport { parseMimeType } from '@scalar/helpers/http/mime-type'\nimport { isObject } from '@scalar/helpers/object/is-object'\nimport { objectEntries } from '@scalar/helpers/object/object-entries'\nimport { ScalarIconMagicWand } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport {\n getExampleValue,\n getExplicitExampleText,\n} from '@scalar/workspace-store/helpers/get-example-value'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n getExampleFromBody,\n getSchemaExampleFromBody,\n getSelectedBodyContentType,\n} from '@scalar/workspace-store/request-example'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n RequestBodyObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { isObjectSchema } from '@scalar/workspace-store/schemas/v3.2/strict/type-guards'\nimport { computed, ref, watch } from 'vue'\n\nimport { useFileDialog } from '@/hooks/use-file-dialog'\nimport RequestBodyForm from '@/v2/blocks/request-block/components/RequestBodyForm.vue'\nimport RequestBodyStructured from '@/v2/blocks/request-block/components/RequestBodyStructured.vue'\nimport RequestBodyViewToggle from '@/v2/blocks/request-block/components/RequestBodyViewToggle.vue'\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { getStructuredBodyCodec } from '@/v2/blocks/request-block/helpers/structured-body-codec'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTable,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\nimport { useLocalization } from '@/v2/features/localization'\n\nconst {\n requestBody,\n exampleKey,\n environment,\n requestBodyCompositionSelection,\n openapiVersion,\n title,\n defaultView = 'raw',\n} = defineProps<{\n /** Request body */\n requestBody?: RequestBodyObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Display title */\n title: string\n /** Selected environment */\n environment: XScalarEnvironment\n /** Originating OpenAPI version, used for XML mapping rules. */\n openapiVersion?: string\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n /**\n * Initial view for structured (JSON/YAML) bodies. Comes from the\n * `x-scalar-default-request-body-view` document extension and falls back to `raw`\n * whenever the body cannot be shown as a form.\n */\n defaultView?: 'form' | 'raw'\n}>()\n\nconst emits = defineEmits<{\n (e: 'update:contentType', payload: { value: string }): void\n /** We use this event to update raw values */\n (\n e: 'update:value',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n >,\n ): void\n /** We use this event when updating form data only */\n (\n e: 'update:formValue',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n >,\n ): void\n /**\n * Create a new example seeded with values generated from the request body schema.\n *\n * The block itself owns the document and operation identity needed to create an example, so we\n * only report the content type the user is currently looking at.\n */\n (e: 'generate:example', payload: { contentType: string }): void\n}>()\n\nconst { translate } = useLocalization()\n\n// Map a content type to a language for the code editor\nconst contentTypeToLanguageMap = {\n 'application/json': 'json',\n 'application/xml': 'xml',\n 'application/yaml': 'yaml',\n} as const\n\n/** Selected content type with default */\nconst selectedContentType = computed(\n () => getSelectedBodyContentType(requestBody, exampleKey) ?? 'none',\n)\n\n/** Keep the editor and copy label aligned with the selected content type. */\nconst selectedLanguage = computed(() =>\n isXmlMediaType(selectedContentType.value)\n ? 'xml'\n : (contentTypeToLanguageMap[\n selectedContentType.value as keyof typeof contentTypeToLanguageMap\n ] ?? 'plaintext'),\n)\n\n/**\n * Strips MIME parameters (such as `charset=utf-8`) for dropdown labels, aligned with how we treat\n * media types elsewhere (see api-reference `normalizeMimeType` / WHATWG essence).\n */\nconst contentTypeLabel = (raw: string): string => parseMimeType(raw).essence\n\n/**\n * Build the dropdown options for the content type selector.\n *\n * The list is composed of two groups:\n * 1. The built-in content types we ship friendly labels for (JSON, XML, Multipart Form, etc.).\n * 2. Any additional content types defined on the OpenAPI request body that are not in the built-in list\n * (for example `text/csv`, `application/pdf`, vendor types like `application/vnd.api+json`, ...).\n *\n * The OpenAPI-defined extras are appended at the bottom so the well-known options stay on top, and\n * users can always pick the exact content type the operation actually accepts.\n */\n/** MIME values remain stable while their human-readable labels follow the locale. */\nconst localizedContentTypes = computed(() => ({\n ...CONTENT_TYPES,\n 'multipart/form-data': translate('apiClient.requestBody.multipartForm'),\n 'application/x-www-form-urlencoded': translate(\n 'apiClient.requestBody.formUrlEncoded',\n ),\n 'application/octet-stream': translate('apiClient.requestBody.binaryFile'),\n 'other': translate('apiClient.requestBody.other'),\n 'none': translate('apiClient.requestBody.none'),\n}))\n\nconst contentTypeOptions = computed<{ id: string; label: string }[]>(() => {\n const builtIn = objectEntries(localizedContentTypes.value).map(\n ([id, label]) => ({\n id,\n label,\n }),\n )\n\n const extras = Object.keys(requestBody?.content ?? {})\n .filter((type) => {\n if (type in CONTENT_TYPES) {\n return false\n }\n // Same essence as a built-in (e.g. `application/json; charset=utf-8`) — do not duplicate the row.\n return !(contentTypeLabel(type) in CONTENT_TYPES)\n })\n .map((type) => ({ id: type, label: contentTypeLabel(type) }))\n\n return [...builtIn, ...extras]\n})\n\nconst selectedContentTypeModel = computed<{ id: string; label: string }>({\n get: () => {\n const found = contentTypeOptions.value.find(\n (it) => it.id === selectedContentType.value,\n )\n if (found) {\n return found\n }\n\n const essence = contentTypeLabel(selectedContentType.value)\n const friendly =\n localizedContentTypes.value[essence as keyof typeof CONTENT_TYPES] ??\n essence\n\n return {\n id: selectedContentType.value,\n label: friendly,\n }\n },\n set: (v) => {\n emits('update:contentType', { value: v.id })\n },\n})\n\nfunction handleFileUpload(callback: (file: File) => void) {\n const { open } = useFileDialog({\n onChange: (files) => {\n const file = files?.[0]\n if (file) {\n callback(file)\n }\n },\n multiple: false,\n accept: '*/*',\n })\n open()\n}\n\n/** Dereferenced example */\nconst example = computed(\n () =>\n requestBody &&\n getExampleFromBody(\n requestBody,\n selectedContentType.value,\n exampleKey,\n requestBodyCompositionSelection,\n openapiVersion,\n ),\n)\n\n/** Convert the example value to a string for the code editor */\nconst bodyValue = computed(() => {\n if (!example.value) {\n return ''\n }\n\n const selected = getExampleValue(example.value)\n const explicitText = getExplicitExampleText(\n selected,\n selectedContentType.value,\n 2,\n )\n if (explicitText !== undefined) {\n return explicitText\n }\n const value = selected?.value\n if (typeof value === 'string') {\n return value\n }\n\n return JSON.stringify(value, null, 2)\n})\n\n/** Resolved schema for the request body */\nconst bodySchema = computed<SchemaObject | undefined>(() => {\n return resolve.schema(\n requestBody?.content?.[selectedContentType.value]?.schema ??\n requestBody?.content?.[selectedContentType.value]?.itemSchema,\n )\n})\n\n/** Codec for structured (JSON/YAML) bodies, undefined for everything else */\nconst structuredCodec = computed(() =>\n selectedContentType.value === 'none'\n ? undefined\n : getStructuredBodyCodec(selectedContentType.value),\n)\n\n/** Parsed body value for the form view — `ok: false` when the raw text is not parseable */\nconst parsedBody = computed<{ ok: boolean; value?: unknown }>(() => {\n const codec = structuredCodec.value\n if (!codec) {\n return { ok: false }\n }\n\n const selected = getExampleValue(example.value ?? undefined)\n // Structured data is already parsed; parsing strings again changes the payload type.\n if (example.value?.dataValue !== undefined) {\n return { ok: true, value: example.value.dataValue }\n }\n const raw = selected?.value\n // An empty body is still form-editable: rows come from the schema.\n if (raw === undefined || raw === null || raw === '') {\n return { ok: true, value: {} }\n }\n if (typeof raw === 'string') {\n try {\n return { ok: true, value: codec.parse(raw) }\n } catch {\n return { ok: false }\n }\n }\n // Spec-provided examples can be stored as objects directly.\n return { ok: true, value: raw }\n})\n\n/**\n * An edited example normally takes precedence over schema-generated data. When a different\n * composition branch is selected, however, keeping that example leaves the editor showing the\n * previous branch. Track the selection itself instead of inspecting discriminator fields so this\n * also works for compositions whose members are distinguished only by their shape.\n */\nconst compositionSelectionKey = computed(() =>\n JSON.stringify(requestBodyCompositionSelection ?? {}),\n)\n\n// Switching operations changes the body (and often the selection) at once, which is not a branch\n// change, so we only regenerate the body when the selection changes while the operation and example\n// stay the same. Watching all three together and comparing against the watcher's own previous values\n// keeps this correct regardless of the order in which props update or watchers flush.\nwatch(\n [() => requestBody, () => exampleKey, compositionSelectionKey],\n (\n [, , selection],\n [previousRequestBody, previousExampleKey, previousSelection],\n ) => {\n const operationChanged =\n requestBody !== previousRequestBody || exampleKey !== previousExampleKey\n const selectionChanged = selection !== previousSelection\n\n // Going from no selection to a populated one is the modal applying the reference's selection as\n // the panel opens, not the user switching branches. Resetting here would discard the body's named\n // example on the very first open (issue #10075), so only a change between two populated selections\n // counts as a real branch switch.\n const hadNoPreviousSelection = previousSelection === '{}'\n\n // Only a genuine branch switch within the same operation should reset the edited body. An empty\n // selection means there is no composition to switch between (or the selection was cleared on an\n // operation change), so there is nothing to reset.\n if (\n operationChanged ||\n !selectionChanged ||\n hadNoPreviousSelection ||\n Object.keys(requestBodyCompositionSelection ?? {}).length === 0\n ) {\n return\n }\n\n const codec = structuredCodec.value\n const isXml = isXmlMediaType(selectedContentType.value)\n if (!requestBody || (!codec && !isXml)) {\n return\n }\n\n // Regenerate through the same helper the initial example uses so a reset produces exactly the\n // value a fresh render of this branch would, rather than a hand-copied second code path.\n const selectedValue = getSchemaExampleFromBody(\n requestBody,\n selectedContentType.value,\n requestBodyCompositionSelection,\n openapiVersion,\n )\n\n emits('update:value', {\n // A branch with no writable content generates `null`/`undefined`; clear the editor rather than\n // writing the literal text `null` or leaving the previously selected branch's body behind.\n payload:\n selectedValue == null\n ? ''\n : isXml\n ? String(selectedValue)\n : codec!.stringify(selectedValue),\n contentType: selectedContentType.value,\n })\n },\n)\n\n/** The form view only works on an object-shaped body root */\nconst isFormViewAvailable = computed(\n () => parsedBody.value.ok && isObject(parsedBody.value.value),\n)\n\n/**\n * Show the Form/Raw toggle for structured bodies that are (or per schema should be)\n * an object at the root. Non-object roots (arrays, primitives) stay raw-only.\n */\nconst showBodyViewToggle = computed(\n () =>\n Boolean(structuredCodec.value) &&\n (isFormViewAvailable.value ||\n Boolean(bodySchema.value && isObjectSchema(bodySchema.value))),\n)\n\n/** Selected body view, seeded from the document default (raw unless configured) */\nconst bodyView = ref<'form' | 'raw'>(defaultView)\n\n// Fall back to raw when the form view stops being available (e.g. the content type\n// changed to a non-structured one, or an external edit made the body unparseable).\nwatch(isFormViewAvailable, (ok) => {\n if (!ok) {\n bodyView.value = 'raw'\n }\n})\n\n/**\n * Whether we can offer to generate a fresh example from the schema.\n *\n * Only structured (JSON/YAML) bodies qualify: they have a schema to generate from and a text\n * representation we can seed the new example with. Binary and form bodies have their own editors,\n * so the button would have nothing meaningful to write.\n */\nconst canGenerateExample = computed(() =>\n Boolean(structuredCodec.value && bodySchema.value),\n)\n</script>\n<template>\n <CollapsibleSection>\n <template #title>{{ title }}</template>\n <DataTable\n :columns=\"['']\"\n presentational>\n <DataTableHeader\n class=\"relative col-span-full flex h-8 cursor-pointer items-center justify-between border-r-0 !p-0\">\n <ScalarListbox\n v-model=\"selectedContentTypeModel\"\n :options=\"contentTypeOptions\"\n teleport>\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-3 font-normal\"\n fullWidth\n variant=\"ghost\">\n <span>{{ selectedContentTypeModel.label }}</span>\n <ScalarIcon\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n <div class=\"flex items-center gap-1\">\n <!--\n Generates a new example from the schema so the auto-generated fields stay reachable\n even once the document ships custom examples.\n -->\n <ScalarIconButton\n v-if=\"canGenerateExample\"\n aria-label=\"Generate example from schema\"\n :icon=\"ScalarIconMagicWand\"\n label=\"Generate example from schema\"\n size=\"sm\"\n tooltip\n @click.stop=\"\n emits('generate:example', { contentType: selectedContentType })\n \" />\n <RequestBodyViewToggle\n v-if=\"showBodyViewToggle\"\n :disabled=\"!isFormViewAvailable\"\n :modelValue=\"bodyView\"\n @update:modelValue=\"(v) => (bodyView = v)\" />\n </div>\n </DataTableHeader>\n <DataTableRow>\n <!-- No Body -->\n <template v-if=\"selectedContentType === 'none'\">\n <div\n class=\"text-c-3 flex min-h-10 w-full items-center justify-center border-t p-2 text-sm\">\n <span>{{ translate('apiClient.requestBody.noBody') }}</span>\n </div>\n </template>\n\n <!-- Binary File -->\n <template\n v-else-if=\"selectedContentType === 'application/octet-stream'\">\n <div\n class=\"flex items-center justify-center overflow-hidden border-t p-1.5\">\n <template\n v-if=\"\n getFileName(unpackProxyObject(example?.value)) !== undefined\n \">\n <span\n class=\"text-c-2 w-full max-w-full overflow-hidden rounded border px-1.5 py-1 text-xs whitespace-nowrap\">\n {{ getFileName(unpackProxyObject(example?.value)) }}\n </span>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 ml-1 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n emits('update:value', {\n payload: undefined,\n contentType: selectedContentType,\n })\n \">\n {{ translate('apiClient.requestBody.delete') }}\n </ScalarButton>\n </template>\n <template v-else>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n () =>\n handleFileUpload((file) =>\n emits('update:value', {\n payload: file,\n contentType: selectedContentType,\n }),\n )\n \">\n <span>{{ translate('apiClient.requestBody.selectFile') }}</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </template>\n </div>\n </template>\n\n <!-- Form Data / URL Encoded -->\n <template\n v-else-if=\"\n selectedContentType === 'multipart/form-data' ||\n selectedContentType === 'application/x-www-form-urlencoded'\n \">\n <RequestBodyForm\n :bodySchema\n :environment\n :example\n :selectedContentType\n @update:formValue=\"\n (payload) =>\n emits('update:formValue', {\n payload,\n contentType: selectedContentType,\n })\n \" />\n </template>\n\n <!-- Code/Other -->\n <template v-else>\n <!-- Schema-driven form view for structured (JSON/YAML) bodies -->\n <RequestBodyStructured\n v-if=\"bodyView === 'form' && isFormViewAvailable\"\n :bodySchema\n :contentType=\"selectedContentType\"\n :environment\n :parsedValue=\"parsedBody.value\"\n @update:value=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n <!-- Editable raw body with a copy button revealed on hover/focus -->\n <div\n v-else\n class=\"group/code-block relative border-t\">\n <CodeInput\n class=\"px-3\"\n content=\"\"\n :environment=\"environment\"\n :language=\"selectedLanguage\"\n lineNumbers\n lint\n :modelValue=\"bodyValue\"\n withFakeData\n @update:modelValue=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n <ScalarCodeBlockCopy\n v-if=\"bodyValue\"\n class=\"absolute top-1.5 right-1.5\"\n :content=\"bodyValue\"\n :lang=\"selectedLanguage\"\n showLang>\n <template #backdrop>\n <ScalarCopyBackdrop class=\"-top-1 -right-1.5\" />\n </template>\n </ScalarCodeBlockCopy>\n </div>\n </template>\n </DataTableRow>\n </DataTable>\n </CollapsibleSection>\n</template>\n<style scoped>\n:deep(.cm-content) {\n font-size: var(--scalar-small);\n}\n</style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"RequestBody.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestBody.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarCodeBlockCopy } from '@scalar/components/code-block'\nimport { ScalarCopyBackdrop } from '@scalar/components/copy'\nimport { ScalarIcon } from '@scalar/components/icon'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarListbox } from '@scalar/components/listbox'\nimport { CONTENT_TYPES } from '@scalar/helpers/http/content-types'\nimport { isXmlMediaType } from '@scalar/helpers/http/is-xml-media-type'\nimport { parseMimeType } from '@scalar/helpers/http/mime-type'\nimport { isObject } from '@scalar/helpers/object/is-object'\nimport { objectEntries } from '@scalar/helpers/object/object-entries'\nimport { ScalarIconMagicWand } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport {\n getExampleValue,\n getExplicitExampleText,\n} from '@scalar/workspace-store/helpers/get-example-value'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n getExampleFromBody,\n getSchemaExampleFromBody,\n getSelectedBodyContentType,\n} from '@scalar/workspace-store/request-example'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n RequestBodyObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { isObjectSchema } from '@scalar/workspace-store/schemas/v3.2/strict/type-guards'\nimport { computed, ref, watch } from 'vue'\n\nimport { useFileDialog } from '@/hooks/use-file-dialog'\nimport RequestBodyForm from '@/v2/blocks/request-block/components/RequestBodyForm.vue'\nimport RequestBodyStructured from '@/v2/blocks/request-block/components/RequestBodyStructured.vue'\nimport RequestBodyViewToggle from '@/v2/blocks/request-block/components/RequestBodyViewToggle.vue'\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { getStructuredBodyCodec } from '@/v2/blocks/request-block/helpers/structured-body-codec'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTable,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\nimport { useLocalization } from '@/v2/features/localization'\n\nconst {\n requestBody,\n exampleKey,\n environment,\n requestBodyCompositionSelection,\n openapiVersion,\n title,\n defaultView = 'raw',\n} = defineProps<{\n /** Request body */\n requestBody?: RequestBodyObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Display title */\n title: string\n /** Selected environment */\n environment: XScalarEnvironment\n /** Originating OpenAPI version, used for XML mapping rules. */\n openapiVersion?: string\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n /**\n * Initial view for structured (JSON/YAML) bodies. Comes from the\n * `x-scalar-default-request-body-view` document extension and falls back to `raw`\n * whenever the body cannot be shown as a form.\n */\n defaultView?: 'form' | 'raw'\n}>()\n\nconst emits = defineEmits<{\n (e: 'update:contentType', payload: { value: string }): void\n /** We use this event to update raw values */\n (\n e: 'update:value',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n >,\n ): void\n /** We use this event when updating form data only */\n (\n e: 'update:formValue',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n >,\n ): void\n /**\n * Create a new example seeded with values generated from the request body schema.\n *\n * The block itself owns the document and operation identity needed to create an example, so we\n * only report the content type the user is currently looking at.\n */\n (e: 'generate:example', payload: { contentType: string }): void\n}>()\n\nconst { translate } = useLocalization()\n\n// Map a content type to a language for the code editor\nconst contentTypeToLanguageMap = {\n 'application/json': 'json',\n 'application/xml': 'xml',\n 'application/yaml': 'yaml',\n} as const\n\n/** Selected content type with default */\nconst selectedContentType = computed(\n () => getSelectedBodyContentType(requestBody, exampleKey) ?? 'none',\n)\n\n/** Keep the editor and copy label aligned with the selected content type. */\nconst selectedLanguage = computed(() =>\n isXmlMediaType(selectedContentType.value)\n ? 'xml'\n : (contentTypeToLanguageMap[\n selectedContentType.value as keyof typeof contentTypeToLanguageMap\n ] ?? 'plaintext'),\n)\n\n/**\n * Strips MIME parameters (such as `charset=utf-8`) for dropdown labels, aligned with how we treat\n * media types elsewhere (see api-reference `normalizeMimeType` / WHATWG essence).\n */\nconst contentTypeLabel = (raw: string): string => parseMimeType(raw).essence\n\n/**\n * Build the dropdown options for the content type selector.\n *\n * The list is composed of two groups:\n * 1. The built-in content types we ship friendly labels for (JSON, XML, Multipart Form, etc.).\n * 2. Any additional content types defined on the OpenAPI request body that are not in the built-in list\n * (for example `text/csv`, `application/pdf`, vendor types like `application/vnd.api+json`, ...).\n *\n * The OpenAPI-defined extras are appended at the bottom so the well-known options stay on top, and\n * users can always pick the exact content type the operation actually accepts.\n */\n/** MIME values remain stable while their human-readable labels follow the locale. */\nconst localizedContentTypes = computed(() => ({\n ...CONTENT_TYPES,\n 'multipart/form-data': translate('apiClient.requestBody.multipartForm'),\n 'application/x-www-form-urlencoded': translate(\n 'apiClient.requestBody.formUrlEncoded',\n ),\n 'application/octet-stream': translate('apiClient.requestBody.binaryFile'),\n 'other': translate('apiClient.requestBody.other'),\n 'none': translate('apiClient.requestBody.none'),\n}))\n\nconst contentTypeOptions = computed<{ id: string; label: string }[]>(() => {\n const builtIn = objectEntries(localizedContentTypes.value).map(\n ([id, label]) => ({\n id,\n label,\n }),\n )\n\n const extras = Object.keys(requestBody?.content ?? {})\n .filter((type) => {\n if (type in CONTENT_TYPES) {\n return false\n }\n // Same essence as a built-in (e.g. `application/json; charset=utf-8`) — do not duplicate the row.\n return !(contentTypeLabel(type) in CONTENT_TYPES)\n })\n .map((type) => ({ id: type, label: contentTypeLabel(type) }))\n\n return [...builtIn, ...extras]\n})\n\nconst selectedContentTypeModel = computed<{ id: string; label: string }>({\n get: () => {\n const found = contentTypeOptions.value.find(\n (it) => it.id === selectedContentType.value,\n )\n if (found) {\n return found\n }\n\n const essence = contentTypeLabel(selectedContentType.value)\n const friendly =\n localizedContentTypes.value[essence as keyof typeof CONTENT_TYPES] ??\n essence\n\n return {\n id: selectedContentType.value,\n label: friendly,\n }\n },\n set: (v) => {\n emits('update:contentType', { value: v.id })\n },\n})\n\nfunction handleFileUpload(callback: (file: File) => void) {\n const { open } = useFileDialog({\n onChange: (files) => {\n const file = files?.[0]\n if (file) {\n callback(file)\n }\n },\n multiple: false,\n accept: '*/*',\n })\n open()\n}\n\n/** Dereferenced example */\nconst example = computed(\n () =>\n requestBody &&\n getExampleFromBody(\n requestBody,\n selectedContentType.value,\n exampleKey,\n requestBodyCompositionSelection,\n openapiVersion,\n ),\n)\n\n/** Convert the example value to a string for the code editor */\nconst bodyValue = computed(() => {\n if (!example.value) {\n return ''\n }\n\n const selected = getExampleValue(example.value)\n const explicitText = getExplicitExampleText(\n selected,\n selectedContentType.value,\n 2,\n )\n if (explicitText !== undefined) {\n return explicitText\n }\n const value = selected?.value\n if (typeof value === 'string') {\n return value\n }\n\n return JSON.stringify(value, null, 2)\n})\n\n/** Resolved schema for the request body */\nconst bodySchema = computed<SchemaObject | undefined>(() => {\n return resolve.schema(\n requestBody?.content?.[selectedContentType.value]?.schema ??\n requestBody?.content?.[selectedContentType.value]?.itemSchema,\n )\n})\n\n/** Codec for structured (JSON/YAML) bodies, undefined for everything else */\nconst structuredCodec = computed(() =>\n selectedContentType.value === 'none'\n ? undefined\n : getStructuredBodyCodec(selectedContentType.value),\n)\n\n/** Parsed body value for the form view — `ok: false` when the raw text is not parseable */\nconst parsedBody = computed<{ ok: boolean; value?: unknown }>(() => {\n const codec = structuredCodec.value\n if (!codec) {\n return { ok: false }\n }\n\n const selected = getExampleValue(example.value ?? undefined)\n // Structured data is already parsed; parsing strings again changes the payload type.\n if (example.value?.dataValue !== undefined) {\n return { ok: true, value: example.value.dataValue }\n }\n const raw = selected?.value\n // An empty body is still form-editable: rows come from the schema.\n if (raw === undefined || raw === null || raw === '') {\n return { ok: true, value: {} }\n }\n if (typeof raw === 'string') {\n try {\n return { ok: true, value: codec.parse(raw) }\n } catch {\n return { ok: false }\n }\n }\n // Spec-provided examples can be stored as objects directly.\n return { ok: true, value: raw }\n})\n\n/**\n * An edited example normally takes precedence over schema-generated data. When a different\n * composition branch is selected, however, keeping that example leaves the editor showing the\n * previous branch. Track the selection itself instead of inspecting discriminator fields so this\n * also works for compositions whose members are distinguished only by their shape.\n */\nconst compositionSelectionKey = computed(() =>\n JSON.stringify(requestBodyCompositionSelection ?? {}),\n)\n\n// Switching operations changes the body (and often the selection) at once, which is not a branch\n// change, so we only regenerate the body when the selection changes while the operation and example\n// stay the same. Watching all three together and comparing against the watcher's own previous values\n// keeps this correct regardless of the order in which props update or watchers flush.\nwatch(\n [() => requestBody, () => exampleKey, compositionSelectionKey],\n (\n [, , selection],\n [previousRequestBody, previousExampleKey, previousSelection],\n ) => {\n const operationChanged =\n requestBody !== previousRequestBody || exampleKey !== previousExampleKey\n const selectionChanged = selection !== previousSelection\n\n // Going from no selection to a populated one is the modal applying the reference's selection as\n // the panel opens, not the user switching branches. Resetting here would discard the body's named\n // example on the very first open (issue #10075), so only a change between two populated selections\n // counts as a real branch switch.\n const hadNoPreviousSelection = previousSelection === '{}'\n\n // Only a genuine branch switch within the same operation should reset the edited body. An empty\n // selection means there is no composition to switch between (or the selection was cleared on an\n // operation change), so there is nothing to reset.\n if (\n operationChanged ||\n !selectionChanged ||\n hadNoPreviousSelection ||\n Object.keys(requestBodyCompositionSelection ?? {}).length === 0\n ) {\n return\n }\n\n const codec = structuredCodec.value\n const isXml = isXmlMediaType(selectedContentType.value)\n if (!requestBody || (!codec && !isXml)) {\n return\n }\n\n // Regenerate through the same helper the initial example uses so a reset produces exactly the\n // value a fresh render of this branch would, rather than a hand-copied second code path.\n const selectedValue = getSchemaExampleFromBody(\n requestBody,\n selectedContentType.value,\n requestBodyCompositionSelection,\n openapiVersion,\n )\n\n emits('update:value', {\n // A branch with no writable content generates `null`/`undefined`; clear the editor rather than\n // writing the literal text `null` or leaving the previously selected branch's body behind.\n payload:\n selectedValue == null\n ? ''\n : isXml\n ? String(selectedValue)\n : codec!.stringify(selectedValue),\n contentType: selectedContentType.value,\n })\n },\n)\n\n/** The form view only works on an object-shaped body root */\nconst isFormViewAvailable = computed(\n () => parsedBody.value.ok && isObject(parsedBody.value.value),\n)\n\n/**\n * Show the Form/Raw toggle for structured bodies that are (or per schema should be)\n * an object at the root. Non-object roots (arrays, primitives) stay raw-only.\n */\nconst showBodyViewToggle = computed(\n () =>\n Boolean(structuredCodec.value) &&\n (isFormViewAvailable.value ||\n Boolean(bodySchema.value && isObjectSchema(bodySchema.value))),\n)\n\n/** Selected body view, seeded from the document default (raw unless configured) */\nconst bodyView = ref<'form' | 'raw'>(defaultView)\n\n// Fall back to raw when the form view stops being available (e.g. the content type\n// changed to a non-structured one, or an external edit made the body unparseable).\nwatch(isFormViewAvailable, (ok) => {\n if (!ok) {\n bodyView.value = 'raw'\n }\n})\n\n/**\n * Whether we can offer to generate a fresh example from the schema.\n *\n * Only structured (JSON/YAML) bodies qualify: they have a schema to generate from and a text\n * representation we can seed the new example with. Binary and form bodies have their own editors,\n * so the button would have nothing meaningful to write.\n */\nconst canGenerateExample = computed(() =>\n Boolean(structuredCodec.value && bodySchema.value),\n)\n</script>\n<template>\n <CollapsibleSection>\n <template #title>{{ title }}</template>\n <DataTable\n :columns=\"['']\"\n presentational>\n <DataTableHeader\n class=\"relative col-span-full flex h-8 cursor-pointer items-center justify-between border-r-0 !p-0\">\n <ScalarListbox\n v-model=\"selectedContentTypeModel\"\n :options=\"contentTypeOptions\"\n teleport>\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-3 font-normal\"\n fullWidth\n variant=\"ghost\">\n <span>{{ selectedContentTypeModel.label }}</span>\n <ScalarIcon\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n <div class=\"flex items-center gap-1\">\n <!--\n Generates a new example from the schema so the auto-generated fields stay reachable\n even once the document ships custom examples.\n -->\n <ScalarIconButton\n v-if=\"canGenerateExample\"\n aria-label=\"Generate example from schema\"\n :icon=\"ScalarIconMagicWand\"\n label=\"Generate example from schema\"\n size=\"sm\"\n tooltip\n @click.stop=\"\n emits('generate:example', { contentType: selectedContentType })\n \" />\n <RequestBodyViewToggle\n v-if=\"showBodyViewToggle\"\n :disabled=\"!isFormViewAvailable\"\n :modelValue=\"bodyView\"\n @update:modelValue=\"(v) => (bodyView = v)\" />\n </div>\n </DataTableHeader>\n <DataTableRow>\n <!-- No Body -->\n <template v-if=\"selectedContentType === 'none'\">\n <div\n class=\"text-c-3 flex min-h-10 w-full items-center justify-center border-t p-2 text-sm\">\n <span>{{ translate('apiClient.requestBody.noBody') }}</span>\n </div>\n </template>\n\n <!-- Binary File -->\n <template\n v-else-if=\"selectedContentType === 'application/octet-stream'\">\n <div\n class=\"flex items-center justify-center overflow-hidden border-t p-1.5\">\n <template\n v-if=\"\n getFileName(unpackProxyObject(example?.value)) !== undefined\n \">\n <span\n class=\"text-c-2 w-full max-w-full overflow-hidden rounded border px-1.5 py-1 text-xs whitespace-nowrap\">\n {{ getFileName(unpackProxyObject(example?.value)) }}\n </span>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 ml-1 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n emits('update:value', {\n payload: undefined,\n contentType: selectedContentType,\n })\n \">\n {{ translate('apiClient.requestBody.delete') }}\n </ScalarButton>\n </template>\n <template v-else>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n () =>\n handleFileUpload((file) =>\n emits('update:value', {\n payload: file,\n contentType: selectedContentType,\n }),\n )\n \">\n <span>{{ translate('apiClient.requestBody.selectFile') }}</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </template>\n </div>\n </template>\n\n <!-- Form Data / URL Encoded -->\n <template\n v-else-if=\"\n selectedContentType === 'multipart/form-data' ||\n selectedContentType === 'application/x-www-form-urlencoded'\n \">\n <RequestBodyForm\n :bodySchema\n :environment\n :example\n :selectedContentType\n @update:formValue=\"\n (payload) =>\n emits('update:formValue', {\n payload,\n contentType: selectedContentType,\n })\n \" />\n </template>\n\n <!-- Code/Other -->\n <template v-else>\n <!-- Schema-driven form view for structured (JSON/YAML) bodies -->\n <RequestBodyStructured\n v-if=\"bodyView === 'form' && isFormViewAvailable\"\n :bodySchema\n :contentType=\"selectedContentType\"\n :environment\n :parsedValue=\"parsedBody.value\"\n @update:value=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n <!-- Editable raw body with a copy button revealed on hover/focus -->\n <div\n v-else\n class=\"group/code-block relative min-w-0 border-t\">\n <CodeInput\n class=\"px-3\"\n content=\"\"\n :environment=\"environment\"\n :language=\"selectedLanguage\"\n lineNumbers\n lint\n :modelValue=\"bodyValue\"\n withFakeData\n @update:modelValue=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n <ScalarCodeBlockCopy\n v-if=\"bodyValue\"\n class=\"absolute top-1.5 right-1.5\"\n :content=\"bodyValue\"\n :lang=\"selectedLanguage\"\n showLang>\n <template #backdrop>\n <ScalarCopyBackdrop class=\"-top-1 -right-1.5\" />\n </template>\n </ScalarCodeBlockCopy>\n </div>\n </template>\n </DataTableRow>\n </DataTable>\n </CollapsibleSection>\n</template>\n<style scoped>\n:deep(.cm-content) {\n font-size: var(--scalar-small);\n}\n</style>\n"],"mappings":""}
|
|
@@ -41,7 +41,7 @@ var _hoisted_3 = {
|
|
|
41
41
|
var _hoisted_4 = { class: "text-c-2 w-full max-w-full overflow-hidden rounded border px-1.5 py-1 text-xs whitespace-nowrap" };
|
|
42
42
|
var _hoisted_5 = {
|
|
43
43
|
key: 1,
|
|
44
|
-
class: "group/code-block relative border-t"
|
|
44
|
+
class: "group/code-block relative min-w-0 border-t"
|
|
45
45
|
};
|
|
46
46
|
var RequestBody_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
47
47
|
__name: "RequestBody",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestBody.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestBody.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarCodeBlockCopy } from '@scalar/components/code-block'\nimport { ScalarCopyBackdrop } from '@scalar/components/copy'\nimport { ScalarIcon } from '@scalar/components/icon'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarListbox } from '@scalar/components/listbox'\nimport { CONTENT_TYPES } from '@scalar/helpers/http/content-types'\nimport { isXmlMediaType } from '@scalar/helpers/http/is-xml-media-type'\nimport { parseMimeType } from '@scalar/helpers/http/mime-type'\nimport { isObject } from '@scalar/helpers/object/is-object'\nimport { objectEntries } from '@scalar/helpers/object/object-entries'\nimport { ScalarIconMagicWand } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport {\n getExampleValue,\n getExplicitExampleText,\n} from '@scalar/workspace-store/helpers/get-example-value'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n getExampleFromBody,\n getSchemaExampleFromBody,\n getSelectedBodyContentType,\n} from '@scalar/workspace-store/request-example'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n RequestBodyObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { isObjectSchema } from '@scalar/workspace-store/schemas/v3.2/strict/type-guards'\nimport { computed, ref, watch } from 'vue'\n\nimport { useFileDialog } from '@/hooks/use-file-dialog'\nimport RequestBodyForm from '@/v2/blocks/request-block/components/RequestBodyForm.vue'\nimport RequestBodyStructured from '@/v2/blocks/request-block/components/RequestBodyStructured.vue'\nimport RequestBodyViewToggle from '@/v2/blocks/request-block/components/RequestBodyViewToggle.vue'\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { getStructuredBodyCodec } from '@/v2/blocks/request-block/helpers/structured-body-codec'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTable,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\nimport { useLocalization } from '@/v2/features/localization'\n\nconst {\n requestBody,\n exampleKey,\n environment,\n requestBodyCompositionSelection,\n openapiVersion,\n title,\n defaultView = 'raw',\n} = defineProps<{\n /** Request body */\n requestBody?: RequestBodyObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Display title */\n title: string\n /** Selected environment */\n environment: XScalarEnvironment\n /** Originating OpenAPI version, used for XML mapping rules. */\n openapiVersion?: string\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n /**\n * Initial view for structured (JSON/YAML) bodies. Comes from the\n * `x-scalar-default-request-body-view` document extension and falls back to `raw`\n * whenever the body cannot be shown as a form.\n */\n defaultView?: 'form' | 'raw'\n}>()\n\nconst emits = defineEmits<{\n (e: 'update:contentType', payload: { value: string }): void\n /** We use this event to update raw values */\n (\n e: 'update:value',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n >,\n ): void\n /** We use this event when updating form data only */\n (\n e: 'update:formValue',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n >,\n ): void\n /**\n * Create a new example seeded with values generated from the request body schema.\n *\n * The block itself owns the document and operation identity needed to create an example, so we\n * only report the content type the user is currently looking at.\n */\n (e: 'generate:example', payload: { contentType: string }): void\n}>()\n\nconst { translate } = useLocalization()\n\n// Map a content type to a language for the code editor\nconst contentTypeToLanguageMap = {\n 'application/json': 'json',\n 'application/xml': 'xml',\n 'application/yaml': 'yaml',\n} as const\n\n/** Selected content type with default */\nconst selectedContentType = computed(\n () => getSelectedBodyContentType(requestBody, exampleKey) ?? 'none',\n)\n\n/** Keep the editor and copy label aligned with the selected content type. */\nconst selectedLanguage = computed(() =>\n isXmlMediaType(selectedContentType.value)\n ? 'xml'\n : (contentTypeToLanguageMap[\n selectedContentType.value as keyof typeof contentTypeToLanguageMap\n ] ?? 'plaintext'),\n)\n\n/**\n * Strips MIME parameters (such as `charset=utf-8`) for dropdown labels, aligned with how we treat\n * media types elsewhere (see api-reference `normalizeMimeType` / WHATWG essence).\n */\nconst contentTypeLabel = (raw: string): string => parseMimeType(raw).essence\n\n/**\n * Build the dropdown options for the content type selector.\n *\n * The list is composed of two groups:\n * 1. The built-in content types we ship friendly labels for (JSON, XML, Multipart Form, etc.).\n * 2. Any additional content types defined on the OpenAPI request body that are not in the built-in list\n * (for example `text/csv`, `application/pdf`, vendor types like `application/vnd.api+json`, ...).\n *\n * The OpenAPI-defined extras are appended at the bottom so the well-known options stay on top, and\n * users can always pick the exact content type the operation actually accepts.\n */\n/** MIME values remain stable while their human-readable labels follow the locale. */\nconst localizedContentTypes = computed(() => ({\n ...CONTENT_TYPES,\n 'multipart/form-data': translate('apiClient.requestBody.multipartForm'),\n 'application/x-www-form-urlencoded': translate(\n 'apiClient.requestBody.formUrlEncoded',\n ),\n 'application/octet-stream': translate('apiClient.requestBody.binaryFile'),\n 'other': translate('apiClient.requestBody.other'),\n 'none': translate('apiClient.requestBody.none'),\n}))\n\nconst contentTypeOptions = computed<{ id: string; label: string }[]>(() => {\n const builtIn = objectEntries(localizedContentTypes.value).map(\n ([id, label]) => ({\n id,\n label,\n }),\n )\n\n const extras = Object.keys(requestBody?.content ?? {})\n .filter((type) => {\n if (type in CONTENT_TYPES) {\n return false\n }\n // Same essence as a built-in (e.g. `application/json; charset=utf-8`) — do not duplicate the row.\n return !(contentTypeLabel(type) in CONTENT_TYPES)\n })\n .map((type) => ({ id: type, label: contentTypeLabel(type) }))\n\n return [...builtIn, ...extras]\n})\n\nconst selectedContentTypeModel = computed<{ id: string; label: string }>({\n get: () => {\n const found = contentTypeOptions.value.find(\n (it) => it.id === selectedContentType.value,\n )\n if (found) {\n return found\n }\n\n const essence = contentTypeLabel(selectedContentType.value)\n const friendly =\n localizedContentTypes.value[essence as keyof typeof CONTENT_TYPES] ??\n essence\n\n return {\n id: selectedContentType.value,\n label: friendly,\n }\n },\n set: (v) => {\n emits('update:contentType', { value: v.id })\n },\n})\n\nfunction handleFileUpload(callback: (file: File) => void) {\n const { open } = useFileDialog({\n onChange: (files) => {\n const file = files?.[0]\n if (file) {\n callback(file)\n }\n },\n multiple: false,\n accept: '*/*',\n })\n open()\n}\n\n/** Dereferenced example */\nconst example = computed(\n () =>\n requestBody &&\n getExampleFromBody(\n requestBody,\n selectedContentType.value,\n exampleKey,\n requestBodyCompositionSelection,\n openapiVersion,\n ),\n)\n\n/** Convert the example value to a string for the code editor */\nconst bodyValue = computed(() => {\n if (!example.value) {\n return ''\n }\n\n const selected = getExampleValue(example.value)\n const explicitText = getExplicitExampleText(\n selected,\n selectedContentType.value,\n 2,\n )\n if (explicitText !== undefined) {\n return explicitText\n }\n const value = selected?.value\n if (typeof value === 'string') {\n return value\n }\n\n return JSON.stringify(value, null, 2)\n})\n\n/** Resolved schema for the request body */\nconst bodySchema = computed<SchemaObject | undefined>(() => {\n return resolve.schema(\n requestBody?.content?.[selectedContentType.value]?.schema ??\n requestBody?.content?.[selectedContentType.value]?.itemSchema,\n )\n})\n\n/** Codec for structured (JSON/YAML) bodies, undefined for everything else */\nconst structuredCodec = computed(() =>\n selectedContentType.value === 'none'\n ? undefined\n : getStructuredBodyCodec(selectedContentType.value),\n)\n\n/** Parsed body value for the form view — `ok: false` when the raw text is not parseable */\nconst parsedBody = computed<{ ok: boolean; value?: unknown }>(() => {\n const codec = structuredCodec.value\n if (!codec) {\n return { ok: false }\n }\n\n const selected = getExampleValue(example.value ?? undefined)\n // Structured data is already parsed; parsing strings again changes the payload type.\n if (example.value?.dataValue !== undefined) {\n return { ok: true, value: example.value.dataValue }\n }\n const raw = selected?.value\n // An empty body is still form-editable: rows come from the schema.\n if (raw === undefined || raw === null || raw === '') {\n return { ok: true, value: {} }\n }\n if (typeof raw === 'string') {\n try {\n return { ok: true, value: codec.parse(raw) }\n } catch {\n return { ok: false }\n }\n }\n // Spec-provided examples can be stored as objects directly.\n return { ok: true, value: raw }\n})\n\n/**\n * An edited example normally takes precedence over schema-generated data. When a different\n * composition branch is selected, however, keeping that example leaves the editor showing the\n * previous branch. Track the selection itself instead of inspecting discriminator fields so this\n * also works for compositions whose members are distinguished only by their shape.\n */\nconst compositionSelectionKey = computed(() =>\n JSON.stringify(requestBodyCompositionSelection ?? {}),\n)\n\n// Switching operations changes the body (and often the selection) at once, which is not a branch\n// change, so we only regenerate the body when the selection changes while the operation and example\n// stay the same. Watching all three together and comparing against the watcher's own previous values\n// keeps this correct regardless of the order in which props update or watchers flush.\nwatch(\n [() => requestBody, () => exampleKey, compositionSelectionKey],\n (\n [, , selection],\n [previousRequestBody, previousExampleKey, previousSelection],\n ) => {\n const operationChanged =\n requestBody !== previousRequestBody || exampleKey !== previousExampleKey\n const selectionChanged = selection !== previousSelection\n\n // Going from no selection to a populated one is the modal applying the reference's selection as\n // the panel opens, not the user switching branches. Resetting here would discard the body's named\n // example on the very first open (issue #10075), so only a change between two populated selections\n // counts as a real branch switch.\n const hadNoPreviousSelection = previousSelection === '{}'\n\n // Only a genuine branch switch within the same operation should reset the edited body. An empty\n // selection means there is no composition to switch between (or the selection was cleared on an\n // operation change), so there is nothing to reset.\n if (\n operationChanged ||\n !selectionChanged ||\n hadNoPreviousSelection ||\n Object.keys(requestBodyCompositionSelection ?? {}).length === 0\n ) {\n return\n }\n\n const codec = structuredCodec.value\n const isXml = isXmlMediaType(selectedContentType.value)\n if (!requestBody || (!codec && !isXml)) {\n return\n }\n\n // Regenerate through the same helper the initial example uses so a reset produces exactly the\n // value a fresh render of this branch would, rather than a hand-copied second code path.\n const selectedValue = getSchemaExampleFromBody(\n requestBody,\n selectedContentType.value,\n requestBodyCompositionSelection,\n openapiVersion,\n )\n\n emits('update:value', {\n // A branch with no writable content generates `null`/`undefined`; clear the editor rather than\n // writing the literal text `null` or leaving the previously selected branch's body behind.\n payload:\n selectedValue == null\n ? ''\n : isXml\n ? String(selectedValue)\n : codec!.stringify(selectedValue),\n contentType: selectedContentType.value,\n })\n },\n)\n\n/** The form view only works on an object-shaped body root */\nconst isFormViewAvailable = computed(\n () => parsedBody.value.ok && isObject(parsedBody.value.value),\n)\n\n/**\n * Show the Form/Raw toggle for structured bodies that are (or per schema should be)\n * an object at the root. Non-object roots (arrays, primitives) stay raw-only.\n */\nconst showBodyViewToggle = computed(\n () =>\n Boolean(structuredCodec.value) &&\n (isFormViewAvailable.value ||\n Boolean(bodySchema.value && isObjectSchema(bodySchema.value))),\n)\n\n/** Selected body view, seeded from the document default (raw unless configured) */\nconst bodyView = ref<'form' | 'raw'>(defaultView)\n\n// Fall back to raw when the form view stops being available (e.g. the content type\n// changed to a non-structured one, or an external edit made the body unparseable).\nwatch(isFormViewAvailable, (ok) => {\n if (!ok) {\n bodyView.value = 'raw'\n }\n})\n\n/**\n * Whether we can offer to generate a fresh example from the schema.\n *\n * Only structured (JSON/YAML) bodies qualify: they have a schema to generate from and a text\n * representation we can seed the new example with. Binary and form bodies have their own editors,\n * so the button would have nothing meaningful to write.\n */\nconst canGenerateExample = computed(() =>\n Boolean(structuredCodec.value && bodySchema.value),\n)\n</script>\n<template>\n <CollapsibleSection>\n <template #title>{{ title }}</template>\n <DataTable\n :columns=\"['']\"\n presentational>\n <DataTableHeader\n class=\"relative col-span-full flex h-8 cursor-pointer items-center justify-between border-r-0 !p-0\">\n <ScalarListbox\n v-model=\"selectedContentTypeModel\"\n :options=\"contentTypeOptions\"\n teleport>\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-3 font-normal\"\n fullWidth\n variant=\"ghost\">\n <span>{{ selectedContentTypeModel.label }}</span>\n <ScalarIcon\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n <div class=\"flex items-center gap-1\">\n <!--\n Generates a new example from the schema so the auto-generated fields stay reachable\n even once the document ships custom examples.\n -->\n <ScalarIconButton\n v-if=\"canGenerateExample\"\n aria-label=\"Generate example from schema\"\n :icon=\"ScalarIconMagicWand\"\n label=\"Generate example from schema\"\n size=\"sm\"\n tooltip\n @click.stop=\"\n emits('generate:example', { contentType: selectedContentType })\n \" />\n <RequestBodyViewToggle\n v-if=\"showBodyViewToggle\"\n :disabled=\"!isFormViewAvailable\"\n :modelValue=\"bodyView\"\n @update:modelValue=\"(v) => (bodyView = v)\" />\n </div>\n </DataTableHeader>\n <DataTableRow>\n <!-- No Body -->\n <template v-if=\"selectedContentType === 'none'\">\n <div\n class=\"text-c-3 flex min-h-10 w-full items-center justify-center border-t p-2 text-sm\">\n <span>{{ translate('apiClient.requestBody.noBody') }}</span>\n </div>\n </template>\n\n <!-- Binary File -->\n <template\n v-else-if=\"selectedContentType === 'application/octet-stream'\">\n <div\n class=\"flex items-center justify-center overflow-hidden border-t p-1.5\">\n <template\n v-if=\"\n getFileName(unpackProxyObject(example?.value)) !== undefined\n \">\n <span\n class=\"text-c-2 w-full max-w-full overflow-hidden rounded border px-1.5 py-1 text-xs whitespace-nowrap\">\n {{ getFileName(unpackProxyObject(example?.value)) }}\n </span>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 ml-1 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n emits('update:value', {\n payload: undefined,\n contentType: selectedContentType,\n })\n \">\n {{ translate('apiClient.requestBody.delete') }}\n </ScalarButton>\n </template>\n <template v-else>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n () =>\n handleFileUpload((file) =>\n emits('update:value', {\n payload: file,\n contentType: selectedContentType,\n }),\n )\n \">\n <span>{{ translate('apiClient.requestBody.selectFile') }}</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </template>\n </div>\n </template>\n\n <!-- Form Data / URL Encoded -->\n <template\n v-else-if=\"\n selectedContentType === 'multipart/form-data' ||\n selectedContentType === 'application/x-www-form-urlencoded'\n \">\n <RequestBodyForm\n :bodySchema\n :environment\n :example\n :selectedContentType\n @update:formValue=\"\n (payload) =>\n emits('update:formValue', {\n payload,\n contentType: selectedContentType,\n })\n \" />\n </template>\n\n <!-- Code/Other -->\n <template v-else>\n <!-- Schema-driven form view for structured (JSON/YAML) bodies -->\n <RequestBodyStructured\n v-if=\"bodyView === 'form' && isFormViewAvailable\"\n :bodySchema\n :contentType=\"selectedContentType\"\n :environment\n :parsedValue=\"parsedBody.value\"\n @update:value=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n <!-- Editable raw body with a copy button revealed on hover/focus -->\n <div\n v-else\n class=\"group/code-block relative border-t\">\n <CodeInput\n class=\"px-3\"\n content=\"\"\n :environment=\"environment\"\n :language=\"selectedLanguage\"\n lineNumbers\n lint\n :modelValue=\"bodyValue\"\n withFakeData\n @update:modelValue=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n <ScalarCodeBlockCopy\n v-if=\"bodyValue\"\n class=\"absolute top-1.5 right-1.5\"\n :content=\"bodyValue\"\n :lang=\"selectedLanguage\"\n showLang>\n <template #backdrop>\n <ScalarCopyBackdrop class=\"-top-1 -right-1.5\" />\n </template>\n </ScalarCodeBlockCopy>\n </div>\n </template>\n </DataTableRow>\n </DataTable>\n </CollapsibleSection>\n</template>\n<style scoped>\n:deep(.cm-content) {\n font-size: var(--scalar-small);\n}\n</style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"RequestBody.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestBody.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarCodeBlockCopy } from '@scalar/components/code-block'\nimport { ScalarCopyBackdrop } from '@scalar/components/copy'\nimport { ScalarIcon } from '@scalar/components/icon'\nimport { ScalarIconButton } from '@scalar/components/icon-button'\nimport { ScalarListbox } from '@scalar/components/listbox'\nimport { CONTENT_TYPES } from '@scalar/helpers/http/content-types'\nimport { isXmlMediaType } from '@scalar/helpers/http/is-xml-media-type'\nimport { parseMimeType } from '@scalar/helpers/http/mime-type'\nimport { isObject } from '@scalar/helpers/object/is-object'\nimport { objectEntries } from '@scalar/helpers/object/object-entries'\nimport { ScalarIconMagicWand } from '@scalar/icons'\nimport type { ApiReferenceEvents } from '@scalar/workspace-store/events'\nimport {\n getExampleValue,\n getExplicitExampleText,\n} from '@scalar/workspace-store/helpers/get-example-value'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n getExampleFromBody,\n getSchemaExampleFromBody,\n getSelectedBodyContentType,\n} from '@scalar/workspace-store/request-example'\nimport { resolve } from '@scalar/workspace-store/resolve'\nimport type { XScalarEnvironment } from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport type {\n RequestBodyObject,\n SchemaObject,\n} from '@scalar/workspace-store/schemas/v3.2/strict/openapi-document'\nimport { isObjectSchema } from '@scalar/workspace-store/schemas/v3.2/strict/type-guards'\nimport { computed, ref, watch } from 'vue'\n\nimport { useFileDialog } from '@/hooks/use-file-dialog'\nimport RequestBodyForm from '@/v2/blocks/request-block/components/RequestBodyForm.vue'\nimport RequestBodyStructured from '@/v2/blocks/request-block/components/RequestBodyStructured.vue'\nimport RequestBodyViewToggle from '@/v2/blocks/request-block/components/RequestBodyViewToggle.vue'\nimport { getFileName } from '@/v2/blocks/request-block/helpers/files'\nimport { getStructuredBodyCodec } from '@/v2/blocks/request-block/helpers/structured-body-codec'\nimport { CodeInput } from '@/v2/components/code-input'\nimport {\n DataTable,\n DataTableHeader,\n DataTableRow,\n} from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\nimport { useLocalization } from '@/v2/features/localization'\n\nconst {\n requestBody,\n exampleKey,\n environment,\n requestBodyCompositionSelection,\n openapiVersion,\n title,\n defaultView = 'raw',\n} = defineProps<{\n /** Request body */\n requestBody?: RequestBodyObject\n /** Currently selected example key for the current operation */\n exampleKey: string\n /** Display title */\n title: string\n /** Selected environment */\n environment: XScalarEnvironment\n /** Originating OpenAPI version, used for XML mapping rules. */\n openapiVersion?: string\n /** Selected anyOf/oneOf request-body variants keyed by schema path */\n requestBodyCompositionSelection?: Record<string, number>\n /**\n * Initial view for structured (JSON/YAML) bodies. Comes from the\n * `x-scalar-default-request-body-view` document extension and falls back to `raw`\n * whenever the body cannot be shown as a form.\n */\n defaultView?: 'form' | 'raw'\n}>()\n\nconst emits = defineEmits<{\n (e: 'update:contentType', payload: { value: string }): void\n /** We use this event to update raw values */\n (\n e: 'update:value',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n >,\n ): void\n /** We use this event when updating form data only */\n (\n e: 'update:formValue',\n payload: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n >,\n ): void\n /**\n * Create a new example seeded with values generated from the request body schema.\n *\n * The block itself owns the document and operation identity needed to create an example, so we\n * only report the content type the user is currently looking at.\n */\n (e: 'generate:example', payload: { contentType: string }): void\n}>()\n\nconst { translate } = useLocalization()\n\n// Map a content type to a language for the code editor\nconst contentTypeToLanguageMap = {\n 'application/json': 'json',\n 'application/xml': 'xml',\n 'application/yaml': 'yaml',\n} as const\n\n/** Selected content type with default */\nconst selectedContentType = computed(\n () => getSelectedBodyContentType(requestBody, exampleKey) ?? 'none',\n)\n\n/** Keep the editor and copy label aligned with the selected content type. */\nconst selectedLanguage = computed(() =>\n isXmlMediaType(selectedContentType.value)\n ? 'xml'\n : (contentTypeToLanguageMap[\n selectedContentType.value as keyof typeof contentTypeToLanguageMap\n ] ?? 'plaintext'),\n)\n\n/**\n * Strips MIME parameters (such as `charset=utf-8`) for dropdown labels, aligned with how we treat\n * media types elsewhere (see api-reference `normalizeMimeType` / WHATWG essence).\n */\nconst contentTypeLabel = (raw: string): string => parseMimeType(raw).essence\n\n/**\n * Build the dropdown options for the content type selector.\n *\n * The list is composed of two groups:\n * 1. The built-in content types we ship friendly labels for (JSON, XML, Multipart Form, etc.).\n * 2. Any additional content types defined on the OpenAPI request body that are not in the built-in list\n * (for example `text/csv`, `application/pdf`, vendor types like `application/vnd.api+json`, ...).\n *\n * The OpenAPI-defined extras are appended at the bottom so the well-known options stay on top, and\n * users can always pick the exact content type the operation actually accepts.\n */\n/** MIME values remain stable while their human-readable labels follow the locale. */\nconst localizedContentTypes = computed(() => ({\n ...CONTENT_TYPES,\n 'multipart/form-data': translate('apiClient.requestBody.multipartForm'),\n 'application/x-www-form-urlencoded': translate(\n 'apiClient.requestBody.formUrlEncoded',\n ),\n 'application/octet-stream': translate('apiClient.requestBody.binaryFile'),\n 'other': translate('apiClient.requestBody.other'),\n 'none': translate('apiClient.requestBody.none'),\n}))\n\nconst contentTypeOptions = computed<{ id: string; label: string }[]>(() => {\n const builtIn = objectEntries(localizedContentTypes.value).map(\n ([id, label]) => ({\n id,\n label,\n }),\n )\n\n const extras = Object.keys(requestBody?.content ?? {})\n .filter((type) => {\n if (type in CONTENT_TYPES) {\n return false\n }\n // Same essence as a built-in (e.g. `application/json; charset=utf-8`) — do not duplicate the row.\n return !(contentTypeLabel(type) in CONTENT_TYPES)\n })\n .map((type) => ({ id: type, label: contentTypeLabel(type) }))\n\n return [...builtIn, ...extras]\n})\n\nconst selectedContentTypeModel = computed<{ id: string; label: string }>({\n get: () => {\n const found = contentTypeOptions.value.find(\n (it) => it.id === selectedContentType.value,\n )\n if (found) {\n return found\n }\n\n const essence = contentTypeLabel(selectedContentType.value)\n const friendly =\n localizedContentTypes.value[essence as keyof typeof CONTENT_TYPES] ??\n essence\n\n return {\n id: selectedContentType.value,\n label: friendly,\n }\n },\n set: (v) => {\n emits('update:contentType', { value: v.id })\n },\n})\n\nfunction handleFileUpload(callback: (file: File) => void) {\n const { open } = useFileDialog({\n onChange: (files) => {\n const file = files?.[0]\n if (file) {\n callback(file)\n }\n },\n multiple: false,\n accept: '*/*',\n })\n open()\n}\n\n/** Dereferenced example */\nconst example = computed(\n () =>\n requestBody &&\n getExampleFromBody(\n requestBody,\n selectedContentType.value,\n exampleKey,\n requestBodyCompositionSelection,\n openapiVersion,\n ),\n)\n\n/** Convert the example value to a string for the code editor */\nconst bodyValue = computed(() => {\n if (!example.value) {\n return ''\n }\n\n const selected = getExampleValue(example.value)\n const explicitText = getExplicitExampleText(\n selected,\n selectedContentType.value,\n 2,\n )\n if (explicitText !== undefined) {\n return explicitText\n }\n const value = selected?.value\n if (typeof value === 'string') {\n return value\n }\n\n return JSON.stringify(value, null, 2)\n})\n\n/** Resolved schema for the request body */\nconst bodySchema = computed<SchemaObject | undefined>(() => {\n return resolve.schema(\n requestBody?.content?.[selectedContentType.value]?.schema ??\n requestBody?.content?.[selectedContentType.value]?.itemSchema,\n )\n})\n\n/** Codec for structured (JSON/YAML) bodies, undefined for everything else */\nconst structuredCodec = computed(() =>\n selectedContentType.value === 'none'\n ? undefined\n : getStructuredBodyCodec(selectedContentType.value),\n)\n\n/** Parsed body value for the form view — `ok: false` when the raw text is not parseable */\nconst parsedBody = computed<{ ok: boolean; value?: unknown }>(() => {\n const codec = structuredCodec.value\n if (!codec) {\n return { ok: false }\n }\n\n const selected = getExampleValue(example.value ?? undefined)\n // Structured data is already parsed; parsing strings again changes the payload type.\n if (example.value?.dataValue !== undefined) {\n return { ok: true, value: example.value.dataValue }\n }\n const raw = selected?.value\n // An empty body is still form-editable: rows come from the schema.\n if (raw === undefined || raw === null || raw === '') {\n return { ok: true, value: {} }\n }\n if (typeof raw === 'string') {\n try {\n return { ok: true, value: codec.parse(raw) }\n } catch {\n return { ok: false }\n }\n }\n // Spec-provided examples can be stored as objects directly.\n return { ok: true, value: raw }\n})\n\n/**\n * An edited example normally takes precedence over schema-generated data. When a different\n * composition branch is selected, however, keeping that example leaves the editor showing the\n * previous branch. Track the selection itself instead of inspecting discriminator fields so this\n * also works for compositions whose members are distinguished only by their shape.\n */\nconst compositionSelectionKey = computed(() =>\n JSON.stringify(requestBodyCompositionSelection ?? {}),\n)\n\n// Switching operations changes the body (and often the selection) at once, which is not a branch\n// change, so we only regenerate the body when the selection changes while the operation and example\n// stay the same. Watching all three together and comparing against the watcher's own previous values\n// keeps this correct regardless of the order in which props update or watchers flush.\nwatch(\n [() => requestBody, () => exampleKey, compositionSelectionKey],\n (\n [, , selection],\n [previousRequestBody, previousExampleKey, previousSelection],\n ) => {\n const operationChanged =\n requestBody !== previousRequestBody || exampleKey !== previousExampleKey\n const selectionChanged = selection !== previousSelection\n\n // Going from no selection to a populated one is the modal applying the reference's selection as\n // the panel opens, not the user switching branches. Resetting here would discard the body's named\n // example on the very first open (issue #10075), so only a change between two populated selections\n // counts as a real branch switch.\n const hadNoPreviousSelection = previousSelection === '{}'\n\n // Only a genuine branch switch within the same operation should reset the edited body. An empty\n // selection means there is no composition to switch between (or the selection was cleared on an\n // operation change), so there is nothing to reset.\n if (\n operationChanged ||\n !selectionChanged ||\n hadNoPreviousSelection ||\n Object.keys(requestBodyCompositionSelection ?? {}).length === 0\n ) {\n return\n }\n\n const codec = structuredCodec.value\n const isXml = isXmlMediaType(selectedContentType.value)\n if (!requestBody || (!codec && !isXml)) {\n return\n }\n\n // Regenerate through the same helper the initial example uses so a reset produces exactly the\n // value a fresh render of this branch would, rather than a hand-copied second code path.\n const selectedValue = getSchemaExampleFromBody(\n requestBody,\n selectedContentType.value,\n requestBodyCompositionSelection,\n openapiVersion,\n )\n\n emits('update:value', {\n // A branch with no writable content generates `null`/`undefined`; clear the editor rather than\n // writing the literal text `null` or leaving the previously selected branch's body behind.\n payload:\n selectedValue == null\n ? ''\n : isXml\n ? String(selectedValue)\n : codec!.stringify(selectedValue),\n contentType: selectedContentType.value,\n })\n },\n)\n\n/** The form view only works on an object-shaped body root */\nconst isFormViewAvailable = computed(\n () => parsedBody.value.ok && isObject(parsedBody.value.value),\n)\n\n/**\n * Show the Form/Raw toggle for structured bodies that are (or per schema should be)\n * an object at the root. Non-object roots (arrays, primitives) stay raw-only.\n */\nconst showBodyViewToggle = computed(\n () =>\n Boolean(structuredCodec.value) &&\n (isFormViewAvailable.value ||\n Boolean(bodySchema.value && isObjectSchema(bodySchema.value))),\n)\n\n/** Selected body view, seeded from the document default (raw unless configured) */\nconst bodyView = ref<'form' | 'raw'>(defaultView)\n\n// Fall back to raw when the form view stops being available (e.g. the content type\n// changed to a non-structured one, or an external edit made the body unparseable).\nwatch(isFormViewAvailable, (ok) => {\n if (!ok) {\n bodyView.value = 'raw'\n }\n})\n\n/**\n * Whether we can offer to generate a fresh example from the schema.\n *\n * Only structured (JSON/YAML) bodies qualify: they have a schema to generate from and a text\n * representation we can seed the new example with. Binary and form bodies have their own editors,\n * so the button would have nothing meaningful to write.\n */\nconst canGenerateExample = computed(() =>\n Boolean(structuredCodec.value && bodySchema.value),\n)\n</script>\n<template>\n <CollapsibleSection>\n <template #title>{{ title }}</template>\n <DataTable\n :columns=\"['']\"\n presentational>\n <DataTableHeader\n class=\"relative col-span-full flex h-8 cursor-pointer items-center justify-between border-r-0 !p-0\">\n <ScalarListbox\n v-model=\"selectedContentTypeModel\"\n :options=\"contentTypeOptions\"\n teleport>\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-3 font-normal\"\n fullWidth\n variant=\"ghost\">\n <span>{{ selectedContentTypeModel.label }}</span>\n <ScalarIcon\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n <div class=\"flex items-center gap-1\">\n <!--\n Generates a new example from the schema so the auto-generated fields stay reachable\n even once the document ships custom examples.\n -->\n <ScalarIconButton\n v-if=\"canGenerateExample\"\n aria-label=\"Generate example from schema\"\n :icon=\"ScalarIconMagicWand\"\n label=\"Generate example from schema\"\n size=\"sm\"\n tooltip\n @click.stop=\"\n emits('generate:example', { contentType: selectedContentType })\n \" />\n <RequestBodyViewToggle\n v-if=\"showBodyViewToggle\"\n :disabled=\"!isFormViewAvailable\"\n :modelValue=\"bodyView\"\n @update:modelValue=\"(v) => (bodyView = v)\" />\n </div>\n </DataTableHeader>\n <DataTableRow>\n <!-- No Body -->\n <template v-if=\"selectedContentType === 'none'\">\n <div\n class=\"text-c-3 flex min-h-10 w-full items-center justify-center border-t p-2 text-sm\">\n <span>{{ translate('apiClient.requestBody.noBody') }}</span>\n </div>\n </template>\n\n <!-- Binary File -->\n <template\n v-else-if=\"selectedContentType === 'application/octet-stream'\">\n <div\n class=\"flex items-center justify-center overflow-hidden border-t p-1.5\">\n <template\n v-if=\"\n getFileName(unpackProxyObject(example?.value)) !== undefined\n \">\n <span\n class=\"text-c-2 w-full max-w-full overflow-hidden rounded border px-1.5 py-1 text-xs whitespace-nowrap\">\n {{ getFileName(unpackProxyObject(example?.value)) }}\n </span>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 ml-1 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n emits('update:value', {\n payload: undefined,\n contentType: selectedContentType,\n })\n \">\n {{ translate('apiClient.requestBody.delete') }}\n </ScalarButton>\n </template>\n <template v-else>\n <ScalarButton\n class=\"bg-b-2 hover:bg-b-3 text-c-2 border-0 shadow-none\"\n size=\"sm\"\n variant=\"outlined\"\n @click=\"\n () =>\n handleFileUpload((file) =>\n emits('update:value', {\n payload: file,\n contentType: selectedContentType,\n }),\n )\n \">\n <span>{{ translate('apiClient.requestBody.selectFile') }}</span>\n <ScalarIcon\n class=\"ml-1\"\n icon=\"Upload\"\n size=\"xs\"\n thickness=\"2.5\" />\n </ScalarButton>\n </template>\n </div>\n </template>\n\n <!-- Form Data / URL Encoded -->\n <template\n v-else-if=\"\n selectedContentType === 'multipart/form-data' ||\n selectedContentType === 'application/x-www-form-urlencoded'\n \">\n <RequestBodyForm\n :bodySchema\n :environment\n :example\n :selectedContentType\n @update:formValue=\"\n (payload) =>\n emits('update:formValue', {\n payload,\n contentType: selectedContentType,\n })\n \" />\n </template>\n\n <!-- Code/Other -->\n <template v-else>\n <!-- Schema-driven form view for structured (JSON/YAML) bodies -->\n <RequestBodyStructured\n v-if=\"bodyView === 'form' && isFormViewAvailable\"\n :bodySchema\n :contentType=\"selectedContentType\"\n :environment\n :parsedValue=\"parsedBody.value\"\n @update:value=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n <!-- Editable raw body with a copy button revealed on hover/focus -->\n <div\n v-else\n class=\"group/code-block relative min-w-0 border-t\">\n <CodeInput\n class=\"px-3\"\n content=\"\"\n :environment=\"environment\"\n :language=\"selectedLanguage\"\n lineNumbers\n lint\n :modelValue=\"bodyValue\"\n withFakeData\n @update:modelValue=\"\n (value) =>\n emits('update:value', {\n payload: value,\n contentType: selectedContentType,\n })\n \" />\n <ScalarCodeBlockCopy\n v-if=\"bodyValue\"\n class=\"absolute top-1.5 right-1.5\"\n :content=\"bodyValue\"\n :lang=\"selectedLanguage\"\n showLang>\n <template #backdrop>\n <ScalarCopyBackdrop class=\"-top-1 -right-1.5\" />\n </template>\n </ScalarCodeBlockCopy>\n </div>\n </template>\n </DataTableRow>\n </DataTable>\n </CollapsibleSection>\n</template>\n<style scoped>\n:deep(.cm-content) {\n font-size: var(--scalar-small);\n}\n</style>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestCodeSnippet.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestCodeSnippet.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RequestCodeSnippet.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestCodeSnippet.vue"],"names":[],"mappings":"AAmLA,OAAO,EAOL,KAAK,gBAAgB,EAEtB,MAAM,6BAA6B,CAAA;AAMpC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAOvE,KAAK,WAAW,GAAG,gBAAgB,GAAG;IAAE,QAAQ,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAkUtE,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestCodeSnippet.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestCodeSnippet.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n findClient,\n generateCodeSnippet,\n getClients,\n getCustomCodeSamples,\n getSecrets,\n type ClientOption,\n type CodeExampleProps,\n type CustomClientOption,\n} from '@scalar/blocks/code-example'\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarCodeBlock } from '@scalar/components/code-block'\nimport { ScalarCombobox } from '@scalar/components/combobox'\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { ScalarIconCaretDown } from '@scalar/icons'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { computed, ref, watch } from 'vue'\n\nimport { DataTable, DataTableRow } from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\nimport { useLocalization } from '@/v2/features/localization'\n\nconst {\n clientOptions,\n eventBus,\n operation,\n method,\n path,\n selectedContentType,\n selectedServer = null,\n selectedExample,\n securitySchemes,\n selectedClient,\n globalCookies,\n openapiVersion,\n requestBodyCompositionSelection,\n integration,\n} = defineProps<CodeExampleProps & { eventBus: WorkspaceEventBus }>()\n\nconst { translate } = useLocalization()\n\n/** Grab any custom code samples from the operation */\nconst customCodeSamples = computed(() => getCustomCodeSamples(operation))\n\n/** Merge custom code samples with the client options */\nconst clients = computed(() =>\n getClients(\n customCodeSamples.value.samples,\n clientOptions,\n customCodeSamples.value.label,\n ),\n)\n\n/**\n * The locally selected client which would include code samples from this operation only\n * Must be local state because it contains custom code samples from this operation only\n */\nconst localSelectedClient = ref<ClientOption | CustomClientOption | undefined>(\n findClient(clients.value, selectedClient),\n)\n\n/**\n * Re-resolve the local client whenever the global selection or the available\n * clients change. Watching `clients` matters when navigating between operations:\n * the stored id stays the same, but the matching option (e.g. a custom sample)\n * differs per operation, so without this the snippet could go stale.\n */\nwatch([() => selectedClient, clients], ([newClient]) => {\n const client = findClient(clients.value, newClient)\n if (client) {\n localSelectedClient.value = client\n }\n})\n\n/** Block secrets from being shown in the code block */\nconst secretCredentials = computed(() => getSecrets(securitySchemes ?? []))\n\n/** Handle client change */\nconst handleClientChange = (option: ClientOption | undefined) => {\n localSelectedClient.value = option\n\n // Sync the selection globally (built-in client or custom sample keyed by language)\n if (option) {\n eventBus.emit('workspace:update:selected-client', option.id)\n }\n}\n\n/** Generate the code snippet for the selected example */\nconst generatedCode = computed<string | null>(() =>\n generateCodeSnippet({\n defaultDisabledParameters: true,\n clientId: localSelectedClient.value?.id,\n customCodeSamples: customCodeSamples.value.samples,\n operation,\n method,\n path,\n contentType: selectedContentType,\n server: selectedServer,\n securitySchemes,\n example: selectedExample,\n globalCookies,\n openapiVersion,\n requestBodyCompositionSelection,\n includeDefaultHeaders: integration === 'client',\n }),\n)\n\n/** Check if there are any clients available (built-in or custom code samples) */\nconst hasClients = computed(() =>\n clients.value.some((group) => group.options.length > 0),\n)\n</script>\n\n<template>\n <CollapsibleSection\n v-if=\"hasClients\"\n class=\"group/preview w-full border-t\"\n :defaultOpen=\"false\">\n <template #title>\n {{ translate('apiClient.requestCodeSnippet.codeSnippet') }}\n </template>\n\n <!-- Client selector -->\n <template #actions>\n <div class=\"flex flex-1\">\n <ScalarCombobox\n :modelValue=\"localSelectedClient\"\n :options=\"clients\"\n placement=\"bottom-end\"\n @update:modelValue=\"\n (ev) => handleClientChange(ev as ClientOption | undefined)\n \">\n <template #default=\"{ open }\">\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-0.5 py-0 text-base font-normal\"\n data-testid=\"client-picker\"\n variant=\"ghost\">\n {{ localSelectedClient?.title }}\n <ScalarIconCaretDown\n class=\"mt-0.25 size-3 transition-transform duration-100\"\n :class=\"open && 'rotate-180'\"\n weight=\"bold\" />\n </ScalarButton>\n </template>\n </ScalarCombobox>\n </div>\n </template>\n\n <!-- Code snippet -->\n <ScalarErrorBoundary>\n <DataTable\n :columns=\"['']\"\n presentational>\n <DataTableRow>\n <div class=\"overflow-hidden\">\n <div\n v-if=\"generatedCode === null\"\n class=\"text-c-2 p-4\"\n role=\"status\">\n {{ translate('apiClient.requestCodeSnippet.unavailable') }}\n </div>\n <ScalarCodeBlock\n v-else\n class=\"text-base\"\n :content=\"generatedCode\"\n :hideCredentials=\"secretCredentials\"\n :lang=\"localSelectedClient?.lang ?? 'plaintext'\"\n lineNumbers />\n </div>\n </DataTableRow>\n </DataTable>\n </ScalarErrorBoundary>\n </CollapsibleSection>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"RequestCodeSnippet.vue.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestCodeSnippet.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n findClient,\n generateCodeSnippet,\n getClients,\n getCustomCodeSamples,\n getSecrets,\n type ClientOption,\n type CodeExampleProps,\n type CustomClientOption,\n} from '@scalar/blocks/code-example'\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarCodeBlock } from '@scalar/components/code-block'\nimport { ScalarCombobox } from '@scalar/components/combobox'\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { ScalarIconCaretDown } from '@scalar/icons'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { computed, ref, watch } from 'vue'\n\nimport { DataTable, DataTableRow } from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\nimport { useLocalization } from '@/v2/features/localization'\n\nconst {\n clientOptions,\n eventBus,\n operation,\n method,\n path,\n selectedContentType,\n selectedServer = null,\n selectedExample,\n securitySchemes,\n selectedClient,\n globalCookies,\n openapiVersion,\n requestBodyCompositionSelection,\n integration,\n} = defineProps<CodeExampleProps & { eventBus: WorkspaceEventBus }>()\n\nconst { translate } = useLocalization()\n\n/** Grab any custom code samples from the operation */\nconst customCodeSamples = computed(() => getCustomCodeSamples(operation))\n\n/** Merge custom code samples with the client options */\nconst clients = computed(() =>\n getClients(\n customCodeSamples.value.samples,\n clientOptions,\n customCodeSamples.value.label,\n ),\n)\n\n/**\n * The locally selected client which would include code samples from this operation only\n * Must be local state because it contains custom code samples from this operation only\n */\nconst localSelectedClient = ref<ClientOption | CustomClientOption | undefined>(\n findClient(clients.value, selectedClient),\n)\n\n/**\n * Re-resolve the local client whenever the global selection or the available\n * clients change. Watching `clients` matters when navigating between operations:\n * the stored id stays the same, but the matching option (e.g. a custom sample)\n * differs per operation, so without this the snippet could go stale.\n */\nwatch([() => selectedClient, clients], ([newClient]) => {\n const client = findClient(clients.value, newClient)\n if (client) {\n localSelectedClient.value = client\n }\n})\n\n/** Block secrets from being shown in the code block */\nconst secretCredentials = computed(() => getSecrets(securitySchemes ?? []))\n\n/** Handle client change */\nconst handleClientChange = (option: ClientOption | undefined) => {\n localSelectedClient.value = option\n\n // Sync the selection globally (built-in client or custom sample keyed by language)\n if (option) {\n eventBus.emit('workspace:update:selected-client', option.id)\n }\n}\n\n/** Generate the code snippet for the selected example */\nconst generatedCode = computed<string | null>(() =>\n generateCodeSnippet({\n defaultDisabledParameters: true,\n clientId: localSelectedClient.value?.id,\n customCodeSamples: customCodeSamples.value.samples,\n operation,\n method,\n path,\n contentType: selectedContentType,\n server: selectedServer,\n securitySchemes,\n example: selectedExample,\n globalCookies,\n openapiVersion,\n requestBodyCompositionSelection,\n includeDefaultHeaders: integration === 'client',\n }),\n)\n\n/** Check if there are any clients available (built-in or custom code samples) */\nconst hasClients = computed(() =>\n clients.value.some((group) => group.options.length > 0),\n)\n</script>\n\n<template>\n <CollapsibleSection\n v-if=\"hasClients\"\n class=\"group/preview w-full border-t\"\n :defaultOpen=\"false\">\n <template #title>\n {{ translate('apiClient.requestCodeSnippet.codeSnippet') }}\n </template>\n\n <!-- Client selector -->\n <template #actions>\n <div class=\"flex flex-1\">\n <ScalarCombobox\n :modelValue=\"localSelectedClient\"\n :options=\"clients\"\n placement=\"bottom-end\"\n @update:modelValue=\"\n (ev) => handleClientChange(ev as ClientOption | undefined)\n \">\n <template #default=\"{ open }\">\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-0.5 py-0 text-base font-normal\"\n data-testid=\"client-picker\"\n variant=\"ghost\">\n {{ localSelectedClient?.title }}\n <ScalarIconCaretDown\n class=\"mt-0.25 size-3 transition-transform duration-100\"\n :class=\"open && 'rotate-180'\"\n weight=\"bold\" />\n </ScalarButton>\n </template>\n </ScalarCombobox>\n </div>\n </template>\n\n <!-- Code snippet -->\n <ScalarErrorBoundary>\n <DataTable\n :columns=\"['']\"\n presentational>\n <DataTableRow>\n <div class=\"overflow-hidden\">\n <div\n v-if=\"generatedCode === null\"\n class=\"text-c-2 p-4\"\n role=\"status\">\n {{ translate('apiClient.requestCodeSnippet.unavailable') }}\n </div>\n <ScalarCodeBlock\n v-else\n class=\"text-base\"\n :content=\"generatedCode\"\n :hideCredentials=\"secretCredentials\"\n :label=\"translate('apiClient.requestCodeSnippet.codeSnippet')\"\n :lang=\"localSelectedClient?.lang ?? 'plaintext'\"\n lineNumbers />\n </div>\n </DataTableRow>\n </DataTable>\n </ScalarErrorBoundary>\n </CollapsibleSection>\n</template>\n"],"mappings":""}
|
|
@@ -23,6 +23,7 @@ var RequestCodeSnippet_vue_vue_type_script_setup_true_lang_default = /*@__PURE__
|
|
|
23
23
|
codeSampleUnavailable: {},
|
|
24
24
|
clientPickerLabel: {},
|
|
25
25
|
clientSearchLabel: {},
|
|
26
|
+
codeSampleLabel: {},
|
|
26
27
|
integration: {},
|
|
27
28
|
clientOptions: {},
|
|
28
29
|
selectedClient: {},
|
|
@@ -125,11 +126,13 @@ var RequestCodeSnippet_vue_vue_type_script_setup_true_lang_default = /*@__PURE__
|
|
|
125
126
|
class: "text-base",
|
|
126
127
|
content: generatedCode.value,
|
|
127
128
|
hideCredentials: secretCredentials.value,
|
|
129
|
+
label: unref(translate)("apiClient.requestCodeSnippet.codeSnippet"),
|
|
128
130
|
lang: localSelectedClient.value?.lang ?? "plaintext",
|
|
129
131
|
lineNumbers: ""
|
|
130
132
|
}, null, 8, [
|
|
131
133
|
"content",
|
|
132
134
|
"hideCredentials",
|
|
135
|
+
"label",
|
|
133
136
|
"lang"
|
|
134
137
|
]))])]),
|
|
135
138
|
_: 1
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequestCodeSnippet.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestCodeSnippet.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n findClient,\n generateCodeSnippet,\n getClients,\n getCustomCodeSamples,\n getSecrets,\n type ClientOption,\n type CodeExampleProps,\n type CustomClientOption,\n} from '@scalar/blocks/code-example'\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarCodeBlock } from '@scalar/components/code-block'\nimport { ScalarCombobox } from '@scalar/components/combobox'\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { ScalarIconCaretDown } from '@scalar/icons'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { computed, ref, watch } from 'vue'\n\nimport { DataTable, DataTableRow } from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\nimport { useLocalization } from '@/v2/features/localization'\n\nconst {\n clientOptions,\n eventBus,\n operation,\n method,\n path,\n selectedContentType,\n selectedServer = null,\n selectedExample,\n securitySchemes,\n selectedClient,\n globalCookies,\n openapiVersion,\n requestBodyCompositionSelection,\n integration,\n} = defineProps<CodeExampleProps & { eventBus: WorkspaceEventBus }>()\n\nconst { translate } = useLocalization()\n\n/** Grab any custom code samples from the operation */\nconst customCodeSamples = computed(() => getCustomCodeSamples(operation))\n\n/** Merge custom code samples with the client options */\nconst clients = computed(() =>\n getClients(\n customCodeSamples.value.samples,\n clientOptions,\n customCodeSamples.value.label,\n ),\n)\n\n/**\n * The locally selected client which would include code samples from this operation only\n * Must be local state because it contains custom code samples from this operation only\n */\nconst localSelectedClient = ref<ClientOption | CustomClientOption | undefined>(\n findClient(clients.value, selectedClient),\n)\n\n/**\n * Re-resolve the local client whenever the global selection or the available\n * clients change. Watching `clients` matters when navigating between operations:\n * the stored id stays the same, but the matching option (e.g. a custom sample)\n * differs per operation, so without this the snippet could go stale.\n */\nwatch([() => selectedClient, clients], ([newClient]) => {\n const client = findClient(clients.value, newClient)\n if (client) {\n localSelectedClient.value = client\n }\n})\n\n/** Block secrets from being shown in the code block */\nconst secretCredentials = computed(() => getSecrets(securitySchemes ?? []))\n\n/** Handle client change */\nconst handleClientChange = (option: ClientOption | undefined) => {\n localSelectedClient.value = option\n\n // Sync the selection globally (built-in client or custom sample keyed by language)\n if (option) {\n eventBus.emit('workspace:update:selected-client', option.id)\n }\n}\n\n/** Generate the code snippet for the selected example */\nconst generatedCode = computed<string | null>(() =>\n generateCodeSnippet({\n defaultDisabledParameters: true,\n clientId: localSelectedClient.value?.id,\n customCodeSamples: customCodeSamples.value.samples,\n operation,\n method,\n path,\n contentType: selectedContentType,\n server: selectedServer,\n securitySchemes,\n example: selectedExample,\n globalCookies,\n openapiVersion,\n requestBodyCompositionSelection,\n includeDefaultHeaders: integration === 'client',\n }),\n)\n\n/** Check if there are any clients available (built-in or custom code samples) */\nconst hasClients = computed(() =>\n clients.value.some((group) => group.options.length > 0),\n)\n</script>\n\n<template>\n <CollapsibleSection\n v-if=\"hasClients\"\n class=\"group/preview w-full border-t\"\n :defaultOpen=\"false\">\n <template #title>\n {{ translate('apiClient.requestCodeSnippet.codeSnippet') }}\n </template>\n\n <!-- Client selector -->\n <template #actions>\n <div class=\"flex flex-1\">\n <ScalarCombobox\n :modelValue=\"localSelectedClient\"\n :options=\"clients\"\n placement=\"bottom-end\"\n @update:modelValue=\"\n (ev) => handleClientChange(ev as ClientOption | undefined)\n \">\n <template #default=\"{ open }\">\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-0.5 py-0 text-base font-normal\"\n data-testid=\"client-picker\"\n variant=\"ghost\">\n {{ localSelectedClient?.title }}\n <ScalarIconCaretDown\n class=\"mt-0.25 size-3 transition-transform duration-100\"\n :class=\"open && 'rotate-180'\"\n weight=\"bold\" />\n </ScalarButton>\n </template>\n </ScalarCombobox>\n </div>\n </template>\n\n <!-- Code snippet -->\n <ScalarErrorBoundary>\n <DataTable\n :columns=\"['']\"\n presentational>\n <DataTableRow>\n <div class=\"overflow-hidden\">\n <div\n v-if=\"generatedCode === null\"\n class=\"text-c-2 p-4\"\n role=\"status\">\n {{ translate('apiClient.requestCodeSnippet.unavailable') }}\n </div>\n <ScalarCodeBlock\n v-else\n class=\"text-base\"\n :content=\"generatedCode\"\n :hideCredentials=\"secretCredentials\"\n :lang=\"localSelectedClient?.lang ?? 'plaintext'\"\n lineNumbers />\n </div>\n </DataTableRow>\n </DataTable>\n </ScalarErrorBoundary>\n </CollapsibleSection>\n</template>\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"RequestCodeSnippet.vue.script.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/components/RequestCodeSnippet.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n findClient,\n generateCodeSnippet,\n getClients,\n getCustomCodeSamples,\n getSecrets,\n type ClientOption,\n type CodeExampleProps,\n type CustomClientOption,\n} from '@scalar/blocks/code-example'\nimport { ScalarButton } from '@scalar/components/button'\nimport { ScalarCodeBlock } from '@scalar/components/code-block'\nimport { ScalarCombobox } from '@scalar/components/combobox'\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { ScalarIconCaretDown } from '@scalar/icons'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { computed, ref, watch } from 'vue'\n\nimport { DataTable, DataTableRow } from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\nimport { useLocalization } from '@/v2/features/localization'\n\nconst {\n clientOptions,\n eventBus,\n operation,\n method,\n path,\n selectedContentType,\n selectedServer = null,\n selectedExample,\n securitySchemes,\n selectedClient,\n globalCookies,\n openapiVersion,\n requestBodyCompositionSelection,\n integration,\n} = defineProps<CodeExampleProps & { eventBus: WorkspaceEventBus }>()\n\nconst { translate } = useLocalization()\n\n/** Grab any custom code samples from the operation */\nconst customCodeSamples = computed(() => getCustomCodeSamples(operation))\n\n/** Merge custom code samples with the client options */\nconst clients = computed(() =>\n getClients(\n customCodeSamples.value.samples,\n clientOptions,\n customCodeSamples.value.label,\n ),\n)\n\n/**\n * The locally selected client which would include code samples from this operation only\n * Must be local state because it contains custom code samples from this operation only\n */\nconst localSelectedClient = ref<ClientOption | CustomClientOption | undefined>(\n findClient(clients.value, selectedClient),\n)\n\n/**\n * Re-resolve the local client whenever the global selection or the available\n * clients change. Watching `clients` matters when navigating between operations:\n * the stored id stays the same, but the matching option (e.g. a custom sample)\n * differs per operation, so without this the snippet could go stale.\n */\nwatch([() => selectedClient, clients], ([newClient]) => {\n const client = findClient(clients.value, newClient)\n if (client) {\n localSelectedClient.value = client\n }\n})\n\n/** Block secrets from being shown in the code block */\nconst secretCredentials = computed(() => getSecrets(securitySchemes ?? []))\n\n/** Handle client change */\nconst handleClientChange = (option: ClientOption | undefined) => {\n localSelectedClient.value = option\n\n // Sync the selection globally (built-in client or custom sample keyed by language)\n if (option) {\n eventBus.emit('workspace:update:selected-client', option.id)\n }\n}\n\n/** Generate the code snippet for the selected example */\nconst generatedCode = computed<string | null>(() =>\n generateCodeSnippet({\n defaultDisabledParameters: true,\n clientId: localSelectedClient.value?.id,\n customCodeSamples: customCodeSamples.value.samples,\n operation,\n method,\n path,\n contentType: selectedContentType,\n server: selectedServer,\n securitySchemes,\n example: selectedExample,\n globalCookies,\n openapiVersion,\n requestBodyCompositionSelection,\n includeDefaultHeaders: integration === 'client',\n }),\n)\n\n/** Check if there are any clients available (built-in or custom code samples) */\nconst hasClients = computed(() =>\n clients.value.some((group) => group.options.length > 0),\n)\n</script>\n\n<template>\n <CollapsibleSection\n v-if=\"hasClients\"\n class=\"group/preview w-full border-t\"\n :defaultOpen=\"false\">\n <template #title>\n {{ translate('apiClient.requestCodeSnippet.codeSnippet') }}\n </template>\n\n <!-- Client selector -->\n <template #actions>\n <div class=\"flex flex-1\">\n <ScalarCombobox\n :modelValue=\"localSelectedClient\"\n :options=\"clients\"\n placement=\"bottom-end\"\n @update:modelValue=\"\n (ev) => handleClientChange(ev as ClientOption | undefined)\n \">\n <template #default=\"{ open }\">\n <ScalarButton\n class=\"text-c-2 hover:text-c-1 flex h-full w-fit gap-1.5 px-0.5 py-0 text-base font-normal\"\n data-testid=\"client-picker\"\n variant=\"ghost\">\n {{ localSelectedClient?.title }}\n <ScalarIconCaretDown\n class=\"mt-0.25 size-3 transition-transform duration-100\"\n :class=\"open && 'rotate-180'\"\n weight=\"bold\" />\n </ScalarButton>\n </template>\n </ScalarCombobox>\n </div>\n </template>\n\n <!-- Code snippet -->\n <ScalarErrorBoundary>\n <DataTable\n :columns=\"['']\"\n presentational>\n <DataTableRow>\n <div class=\"overflow-hidden\">\n <div\n v-if=\"generatedCode === null\"\n class=\"text-c-2 p-4\"\n role=\"status\">\n {{ translate('apiClient.requestCodeSnippet.unavailable') }}\n </div>\n <ScalarCodeBlock\n v-else\n class=\"text-base\"\n :content=\"generatedCode\"\n :hideCredentials=\"secretCredentials\"\n :label=\"translate('apiClient.requestCodeSnippet.codeSnippet')\"\n :lang=\"localSelectedClient?.lang ?? 'plaintext'\"\n lineNumbers />\n </div>\n </DataTableRow>\n </DataTable>\n </ScalarErrorBoundary>\n </CollapsibleSection>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwCA,MAAM,EAAE,cAAc,gBAAgB;;EAGtC,MAAM,oBAAoB,eAAe,qBAAqB,QAAA,SAAS,CAAC;;EAGxE,MAAM,UAAU,eACd,WACE,kBAAkB,MAAM,SACxB,QAAA,eACA,kBAAkB,MAAM,KAC1B,CACF;;;;;EAMA,MAAM,sBAAsB,IAC1B,WAAW,QAAQ,OAAO,QAAA,cAAc,CAC1C;;;;;;;EAQA,MAAM,OAAO,QAAA,gBAAgB,OAAO,IAAI,CAAC,eAAe;GACtD,MAAM,SAAS,WAAW,QAAQ,OAAO,SAAS;GAClD,IAAI,QACF,oBAAoB,QAAQ;EAEhC,CAAC;;EAGD,MAAM,oBAAoB,eAAe,WAAW,QAAA,mBAAmB,CAAC,CAAC,CAAC;;EAG1E,MAAM,sBAAsB,WAAqC;GAC/D,oBAAoB,QAAQ;GAG5B,IAAI,QACF,QAAA,SAAS,KAAK,oCAAoC,OAAO,EAAE;EAE/D;;EAGA,MAAM,gBAAgB,eACpB,oBAAoB;GAClB,2BAA2B;GAC3B,UAAU,oBAAoB,OAAO;GACrC,mBAAmB,kBAAkB,MAAM;GAC3C,WAAQ,QAAA;GACR,QAAK,QAAA;GACL,MAAG,QAAA;GACH,aAAa,QAAA;GACb,QAAQ,QAAA;GACR,iBAAc,QAAA;GACd,SAAS,QAAA;GACT,eAAY,QAAA;GACZ,gBAAa,QAAA;GACb,iCAA8B,QAAA;GAC9B,uBAAuB,QAAA,gBAAgB;EACzC,CAAC,CACH;;EAGA,MAAM,aAAa,eACjB,QAAQ,MAAM,MAAM,UAAU,MAAM,QAAQ,SAAS,CAAC,CACxD;;UAKU,WAAA,SAAA,UAAA,GADR,YA2DqB,MAAA,0BAAA,GAAA;;IAzDnB,OAAM;IACL,aAAa;;IACH,OAAK,cAC6C,CAAA,gBAAA,gBAAxD,MAAA,SAAA,CAAS,CAAA,0CAAA,CAAA,GAAA,CAAA,CAAA,CAAA;IAIH,SAAO,cAsBV,CArBN,mBAqBM,OArBN,YAqBM,CApBJ,YAmBiB,MAAA,cAAA,GAAA;KAlBd,YAAY,oBAAA;KACZ,SAAS,QAAA;KACV,WAAU;KACT,uBAAiB,OAAA,OAAA,OAAA,MAAgB,OAAO,mBAAmB,EAAE;;KAGnD,SAAO,SAUD,EAVK,WAAI,CACxB,YASe,MAAA,YAAA,GAAA;MARb,OAAM;MACN,eAAY;MACZ,SAAQ;;6BACwB,CAAA,gBAAA,gBAA7B,oBAAA,OAAqB,KAAK,IAAG,KAChC,CAAA,GAAA,YAGkB,MAAA,mBAAA,GAAA;OAFhB,OAAK,eAAA,CAAC,oDACE,QAAI,YAAA,CAAA;OACZ,QAAO;;;;;;2BA+BG,CAvBtB,YAuBsB,MAAA,mBAAA,GAAA,MAAA;4BADR,CArBZ,YAqBY,MAAA,iBAAA,GAAA;MApBT,SAAS,CAAA,EAAA;MACV,gBAAA;;6BAkBe,CAjBf,YAiBe,MAAA,oBAAA,GAAA,MAAA;8BADP,CAfN,mBAeM,OAfN,YAeM,CAbI,cAAA,UAAa,QAAA,UAAA,GADrB,mBAKM,OALN,YAKM,gBADD,MAAA,SAAA,CAAS,CAAA,0CAAA,CAAA,GAAA,CAAA,MAAA,UAAA,GAEd,YAOgB,MAAA,eAAA,GAAA;;QALd,OAAM;QACL,SAAS,cAAA;QACT,iBAAiB,kBAAA;QACjB,OAAO,MAAA,SAAA,CAAS,CAAA,0CAAA;QAChB,MAAM,oBAAA,OAAqB,QAAI;QAChC,aAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AddressBarHistory.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AddressBarHistory.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/scalar-address-bar-block/components/AddressBarHistory.vue"],"names":[],"mappings":"AAkIA,KAAK,WAAW,GAAG;IACjB,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAA;IACd,wCAAwC;IACxC,OAAO,EAAE,OAAO,EAAE,CAAA;CACnB,CAAC;AAcF,MAAM,MAAM,OAAO,GAAG;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAwRD,QAAA,MAAM,YAAY;;;eArS6B,MAAM;;;;;eAAN,MAAM;;kFAwSnD,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|