@scalar/api-client 3.11.0 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/plugins/posthog/sanitize-event-payload.d.ts.map +1 -1
  3. package/dist/plugins/posthog/sanitize-event-payload.js +1 -0
  4. package/dist/plugins/posthog/sanitize-event-payload.js.map +1 -1
  5. package/dist/style.css +15 -69
  6. package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts.map +1 -1
  7. package/dist/v2/blocks/operation-block/OperationBlock.vue.js.map +1 -1
  8. package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js +1 -1
  9. package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js.map +1 -1
  10. package/dist/v2/blocks/operation-block/helpers/validate-path-parameters.d.ts.map +1 -1
  11. package/dist/v2/blocks/operation-block/helpers/validate-path-parameters.js +1 -2
  12. package/dist/v2/blocks/operation-block/helpers/validate-path-parameters.js.map +1 -1
  13. package/dist/v2/blocks/request-block/RequestBlock.vue.d.ts +1 -1
  14. package/dist/v2/blocks/request-block/RequestBlock.vue.d.ts.map +1 -1
  15. package/dist/v2/blocks/request-block/RequestBlock.vue.js +1 -1
  16. package/dist/v2/blocks/request-block/RequestBlock.vue.js.map +1 -1
  17. package/dist/v2/blocks/request-block/RequestBlock.vue.script.js +2 -2
  18. package/dist/v2/blocks/request-block/RequestBlock.vue.script.js.map +1 -1
  19. package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.d.ts +2 -2
  20. package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.d.ts.map +1 -1
  21. package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.js.map +1 -1
  22. package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.script.js +2 -6
  23. package/dist/v2/blocks/request-block/components/RequestCodeSnippet.vue.script.js.map +1 -1
  24. package/dist/v2/blocks/request-block/helpers/create-parameter-handlers.d.ts.map +1 -1
  25. package/dist/v2/blocks/request-block/helpers/create-parameter-handlers.js +17 -3
  26. package/dist/v2/blocks/request-block/helpers/create-parameter-handlers.js.map +1 -1
  27. package/dist/v2/blocks/request-block/helpers/create-parameter-rows.d.ts.map +1 -1
  28. package/dist/v2/blocks/request-block/helpers/create-parameter-rows.js +28 -17
  29. package/dist/v2/blocks/request-block/helpers/create-parameter-rows.js.map +1 -1
  30. package/dist/v2/blocks/request-block/helpers/get-form-body-rows.js +1 -1
  31. package/dist/v2/blocks/scalar-auth-selector-block/helpers/oauth.js +1 -1
  32. package/dist/v2/components/data-table/DataTableInput.vue.d.ts +1 -1
  33. package/dist/v2/components/data-table/DataTableInput.vue.d.ts.map +1 -1
  34. package/dist/v2/constants.js +1 -1
  35. package/dist/v2/features/modal/helpers/create-api-client-modal.js +1 -1
  36. package/dist/v2/features/operation/Operation.vue.script.js +1 -1
  37. package/dist/v2/workspace-events.d.ts.map +1 -1
  38. package/dist/v2/workspace-events.js +1 -0
  39. package/dist/v2/workspace-events.js.map +1 -1
  40. package/dist/vue-styles.css +6 -48
  41. package/package.json +11 -22
  42. package/dist/v2/blocks/operation-code-sample/components/ExamplePicker.vue.d.ts +0 -16
  43. package/dist/v2/blocks/operation-code-sample/components/ExamplePicker.vue.d.ts.map +0 -1
  44. package/dist/v2/blocks/operation-code-sample/components/ExamplePicker.vue.js +0 -7
  45. package/dist/v2/blocks/operation-code-sample/components/ExamplePicker.vue.js.map +0 -1
  46. package/dist/v2/blocks/operation-code-sample/components/ExamplePicker.vue.script.js +0 -53
  47. package/dist/v2/blocks/operation-code-sample/components/ExamplePicker.vue.script.js.map +0 -1
  48. package/dist/v2/blocks/operation-code-sample/components/HttpMethod.vue.d.ts +0 -26
  49. package/dist/v2/blocks/operation-code-sample/components/HttpMethod.vue.d.ts.map +0 -1
  50. package/dist/v2/blocks/operation-code-sample/components/HttpMethod.vue.js +0 -7
  51. package/dist/v2/blocks/operation-code-sample/components/HttpMethod.vue.js.map +0 -1
  52. package/dist/v2/blocks/operation-code-sample/components/HttpMethod.vue.script.js +0 -33
  53. package/dist/v2/blocks/operation-code-sample/components/HttpMethod.vue.script.js.map +0 -1
  54. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.d.ts +0 -141
  55. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.d.ts.map +0 -1
  56. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.js +0 -9
  57. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.js.map +0 -1
  58. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.script.js +0 -272
  59. package/dist/v2/blocks/operation-code-sample/components/OperationCodeSample.vue.script.js.map +0 -1
  60. package/dist/v2/blocks/operation-code-sample/helpers/filter-clients-by-query.d.ts +0 -9
  61. package/dist/v2/blocks/operation-code-sample/helpers/filter-clients-by-query.d.ts.map +0 -1
  62. package/dist/v2/blocks/operation-code-sample/helpers/filter-clients-by-query.js +0 -37
  63. package/dist/v2/blocks/operation-code-sample/helpers/filter-clients-by-query.js.map +0 -1
  64. package/dist/v2/blocks/operation-code-sample/helpers/find-client.d.ts +0 -41
  65. package/dist/v2/blocks/operation-code-sample/helpers/find-client.d.ts.map +0 -1
  66. package/dist/v2/blocks/operation-code-sample/helpers/find-client.js +0 -48
  67. package/dist/v2/blocks/operation-code-sample/helpers/find-client.js.map +0 -1
  68. package/dist/v2/blocks/operation-code-sample/helpers/format-language.d.ts +0 -8
  69. package/dist/v2/blocks/operation-code-sample/helpers/format-language.d.ts.map +0 -1
  70. package/dist/v2/blocks/operation-code-sample/helpers/format-language.js +0 -70
  71. package/dist/v2/blocks/operation-code-sample/helpers/format-language.js.map +0 -1
  72. package/dist/v2/blocks/operation-code-sample/helpers/generate-client-options.d.ts +0 -30
  73. package/dist/v2/blocks/operation-code-sample/helpers/generate-client-options.d.ts.map +0 -1
  74. package/dist/v2/blocks/operation-code-sample/helpers/generate-client-options.js +0 -63
  75. package/dist/v2/blocks/operation-code-sample/helpers/generate-client-options.js.map +0 -1
  76. package/dist/v2/blocks/operation-code-sample/helpers/generate-code-snippet.d.ts +0 -39
  77. package/dist/v2/blocks/operation-code-sample/helpers/generate-code-snippet.d.ts.map +0 -1
  78. package/dist/v2/blocks/operation-code-sample/helpers/generate-code-snippet.js +0 -38
  79. package/dist/v2/blocks/operation-code-sample/helpers/generate-code-snippet.js.map +0 -1
  80. package/dist/v2/blocks/operation-code-sample/helpers/get-clients.d.ts +0 -13
  81. package/dist/v2/blocks/operation-code-sample/helpers/get-clients.d.ts.map +0 -1
  82. package/dist/v2/blocks/operation-code-sample/helpers/get-clients.js +0 -37
  83. package/dist/v2/blocks/operation-code-sample/helpers/get-clients.js.map +0 -1
  84. package/dist/v2/blocks/operation-code-sample/helpers/get-custom-code-samples.d.ts +0 -45
  85. package/dist/v2/blocks/operation-code-sample/helpers/get-custom-code-samples.d.ts.map +0 -1
  86. package/dist/v2/blocks/operation-code-sample/helpers/get-custom-code-samples.js +0 -84
  87. package/dist/v2/blocks/operation-code-sample/helpers/get-custom-code-samples.js.map +0 -1
  88. package/dist/v2/blocks/operation-code-sample/helpers/get-resolved-ref-deep.d.ts +0 -27
  89. package/dist/v2/blocks/operation-code-sample/helpers/get-resolved-ref-deep.d.ts.map +0 -1
  90. package/dist/v2/blocks/operation-code-sample/helpers/get-resolved-ref-deep.js +0 -41
  91. package/dist/v2/blocks/operation-code-sample/helpers/get-resolved-ref-deep.js.map +0 -1
  92. package/dist/v2/blocks/operation-code-sample/helpers/get-secrets.d.ts +0 -4
  93. package/dist/v2/blocks/operation-code-sample/helpers/get-secrets.d.ts.map +0 -1
  94. package/dist/v2/blocks/operation-code-sample/helpers/get-secrets.js +0 -18
  95. package/dist/v2/blocks/operation-code-sample/helpers/get-secrets.js.map +0 -1
  96. package/dist/v2/blocks/operation-code-sample/helpers/get-snippet.d.ts +0 -8
  97. package/dist/v2/blocks/operation-code-sample/helpers/get-snippet.d.ts.map +0 -1
  98. package/dist/v2/blocks/operation-code-sample/helpers/get-snippet.js +0 -38
  99. package/dist/v2/blocks/operation-code-sample/helpers/get-snippet.js.map +0 -1
  100. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/operation-to-har.d.ts +0 -72
  101. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/operation-to-har.d.ts.map +0 -1
  102. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/operation-to-har.js +0 -114
  103. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/operation-to-har.js.map +0 -1
  104. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-body.d.ts +0 -13
  105. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-body.d.ts.map +0 -1
  106. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-body.js +0 -196
  107. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-body.js.map +0 -1
  108. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-parameters.d.ts +0 -24
  109. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-parameters.d.ts.map +0 -1
  110. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-parameters.js +0 -237
  111. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-parameters.js.map +0 -1
  112. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-security-schemes.d.ts +0 -15
  113. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-security-schemes.d.ts.map +0 -1
  114. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-security-schemes.js +0 -65
  115. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-security-schemes.js.map +0 -1
  116. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-server-url.d.ts +0 -6
  117. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-server-url.d.ts.map +0 -1
  118. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-server-url.js +0 -19
  119. package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-server-url.js.map +0 -1
  120. package/dist/v2/blocks/operation-code-sample/index.d.ts +0 -9
  121. package/dist/v2/blocks/operation-code-sample/index.d.ts.map +0 -1
  122. package/dist/v2/blocks/operation-code-sample/index.js +0 -8
  123. package/dist/v2/blocks/operation-code-sample/types.d.ts +0 -46
  124. package/dist/v2/blocks/operation-code-sample/types.d.ts.map +0 -1
  125. package/dist/v2/blocks/request-block/helpers/is-param-disabled.d.ts +0 -13
  126. package/dist/v2/blocks/request-block/helpers/is-param-disabled.d.ts.map +0 -1
  127. package/dist/v2/blocks/request-block/helpers/is-param-disabled.js +0 -21
  128. package/dist/v2/blocks/request-block/helpers/is-param-disabled.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"RequestBlock.vue.js","names":[],"sources":["../../../../src/v2/blocks/request-block/RequestBlock.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { canMethodHaveBody } from '@scalar/helpers/http/can-method-have-body'\nimport type { HttpMethod } from '@scalar/helpers/http/http-methods'\nimport { REGEX } from '@scalar/helpers/regex/regex-helpers'\nimport { replaceEnvVariables } from '@scalar/helpers/regex/replace-variables'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type {\n ApiReferenceEvents,\n AuthMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n filterGlobalCookie,\n getEnvironmentVariables,\n getResolvedUrl,\n type MergedSecuritySchemes,\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 OperationObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, useId, watch } from 'vue'\n\nimport SectionFilter from '@/components/SectionFilter.vue'\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport type { ClientOptionGroup } from '@/v2/blocks/operation-code-sample'\nimport RequestBody from '@/v2/blocks/request-block/components/RequestBody.vue'\nimport RequestCodeSnippet from '@/v2/blocks/request-block/components/RequestCodeSnippet.vue'\nimport RequestParams from '@/v2/blocks/request-block/components/RequestParams.vue'\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport { createParameterHandlers } from '@/v2/blocks/request-block/helpers/create-parameter-handlers'\nimport { createParameterRows } from '@/v2/blocks/request-block/helpers/create-parameter-rows'\nimport { groupBy } from '@/v2/blocks/request-block/helpers/group-by'\nimport { AuthSelector } from '@/v2/blocks/scalar-auth-selector-block'\nimport type { OAuth2Options } from '@/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\ntype Filter =\n | 'All'\n | 'Auth'\n | 'Variables'\n | 'Cookies'\n | 'Headers'\n | 'Query'\n | 'Body'\n\nexport type RequestBlockProps = {\n authMeta: AuthMeta\n clientOptions: ClientOptionGroup[]\n environment: XScalarEnvironment\n eventBus: WorkspaceEventBus\n exampleKey: string\n workspaceCookies: XScalarCookie[]\n documentCookies: XScalarCookie[]\n layout: ClientLayout\n method: HttpMethod\n operation: OperationObject\n path: string\n plugins: ClientPlugin[]\n proxyUrl: string\n securityRequirements: OpenApiDocument['security']\n securitySchemes: MergedSecuritySchemes\n requestBodyCompositionSelection?: Record<string, number>\n selectedClient: WorkspaceStore['workspace']['x-scalar-default-client']\n selectedSecurity: SelectedSecurity\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n server: ServerObject | null\n defaultHeaders: Record<string, string>\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}\n\nconst {\n authMeta = { type: 'document' },\n clientOptions,\n environment,\n eventBus,\n exampleKey,\n workspaceCookies,\n documentCookies,\n layout,\n method,\n operation,\n path,\n plugins,\n proxyUrl,\n requestBodyCompositionSelection,\n securityRequirements,\n securitySchemes,\n selectedClient,\n selectedSecurity,\n selectedSecuritySchemes,\n server,\n defaultHeaders: autoGeneratedHeaders,\n} = defineProps<RequestBlockProps>()\n\n/** Operation metadata used across event emissions */\nconst meta = computed(() => ({\n method,\n path,\n exampleKey,\n}))\n\nconst deletedExpandedParameterPaths = ref<Record<string, string[][]>>({})\n\n/** Renamed expanded rows, tracked as old-schema-path -> typed-value-path per parameter. */\nconst renamedExpandedParameterPaths = ref<\n Record<string, { from: string[]; to: string[] }[]>\n>({})\n\nconst getExpandedParameterKey = (parameter: {\n in: string\n name: string\n}): string => `${parameter.in}:${parameter.name}`\n\nconst getHiddenValuePaths = (parameter: {\n in: string\n name: string\n}): string[][] =>\n deletedExpandedParameterPaths.value[getExpandedParameterKey(parameter)] ?? []\n\nconst getRenamedValuePaths = (parameter: {\n in: string\n name: string\n}): { from: string[]; to: string[] }[] =>\n renamedExpandedParameterPaths.value[getExpandedParameterKey(parameter)] ?? []\n\nconst pathsEqual = (a: string[], b: string[]): boolean =>\n a.length === b.length && a.every((segment, index) => segment === b[index])\n\n/**\n * Hides the schema path of an expanded row so it does not reappear as an empty suggestion. Used\n * both when a row is deleted and when its key is renamed (the old key should not pop back up).\n */\nconst hideExpandedRowPath = (row: TableRow): void => {\n if (!row.originalParameter || !row.sourceParameterValuePath) {\n return\n }\n\n const key = getExpandedParameterKey(row.originalParameter)\n deletedExpandedParameterPaths.value = {\n ...deletedExpandedParameterPaths.value,\n [key]: [\n ...(deletedExpandedParameterPaths.value[key] ?? []),\n row.sourceParameterValuePath,\n ],\n }\n}\n\n/**\n * Records that an expanded row was renamed from its current value path to the typed one, so the\n * read side can render the renamed key in the original property's slot instead of appending it to\n * the end of the table. Repeated renames of the same row stay anchored to the original schema path.\n */\nconst recordExpandedRowRename = (\n row: TableRow,\n newValuePath: string[],\n): void => {\n if (!row.originalParameter || !row.sourceParameterValuePath) {\n return\n }\n\n const from = row.sourceParameterValuePath\n const key = getExpandedParameterKey(row.originalParameter)\n const existing = renamedExpandedParameterPaths.value[key] ?? []\n\n // If this row was already renamed, the row's current path is the previous target. Re-anchor that\n // entry to the new target so a second rename does not create an orphaned mapping.\n const chained = existing.find((entry) => pathsEqual(entry.to, from))\n const next = chained\n ? existing.map((entry) =>\n entry === chained ? { from: entry.from, to: newValuePath } : entry,\n )\n : [...existing, { from, to: newValuePath }]\n\n renamedExpandedParameterPaths.value = {\n ...renamedExpandedParameterPaths.value,\n [key]: next,\n }\n}\n\n/** Parameters grouped by type (path, query, header, cookie) */\nconst sections = computed(() =>\n groupBy(\n operation.parameters\n ?.map((param) => getResolvedRef(param))\n .flatMap((param) =>\n createParameterRows(param, exampleKey, {\n hiddenValuePaths:\n param.in === 'query' ? getHiddenValuePaths(param) : [],\n renamedValuePaths:\n param.in === 'query' ? getRenamedValuePaths(param) : [],\n }).map((row) => ({\n ...row,\n in: param.in,\n })),\n ) ?? [],\n 'in',\n ({ in: _in, ...row }) => {\n return row as TableRow\n },\n ),\n)\n\n// Generate a reverse map for fast lookup of headers by the name\nconst headersMap = computed(() =>\n groupBy(\n sections.value.header?.map((it) => ({\n ...it,\n name: it.name.toLowerCase(),\n })) ?? [],\n 'name',\n ),\n)\n\nconst defaultHeaders = computed(() => {\n const disableParameters =\n operation['x-scalar-disable-parameters']?.['default-headers']?.[\n exampleKey\n ] ?? {}\n\n const isOverridden = (name: string) => {\n const header = headersMap.value[name.toLowerCase()]?.[0]\n\n if (!header) {\n return false\n }\n\n return !header.isDisabled\n }\n\n return Object.entries(autoGeneratedHeaders).map(([name, value]) => {\n return {\n name,\n value,\n schema: undefined,\n isOverridden: isOverridden(name),\n isReadonly: true,\n isDisabled: disableParameters[name.toLowerCase()] ?? false,\n } satisfies TableRow\n })\n})\n\nconst headers = computed(() => [\n ...defaultHeaders.value,\n ...(sections.value.header ?? []),\n])\n\nconst defaultCookies = computed(() => {\n const environmentVariables = getEnvironmentVariables(environment)\n const resolvedUrl = getResolvedUrl({\n server,\n path,\n })\n const url = replaceEnvVariables(resolvedUrl, environmentVariables)\n\n const disabledGlobalCookies =\n operation['x-scalar-disable-parameters']?.['global-cookies']?.[\n exampleKey\n ] ?? {}\n\n const transform = (\n cookie: XScalarCookie,\n location: 'document' | 'workspace',\n ) => {\n return {\n name: cookie.name,\n value: cookie.value,\n globalRoute: { page: location, path: 'cookies' } as const,\n isReadonly: true,\n isDisabled: disabledGlobalCookies[cookie.name.toLowerCase()] ?? false,\n } satisfies TableRow\n }\n\n const globalCookies = [\n {\n location: 'workspace',\n cookies: workspaceCookies,\n },\n {\n location: 'document',\n cookies: documentCookies,\n },\n ] as const\n\n return globalCookies.flatMap(({ location, cookies }) => {\n return cookies\n .filter((cookie) =>\n filterGlobalCookie({\n cookie,\n url,\n disabledGlobalCookies: {},\n }),\n )\n .map((cookie) => transform(cookie, location))\n })\n})\n\nconst cookies = computed(() => [\n ...(defaultCookies.value ?? []),\n ...(sections.value.cookie ?? []),\n])\n\n/** Currently selected filter for the request sections */\nconst selectedFilter = ref<Filter>('All')\n\n/** Available operation sections */\nconst OPERATION_SECTIONS: readonly Filter[] = [\n 'Auth',\n 'Variables',\n 'Cookies',\n 'Headers',\n 'Query',\n 'Body',\n] as const\n\n/**\n * Pre-generated stable IDs for all possible filter sections.\n * These are created once at setup time to avoid regenerating IDs on re-render.\n */\nconst sectionIds: Record<Filter, string> = {\n All: useId(),\n Auth: useId(),\n Variables: useId(),\n Cookies: useId(),\n Headers: useId(),\n Query: useId(),\n Body: useId(),\n}\n\n/** Filters available based on operation state */\nconst filters = computed<Filter[]>(() => {\n const availableFilters = new Set<Filter>(['All', ...OPERATION_SECTIONS])\n\n if (!sections.value.path?.length) {\n availableFilters.delete('Variables')\n }\n if (!canMethodHaveBody(method)) {\n availableFilters.delete('Body')\n }\n if (isAuthHidden.value) {\n availableFilters.delete('Auth')\n }\n\n return [...availableFilters]\n})\n\n/**\n * Map available filters to their pre-generated stable IDs.\n * Only includes IDs for filters that are currently available.\n */\nconst filterIds = computed(\n () =>\n Object.fromEntries(\n filters.value.map((section) => [section, sectionIds[section]]),\n ) as Record<Filter, string>,\n)\n\n/**\n * Hide auth selector in readonly mode when no security schemes are defined.\n * This keeps the UI clean when there are no authentication options available.\n */\nconst isAuthHidden = computed(\n () => layout === 'modal' && !Object.keys(securitySchemes ?? {}).length,\n)\n\n/**\n * Keep auth available for unauthenticated operations, but collapse it by default\n * in readonly modal layouts unless a requirement or manual selection exists.\n */\nconst isAuthDefaultOpen = computed(\n () =>\n layout !== 'modal' ||\n Boolean(\n securityRequirements?.length || selectedSecurity.selectedSchemes.length,\n ),\n)\n\n/** Get a sensible placeholder for the request name input */\nconst requestNamePlaceholder = computed(() => {\n if (operation.summary) {\n return operation.summary\n }\n const cleanPath = path.replace(REGEX.PROTOCOL, '')\n return cleanPath || 'Request Name'\n})\n\n/** Check if the section should be shown based on the selected filter */\nconst isSectionVisible = (section: Filter): boolean => {\n return selectedFilter.value === 'All' || selectedFilter.value === section\n}\n\n/**\n * Reset filter to 'All' if Body filter is selected but method changes to one that cannot have a body.\n * This prevents showing an empty Body section when switching methods.\n */\nwatch(\n () => method,\n (newMethod) => {\n if (selectedFilter.value === 'Body' && !canMethodHaveBody(newMethod)) {\n selectedFilter.value = 'All'\n }\n },\n)\n\n// Expanded-row bookkeeping is keyed by `in:name`, which is not unique across operations or\n// examples. Reset both maps when the operation or example changes so stale delete/rename mappings\n// do not leak onto another request that happens to share a query parameter name.\nwatch(\n () => [method, path, exampleKey],\n () => {\n deletedExpandedParameterPaths.value = {}\n renamedExpandedParameterPaths.value = {}\n },\n)\n\n/** Handle operation summary updates */\nconst handleSummaryUpdate = (event: Event): void => {\n const summary = (event.target as HTMLInputElement).value\n eventBus.emit('operation:update:meta', {\n meta: meta.value,\n payload: { summary: summary.trim() },\n })\n}\n\n/** Parameter handlers */\nconst parameterHandlers = computed(() => ({\n path: createParameterHandlers('path', eventBus, meta.value, {\n context: sections.value.path ?? [],\n }),\n cookie: createParameterHandlers('cookie', eventBus, meta.value, {\n context: cookies.value ?? [],\n globalParameters: defaultCookies.value.length,\n }),\n header: createParameterHandlers('header', eventBus, meta.value, {\n context: headers.value,\n defaultParameters: defaultHeaders.value.length,\n }),\n query: createParameterHandlers('query', eventBus, meta.value, {\n context: sections.value.query ?? [],\n onDeleteExpandedRow: hideExpandedRowPath,\n onRenameExpandedRow: recordExpandedRowRename,\n }),\n}))\n\n/** Handle request body content type update */\nconst handleUpdateContentType = (payload: { value: string }): void =>\n eventBus.emit('operation:update:requestBody:contentType', {\n payload: { contentType: payload.value },\n meta: meta.value,\n })\n\n/** Handle request body value update */\nconst handleUpdateBodyValue = ({\n payload,\n contentType,\n}: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n>): void => {\n const debounceKey =\n typeof payload === 'string'\n ? `update:requestBody:value-${contentType}`\n : undefined\n\n eventBus.emit(\n 'operation:update:requestBody:value',\n {\n payload,\n contentType,\n meta: meta.value,\n },\n {\n debounceKey,\n },\n )\n}\n\n/** Handle request body value update */\nconst handleUpdateBodyFormValue = ({\n payload,\n contentType,\n}: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n>): void => {\n const debounceKey = `update:requestBody:${contentType}-form-value`\n\n eventBus.emit(\n 'operation:update:requestBody:formValue',\n {\n payload: payload.map((row) => unpackProxyObject(row, { depth: 1 })),\n contentType,\n meta: meta.value,\n },\n {\n debounceKey,\n },\n )\n}\n\nconst labelRequestNameId = useId()\n\nconst globalCookies = computed(() => [...workspaceCookies, ...documentCookies])\n\n/** Allow updating the operation extensions for the plugins */\nconst updateOperationExtension = (\n payload: ApiReferenceEvents['operation:update:extension']['payload'],\n): void =>\n eventBus.emit('operation:update:extension', { payload, meta: meta.value })\n</script>\n<template>\n <ViewLayoutSection :aria-label=\"`Request: ${operation.summary}`\">\n <template #title>\n <div\n class=\"group pointer-events-none flex flex-1 items-center gap-1 lg:pr-24\">\n <label\n v-if=\"layout !== 'modal'\"\n class=\"pointer-events-auto absolute top-0 left-0 h-full w-full cursor-text opacity-0\"\n :for=\"labelRequestNameId\" />\n <input\n v-if=\"layout !== 'modal'\"\n :id=\"labelRequestNameId\"\n class=\"text-c-1 group-hover-input pointer-events-auto relative z-10 -ml-0.5 h-8 w-full rounded pl-1.25 has-[:focus-visible]:outline md:-ml-1.25\"\n :placeholder=\"requestNamePlaceholder\"\n :value=\"operation.summary\"\n @blur=\"handleSummaryUpdate\" />\n <span\n v-else\n class=\"text-c-1 flex h-8 items-center\">\n {{ operation.summary }}\n </span>\n </div>\n <SectionFilter\n v-model=\"selectedFilter\"\n :filterIds=\"filterIds\"\n :filters=\"filters\" />\n </template>\n\n <div\n :id=\"filterIds.All\"\n class=\"request-section-content custom-scroll relative flex flex-1 flex-col\"\n :role=\"selectedFilter === 'All' ? 'tabpanel' : 'none'\">\n <!-- Auth Selector -->\n <AuthSelector\n v-show=\"isSectionVisible('Auth') && !isAuthHidden\"\n :id=\"filterIds.Auth\"\n :createAnySecurityScheme=\"layout !== 'modal'\"\n :defaultOpen=\"isAuthDefaultOpen\"\n :environment\n :eventBus\n :meta=\"authMeta\"\n :options\n :proxyUrl\n :securityRequirements\n :securitySchemes\n :selectedSecurity\n :selectedSecuritySchemes\n :server\n title=\"Authentication\" />\n\n <!-- Variables (Path Parameters) -->\n <RequestParams\n v-show=\"isSectionVisible('Variables') && sections.path?.length\"\n :id=\"filterIds.Variables\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"sections.path ?? []\"\n :showAddRowPlaceholder=\"false\"\n title=\"Variables\"\n v-on=\"parameterHandlers.path\" />\n\n <!-- Cookies -->\n <RequestParams\n v-show=\"isSectionVisible('Cookies')\"\n :id=\"filterIds.Cookies\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"cookies ?? []\"\n :showAddRowPlaceholder=\"true\"\n title=\"Cookies\"\n v-on=\"parameterHandlers.cookie\" />\n\n <!-- Headers -->\n <RequestParams\n v-show=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"headers ?? []\"\n title=\"Headers\"\n v-on=\"parameterHandlers.header\" />\n\n <!-- Query Parameters -->\n <RequestParams\n v-show=\"isSectionVisible('Query')\"\n :id=\"filterIds.Query\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"sections.query ?? []\"\n title=\"Query Parameters\"\n v-on=\"parameterHandlers.query\" />\n\n <!-- Request Body -->\n <RequestBody\n v-show=\"isSectionVisible('Body') && canMethodHaveBody(method)\"\n :id=\"filterIds.Body\"\n :environment\n :exampleKey\n :requestBody=\"getResolvedRef(operation.requestBody)\"\n :requestBodyCompositionSelection\n title=\"Request Body\"\n @update:contentType=\"handleUpdateContentType\"\n @update:formValue=\"handleUpdateBodyFormValue\"\n @update:value=\"handleUpdateBodyValue\" />\n\n <!-- Inject request section plugin components -->\n <ScalarErrorBoundary\n v-for=\"(plugin, index) in plugins\"\n :key=\"index\">\n <component\n :is=\"plugin.components.request.component\"\n v-if=\"plugin?.components?.request\"\n v-show=\"selectedFilter === 'All'\"\n :operation\n v-bind=\"plugin.components.request.additionalProps\"\n @operation:update:extension=\"updateOperationExtension\" />\n </ScalarErrorBoundary>\n\n <!-- Spacer -->\n <div class=\"flex grow\" />\n <!-- Code Snippet -->\n <RequestCodeSnippet\n v-show=\"selectedFilter === 'All'\"\n :clientOptions\n :eventBus\n :globalCookies\n integration=\"client\"\n :method\n :operation\n :path\n :securitySchemes=\"selectedSecuritySchemes\"\n :selectedClient\n :selectedContentType=\"\n getResolvedRef(operation.requestBody)?.[\n 'x-scalar-selected-content-type'\n ]?.[exampleKey]\n \"\n :selectedServer=\"server ?? undefined\" />\n </div>\n </ViewLayoutSection>\n</template>\n<style scoped>\n.request-section-content {\n --scalar-border-width: 0.5px;\n}\n.request-section-content-filter {\n box-shadow: 0 -10px 0 10px var(--scalar-background-1);\n}\n.request-item:focus-within .request-meta-buttons {\n opacity: 1;\n}\n.group-hover-input {\n border-width: var(--scalar-border-width);\n border-color: transparent;\n}\n.group:hover .group-hover-input {\n background: color-mix(\n in srgb,\n var(--scalar-background-1),\n var(--scalar-background-2)\n );\n border-color: var(--scalar-border-color);\n}\n.group-hover-input:focus {\n background: transparent !important;\n border-color: var(--scalar-border-color) !important;\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"RequestBlock.vue.js","names":[],"sources":["../../../../src/v2/blocks/request-block/RequestBlock.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ClientOptionGroup } from '@scalar/blocks/code-example'\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { canMethodHaveBody } from '@scalar/helpers/http/can-method-have-body'\nimport type { HttpMethod } from '@scalar/helpers/http/http-methods'\nimport { REGEX } from '@scalar/helpers/regex/regex-helpers'\nimport { replaceEnvVariables } from '@scalar/helpers/regex/replace-variables'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type {\n ApiReferenceEvents,\n AuthMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n filterGlobalCookie,\n getEnvironmentVariables,\n getResolvedUrl,\n type MergedSecuritySchemes,\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 OperationObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, useId, watch } from 'vue'\n\nimport SectionFilter from '@/components/SectionFilter.vue'\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport RequestBody from '@/v2/blocks/request-block/components/RequestBody.vue'\nimport RequestCodeSnippet from '@/v2/blocks/request-block/components/RequestCodeSnippet.vue'\nimport RequestParams from '@/v2/blocks/request-block/components/RequestParams.vue'\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport { createParameterHandlers } from '@/v2/blocks/request-block/helpers/create-parameter-handlers'\nimport { createParameterRows } from '@/v2/blocks/request-block/helpers/create-parameter-rows'\nimport { groupBy } from '@/v2/blocks/request-block/helpers/group-by'\nimport { AuthSelector } from '@/v2/blocks/scalar-auth-selector-block'\nimport type { OAuth2Options } from '@/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\ntype Filter =\n | 'All'\n | 'Auth'\n | 'Variables'\n | 'Cookies'\n | 'Headers'\n | 'Query'\n | 'Body'\n\nexport type RequestBlockProps = {\n authMeta: AuthMeta\n clientOptions: ClientOptionGroup[]\n environment: XScalarEnvironment\n eventBus: WorkspaceEventBus\n exampleKey: string\n workspaceCookies: XScalarCookie[]\n documentCookies: XScalarCookie[]\n layout: ClientLayout\n method: HttpMethod\n operation: OperationObject\n path: string\n plugins: ClientPlugin[]\n proxyUrl: string\n securityRequirements: OpenApiDocument['security']\n securitySchemes: MergedSecuritySchemes\n requestBodyCompositionSelection?: Record<string, number>\n selectedClient: WorkspaceStore['workspace']['x-scalar-default-client']\n selectedSecurity: SelectedSecurity\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n server: ServerObject | null\n defaultHeaders: Record<string, string>\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}\n\nconst {\n authMeta = { type: 'document' },\n clientOptions,\n environment,\n eventBus,\n exampleKey,\n workspaceCookies,\n documentCookies,\n layout,\n method,\n operation,\n path,\n plugins,\n proxyUrl,\n requestBodyCompositionSelection,\n securityRequirements,\n securitySchemes,\n selectedClient,\n selectedSecurity,\n selectedSecuritySchemes,\n server,\n defaultHeaders: autoGeneratedHeaders,\n} = defineProps<RequestBlockProps>()\n\n/** Operation metadata used across event emissions */\nconst meta = computed(() => ({\n method,\n path,\n exampleKey,\n}))\n\nconst deletedExpandedParameterPaths = ref<Record<string, string[][]>>({})\n\n/** Renamed expanded rows, tracked as old-schema-path -> typed-value-path per parameter. */\nconst renamedExpandedParameterPaths = ref<\n Record<string, { from: string[]; to: string[] }[]>\n>({})\n\nconst getExpandedParameterKey = (parameter: {\n in: string\n name: string\n}): string => `${parameter.in}:${parameter.name}`\n\nconst getHiddenValuePaths = (parameter: {\n in: string\n name: string\n}): string[][] =>\n deletedExpandedParameterPaths.value[getExpandedParameterKey(parameter)] ?? []\n\nconst getRenamedValuePaths = (parameter: {\n in: string\n name: string\n}): { from: string[]; to: string[] }[] =>\n renamedExpandedParameterPaths.value[getExpandedParameterKey(parameter)] ?? []\n\nconst pathsEqual = (a: string[], b: string[]): boolean =>\n a.length === b.length && a.every((segment, index) => segment === b[index])\n\n/**\n * Hides the schema path of an expanded row so it does not reappear as an empty suggestion. Used\n * both when a row is deleted and when its key is renamed (the old key should not pop back up).\n */\nconst hideExpandedRowPath = (row: TableRow): void => {\n if (!row.originalParameter || !row.sourceParameterValuePath) {\n return\n }\n\n const key = getExpandedParameterKey(row.originalParameter)\n deletedExpandedParameterPaths.value = {\n ...deletedExpandedParameterPaths.value,\n [key]: [\n ...(deletedExpandedParameterPaths.value[key] ?? []),\n row.sourceParameterValuePath,\n ],\n }\n}\n\n/**\n * Records that an expanded row was renamed from its current value path to the typed one, so the\n * read side can render the renamed key in the original property's slot instead of appending it to\n * the end of the table. Repeated renames of the same row stay anchored to the original schema path.\n */\nconst recordExpandedRowRename = (\n row: TableRow,\n newValuePath: string[],\n): void => {\n if (!row.originalParameter || !row.sourceParameterValuePath) {\n return\n }\n\n const from = row.sourceParameterValuePath\n const key = getExpandedParameterKey(row.originalParameter)\n const existing = renamedExpandedParameterPaths.value[key] ?? []\n\n // If this row was already renamed, the row's current path is the previous target. Re-anchor that\n // entry to the new target so a second rename does not create an orphaned mapping.\n const chained = existing.find((entry) => pathsEqual(entry.to, from))\n const next = chained\n ? existing.map((entry) =>\n entry === chained ? { from: entry.from, to: newValuePath } : entry,\n )\n : [...existing, { from, to: newValuePath }]\n\n renamedExpandedParameterPaths.value = {\n ...renamedExpandedParameterPaths.value,\n [key]: next,\n }\n}\n\n/** Parameters grouped by type (path, query, header, cookie) */\nconst sections = computed(() =>\n groupBy(\n operation.parameters\n ?.map((param) => getResolvedRef(param))\n .flatMap((param) =>\n createParameterRows(param, exampleKey, {\n hiddenValuePaths:\n param.in === 'query' ? getHiddenValuePaths(param) : [],\n renamedValuePaths:\n param.in === 'query' ? getRenamedValuePaths(param) : [],\n }).map((row) => ({\n ...row,\n in: param.in,\n })),\n ) ?? [],\n 'in',\n ({ in: _in, ...row }) => {\n return row as TableRow\n },\n ),\n)\n\n// Generate a reverse map for fast lookup of headers by the name\nconst headersMap = computed(() =>\n groupBy(\n sections.value.header?.map((it) => ({\n ...it,\n name: it.name.toLowerCase(),\n })) ?? [],\n 'name',\n ),\n)\n\nconst defaultHeaders = computed(() => {\n const disableParameters =\n operation['x-scalar-disable-parameters']?.['default-headers']?.[\n exampleKey\n ] ?? {}\n\n const isOverridden = (name: string) => {\n const header = headersMap.value[name.toLowerCase()]?.[0]\n\n if (!header) {\n return false\n }\n\n return !header.isDisabled\n }\n\n return Object.entries(autoGeneratedHeaders).map(([name, value]) => {\n return {\n name,\n value,\n schema: undefined,\n isOverridden: isOverridden(name),\n isReadonly: true,\n isDisabled: disableParameters[name.toLowerCase()] ?? false,\n } satisfies TableRow\n })\n})\n\nconst headers = computed(() => [\n ...defaultHeaders.value,\n ...(sections.value.header ?? []),\n])\n\nconst defaultCookies = computed(() => {\n const environmentVariables = getEnvironmentVariables(environment)\n const resolvedUrl = getResolvedUrl({\n server,\n path,\n })\n const url = replaceEnvVariables(resolvedUrl, environmentVariables)\n\n const disabledGlobalCookies =\n operation['x-scalar-disable-parameters']?.['global-cookies']?.[\n exampleKey\n ] ?? {}\n\n const transform = (\n cookie: XScalarCookie,\n location: 'document' | 'workspace',\n ) => {\n return {\n name: cookie.name,\n value: cookie.value,\n globalRoute: { page: location, path: 'cookies' } as const,\n isReadonly: true,\n isDisabled: disabledGlobalCookies[cookie.name.toLowerCase()] ?? false,\n } satisfies TableRow\n }\n\n const globalCookies = [\n {\n location: 'workspace',\n cookies: workspaceCookies,\n },\n {\n location: 'document',\n cookies: documentCookies,\n },\n ] as const\n\n return globalCookies.flatMap(({ location, cookies }) => {\n return cookies\n .filter((cookie) =>\n filterGlobalCookie({\n cookie,\n url,\n disabledGlobalCookies: {},\n }),\n )\n .map((cookie) => transform(cookie, location))\n })\n})\n\nconst cookies = computed(() => [\n ...(defaultCookies.value ?? []),\n ...(sections.value.cookie ?? []),\n])\n\n/** Currently selected filter for the request sections */\nconst selectedFilter = ref<Filter>('All')\n\n/** Available operation sections */\nconst OPERATION_SECTIONS: readonly Filter[] = [\n 'Auth',\n 'Variables',\n 'Cookies',\n 'Headers',\n 'Query',\n 'Body',\n] as const\n\n/**\n * Pre-generated stable IDs for all possible filter sections.\n * These are created once at setup time to avoid regenerating IDs on re-render.\n */\nconst sectionIds: Record<Filter, string> = {\n All: useId(),\n Auth: useId(),\n Variables: useId(),\n Cookies: useId(),\n Headers: useId(),\n Query: useId(),\n Body: useId(),\n}\n\n/** Filters available based on operation state */\nconst filters = computed<Filter[]>(() => {\n const availableFilters = new Set<Filter>(['All', ...OPERATION_SECTIONS])\n\n if (!sections.value.path?.length) {\n availableFilters.delete('Variables')\n }\n if (!canMethodHaveBody(method)) {\n availableFilters.delete('Body')\n }\n if (isAuthHidden.value) {\n availableFilters.delete('Auth')\n }\n\n return [...availableFilters]\n})\n\n/**\n * Map available filters to their pre-generated stable IDs.\n * Only includes IDs for filters that are currently available.\n */\nconst filterIds = computed(\n () =>\n Object.fromEntries(\n filters.value.map((section) => [section, sectionIds[section]]),\n ) as Record<Filter, string>,\n)\n\n/**\n * Hide auth selector in readonly mode when no security schemes are defined.\n * This keeps the UI clean when there are no authentication options available.\n */\nconst isAuthHidden = computed(\n () => layout === 'modal' && !Object.keys(securitySchemes ?? {}).length,\n)\n\n/**\n * Keep auth available for unauthenticated operations, but collapse it by default\n * in readonly modal layouts unless a requirement or manual selection exists.\n */\nconst isAuthDefaultOpen = computed(\n () =>\n layout !== 'modal' ||\n Boolean(\n securityRequirements?.length || selectedSecurity.selectedSchemes.length,\n ),\n)\n\n/** Get a sensible placeholder for the request name input */\nconst requestNamePlaceholder = computed(() => {\n if (operation.summary) {\n return operation.summary\n }\n const cleanPath = path.replace(REGEX.PROTOCOL, '')\n return cleanPath || 'Request Name'\n})\n\n/** Check if the section should be shown based on the selected filter */\nconst isSectionVisible = (section: Filter): boolean => {\n return selectedFilter.value === 'All' || selectedFilter.value === section\n}\n\n/**\n * Reset filter to 'All' if Body filter is selected but method changes to one that cannot have a body.\n * This prevents showing an empty Body section when switching methods.\n */\nwatch(\n () => method,\n (newMethod) => {\n if (selectedFilter.value === 'Body' && !canMethodHaveBody(newMethod)) {\n selectedFilter.value = 'All'\n }\n },\n)\n\n// Expanded-row bookkeeping is keyed by `in:name`, which is not unique across operations or\n// examples. Reset both maps when the operation or example changes so stale delete/rename mappings\n// do not leak onto another request that happens to share a query parameter name.\nwatch(\n () => [method, path, exampleKey],\n () => {\n deletedExpandedParameterPaths.value = {}\n renamedExpandedParameterPaths.value = {}\n },\n)\n\n/** Handle operation summary updates */\nconst handleSummaryUpdate = (event: Event): void => {\n const summary = (event.target as HTMLInputElement).value\n eventBus.emit('operation:update:meta', {\n meta: meta.value,\n payload: { summary: summary.trim() },\n })\n}\n\n/** Parameter handlers */\nconst parameterHandlers = computed(() => ({\n path: createParameterHandlers('path', eventBus, meta.value, {\n context: sections.value.path ?? [],\n }),\n cookie: createParameterHandlers('cookie', eventBus, meta.value, {\n context: cookies.value ?? [],\n globalParameters: defaultCookies.value.length,\n }),\n header: createParameterHandlers('header', eventBus, meta.value, {\n context: headers.value,\n defaultParameters: defaultHeaders.value.length,\n }),\n query: createParameterHandlers('query', eventBus, meta.value, {\n context: sections.value.query ?? [],\n onDeleteExpandedRow: hideExpandedRowPath,\n onRenameExpandedRow: recordExpandedRowRename,\n }),\n}))\n\n/** Handle request body content type update */\nconst handleUpdateContentType = (payload: { value: string }): void =>\n eventBus.emit('operation:update:requestBody:contentType', {\n payload: { contentType: payload.value },\n meta: meta.value,\n })\n\n/** Handle request body value update */\nconst handleUpdateBodyValue = ({\n payload,\n contentType,\n}: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n>): void => {\n const debounceKey =\n typeof payload === 'string'\n ? `update:requestBody:value-${contentType}`\n : undefined\n\n eventBus.emit(\n 'operation:update:requestBody:value',\n {\n payload,\n contentType,\n meta: meta.value,\n },\n {\n debounceKey,\n },\n )\n}\n\n/** Handle request body value update */\nconst handleUpdateBodyFormValue = ({\n payload,\n contentType,\n}: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n>): void => {\n const debounceKey = `update:requestBody:${contentType}-form-value`\n\n eventBus.emit(\n 'operation:update:requestBody:formValue',\n {\n payload: payload.map((row) => unpackProxyObject(row, { depth: 1 })),\n contentType,\n meta: meta.value,\n },\n {\n debounceKey,\n },\n )\n}\n\nconst labelRequestNameId = useId()\n\nconst globalCookies = computed(() => [...workspaceCookies, ...documentCookies])\n\n/** Allow updating the operation extensions for the plugins */\nconst updateOperationExtension = (\n payload: ApiReferenceEvents['operation:update:extension']['payload'],\n): void =>\n eventBus.emit('operation:update:extension', { payload, meta: meta.value })\n</script>\n<template>\n <ViewLayoutSection :aria-label=\"`Request: ${operation.summary}`\">\n <template #title>\n <div\n class=\"group pointer-events-none flex flex-1 items-center gap-1 lg:pr-24\">\n <label\n v-if=\"layout !== 'modal'\"\n class=\"pointer-events-auto absolute top-0 left-0 h-full w-full cursor-text opacity-0\"\n :for=\"labelRequestNameId\" />\n <input\n v-if=\"layout !== 'modal'\"\n :id=\"labelRequestNameId\"\n class=\"text-c-1 group-hover-input pointer-events-auto relative z-10 -ml-0.5 h-8 w-full rounded pl-1.25 has-[:focus-visible]:outline md:-ml-1.25\"\n :placeholder=\"requestNamePlaceholder\"\n :value=\"operation.summary\"\n @blur=\"handleSummaryUpdate\" />\n <span\n v-else\n class=\"text-c-1 flex h-8 items-center\">\n {{ operation.summary }}\n </span>\n </div>\n <SectionFilter\n v-model=\"selectedFilter\"\n :filterIds=\"filterIds\"\n :filters=\"filters\" />\n </template>\n\n <div\n :id=\"filterIds.All\"\n class=\"request-section-content custom-scroll relative flex flex-1 flex-col\"\n :role=\"selectedFilter === 'All' ? 'tabpanel' : 'none'\">\n <!-- Auth Selector -->\n <AuthSelector\n v-show=\"isSectionVisible('Auth') && !isAuthHidden\"\n :id=\"filterIds.Auth\"\n :createAnySecurityScheme=\"layout !== 'modal'\"\n :defaultOpen=\"isAuthDefaultOpen\"\n :environment\n :eventBus\n :meta=\"authMeta\"\n :options\n :proxyUrl\n :securityRequirements\n :securitySchemes\n :selectedSecurity\n :selectedSecuritySchemes\n :server\n title=\"Authentication\" />\n\n <!-- Variables (Path Parameters) -->\n <RequestParams\n v-show=\"isSectionVisible('Variables') && sections.path?.length\"\n :id=\"filterIds.Variables\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"sections.path ?? []\"\n :showAddRowPlaceholder=\"false\"\n title=\"Variables\"\n v-on=\"parameterHandlers.path\" />\n\n <!-- Cookies -->\n <RequestParams\n v-show=\"isSectionVisible('Cookies')\"\n :id=\"filterIds.Cookies\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"cookies ?? []\"\n :showAddRowPlaceholder=\"true\"\n title=\"Cookies\"\n v-on=\"parameterHandlers.cookie\" />\n\n <!-- Headers -->\n <RequestParams\n v-show=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"headers ?? []\"\n title=\"Headers\"\n v-on=\"parameterHandlers.header\" />\n\n <!-- Query Parameters -->\n <RequestParams\n v-show=\"isSectionVisible('Query')\"\n :id=\"filterIds.Query\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"sections.query ?? []\"\n title=\"Query Parameters\"\n v-on=\"parameterHandlers.query\" />\n\n <!-- Request Body -->\n <RequestBody\n v-show=\"isSectionVisible('Body') && canMethodHaveBody(method)\"\n :id=\"filterIds.Body\"\n :environment\n :exampleKey\n :requestBody=\"getResolvedRef(operation.requestBody)\"\n :requestBodyCompositionSelection\n title=\"Request Body\"\n @update:contentType=\"handleUpdateContentType\"\n @update:formValue=\"handleUpdateBodyFormValue\"\n @update:value=\"handleUpdateBodyValue\" />\n\n <!-- Inject request section plugin components -->\n <ScalarErrorBoundary\n v-for=\"(plugin, index) in plugins\"\n :key=\"index\">\n <component\n :is=\"plugin.components.request.component\"\n v-if=\"plugin?.components?.request\"\n v-show=\"selectedFilter === 'All'\"\n :operation\n v-bind=\"plugin.components.request.additionalProps\"\n @operation:update:extension=\"updateOperationExtension\" />\n </ScalarErrorBoundary>\n\n <!-- Spacer -->\n <div class=\"flex grow\" />\n <!-- Code Snippet -->\n <RequestCodeSnippet\n v-show=\"selectedFilter === 'All'\"\n :clientOptions\n :eventBus\n :globalCookies\n integration=\"client\"\n :method\n :operation\n :path\n :securitySchemes=\"selectedSecuritySchemes\"\n :selectedClient\n :selectedContentType=\"\n getResolvedRef(operation.requestBody)?.[\n 'x-scalar-selected-content-type'\n ]?.[exampleKey]\n \"\n :selectedServer=\"server ?? undefined\" />\n </div>\n </ViewLayoutSection>\n</template>\n<style scoped>\n.request-section-content {\n --scalar-border-width: 0.5px;\n}\n.request-section-content-filter {\n box-shadow: 0 -10px 0 10px var(--scalar-background-1);\n}\n.request-item:focus-within .request-meta-buttons {\n opacity: 1;\n}\n.group-hover-input {\n border-width: var(--scalar-border-width);\n border-color: transparent;\n}\n.group:hover .group-hover-input {\n background: color-mix(\n in srgb,\n var(--scalar-background-1),\n var(--scalar-background-2)\n );\n border-color: var(--scalar-border-color);\n}\n.group-hover-input:focus {\n background: transparent !important;\n border-color: var(--scalar-border-color) !important;\n}\n</style>\n"],"mappings":""}
@@ -12,9 +12,9 @@ import { filterGlobalCookie, getEnvironmentVariables, getResolvedUrl } from "@sc
12
12
  import { REGEX } from "@scalar/helpers/regex/regex-helpers";
13
13
  import { canMethodHaveBody } from "@scalar/helpers/http/can-method-have-body";
14
14
  import { getResolvedRef } from "@scalar/workspace-store/helpers/get-resolved-ref";
15
- import { unpackProxyObject } from "@scalar/workspace-store/helpers/unpack-proxy";
16
- import { replaceEnvVariables } from "@scalar/helpers/regex/replace-variables";
17
15
  import { ScalarErrorBoundary } from "@scalar/components/error-boundary";
16
+ import { replaceEnvVariables } from "@scalar/helpers/regex/replace-variables";
17
+ import { unpackProxyObject } from "@scalar/workspace-store/helpers/unpack-proxy";
18
18
  //#region src/v2/blocks/request-block/RequestBlock.vue?vue&type=script&setup=true&lang.ts
19
19
  var _hoisted_1 = { class: "group pointer-events-none flex flex-1 items-center gap-1 lg:pr-24" };
20
20
  var _hoisted_2 = ["for"];
@@ -1 +1 @@
1
- {"version":3,"file":"RequestBlock.vue.script.js","names":[],"sources":["../../../../src/v2/blocks/request-block/RequestBlock.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { canMethodHaveBody } from '@scalar/helpers/http/can-method-have-body'\nimport type { HttpMethod } from '@scalar/helpers/http/http-methods'\nimport { REGEX } from '@scalar/helpers/regex/regex-helpers'\nimport { replaceEnvVariables } from '@scalar/helpers/regex/replace-variables'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type {\n ApiReferenceEvents,\n AuthMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n filterGlobalCookie,\n getEnvironmentVariables,\n getResolvedUrl,\n type MergedSecuritySchemes,\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 OperationObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, useId, watch } from 'vue'\n\nimport SectionFilter from '@/components/SectionFilter.vue'\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport type { ClientOptionGroup } from '@/v2/blocks/operation-code-sample'\nimport RequestBody from '@/v2/blocks/request-block/components/RequestBody.vue'\nimport RequestCodeSnippet from '@/v2/blocks/request-block/components/RequestCodeSnippet.vue'\nimport RequestParams from '@/v2/blocks/request-block/components/RequestParams.vue'\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport { createParameterHandlers } from '@/v2/blocks/request-block/helpers/create-parameter-handlers'\nimport { createParameterRows } from '@/v2/blocks/request-block/helpers/create-parameter-rows'\nimport { groupBy } from '@/v2/blocks/request-block/helpers/group-by'\nimport { AuthSelector } from '@/v2/blocks/scalar-auth-selector-block'\nimport type { OAuth2Options } from '@/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\ntype Filter =\n | 'All'\n | 'Auth'\n | 'Variables'\n | 'Cookies'\n | 'Headers'\n | 'Query'\n | 'Body'\n\nexport type RequestBlockProps = {\n authMeta: AuthMeta\n clientOptions: ClientOptionGroup[]\n environment: XScalarEnvironment\n eventBus: WorkspaceEventBus\n exampleKey: string\n workspaceCookies: XScalarCookie[]\n documentCookies: XScalarCookie[]\n layout: ClientLayout\n method: HttpMethod\n operation: OperationObject\n path: string\n plugins: ClientPlugin[]\n proxyUrl: string\n securityRequirements: OpenApiDocument['security']\n securitySchemes: MergedSecuritySchemes\n requestBodyCompositionSelection?: Record<string, number>\n selectedClient: WorkspaceStore['workspace']['x-scalar-default-client']\n selectedSecurity: SelectedSecurity\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n server: ServerObject | null\n defaultHeaders: Record<string, string>\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}\n\nconst {\n authMeta = { type: 'document' },\n clientOptions,\n environment,\n eventBus,\n exampleKey,\n workspaceCookies,\n documentCookies,\n layout,\n method,\n operation,\n path,\n plugins,\n proxyUrl,\n requestBodyCompositionSelection,\n securityRequirements,\n securitySchemes,\n selectedClient,\n selectedSecurity,\n selectedSecuritySchemes,\n server,\n defaultHeaders: autoGeneratedHeaders,\n} = defineProps<RequestBlockProps>()\n\n/** Operation metadata used across event emissions */\nconst meta = computed(() => ({\n method,\n path,\n exampleKey,\n}))\n\nconst deletedExpandedParameterPaths = ref<Record<string, string[][]>>({})\n\n/** Renamed expanded rows, tracked as old-schema-path -> typed-value-path per parameter. */\nconst renamedExpandedParameterPaths = ref<\n Record<string, { from: string[]; to: string[] }[]>\n>({})\n\nconst getExpandedParameterKey = (parameter: {\n in: string\n name: string\n}): string => `${parameter.in}:${parameter.name}`\n\nconst getHiddenValuePaths = (parameter: {\n in: string\n name: string\n}): string[][] =>\n deletedExpandedParameterPaths.value[getExpandedParameterKey(parameter)] ?? []\n\nconst getRenamedValuePaths = (parameter: {\n in: string\n name: string\n}): { from: string[]; to: string[] }[] =>\n renamedExpandedParameterPaths.value[getExpandedParameterKey(parameter)] ?? []\n\nconst pathsEqual = (a: string[], b: string[]): boolean =>\n a.length === b.length && a.every((segment, index) => segment === b[index])\n\n/**\n * Hides the schema path of an expanded row so it does not reappear as an empty suggestion. Used\n * both when a row is deleted and when its key is renamed (the old key should not pop back up).\n */\nconst hideExpandedRowPath = (row: TableRow): void => {\n if (!row.originalParameter || !row.sourceParameterValuePath) {\n return\n }\n\n const key = getExpandedParameterKey(row.originalParameter)\n deletedExpandedParameterPaths.value = {\n ...deletedExpandedParameterPaths.value,\n [key]: [\n ...(deletedExpandedParameterPaths.value[key] ?? []),\n row.sourceParameterValuePath,\n ],\n }\n}\n\n/**\n * Records that an expanded row was renamed from its current value path to the typed one, so the\n * read side can render the renamed key in the original property's slot instead of appending it to\n * the end of the table. Repeated renames of the same row stay anchored to the original schema path.\n */\nconst recordExpandedRowRename = (\n row: TableRow,\n newValuePath: string[],\n): void => {\n if (!row.originalParameter || !row.sourceParameterValuePath) {\n return\n }\n\n const from = row.sourceParameterValuePath\n const key = getExpandedParameterKey(row.originalParameter)\n const existing = renamedExpandedParameterPaths.value[key] ?? []\n\n // If this row was already renamed, the row's current path is the previous target. Re-anchor that\n // entry to the new target so a second rename does not create an orphaned mapping.\n const chained = existing.find((entry) => pathsEqual(entry.to, from))\n const next = chained\n ? existing.map((entry) =>\n entry === chained ? { from: entry.from, to: newValuePath } : entry,\n )\n : [...existing, { from, to: newValuePath }]\n\n renamedExpandedParameterPaths.value = {\n ...renamedExpandedParameterPaths.value,\n [key]: next,\n }\n}\n\n/** Parameters grouped by type (path, query, header, cookie) */\nconst sections = computed(() =>\n groupBy(\n operation.parameters\n ?.map((param) => getResolvedRef(param))\n .flatMap((param) =>\n createParameterRows(param, exampleKey, {\n hiddenValuePaths:\n param.in === 'query' ? getHiddenValuePaths(param) : [],\n renamedValuePaths:\n param.in === 'query' ? getRenamedValuePaths(param) : [],\n }).map((row) => ({\n ...row,\n in: param.in,\n })),\n ) ?? [],\n 'in',\n ({ in: _in, ...row }) => {\n return row as TableRow\n },\n ),\n)\n\n// Generate a reverse map for fast lookup of headers by the name\nconst headersMap = computed(() =>\n groupBy(\n sections.value.header?.map((it) => ({\n ...it,\n name: it.name.toLowerCase(),\n })) ?? [],\n 'name',\n ),\n)\n\nconst defaultHeaders = computed(() => {\n const disableParameters =\n operation['x-scalar-disable-parameters']?.['default-headers']?.[\n exampleKey\n ] ?? {}\n\n const isOverridden = (name: string) => {\n const header = headersMap.value[name.toLowerCase()]?.[0]\n\n if (!header) {\n return false\n }\n\n return !header.isDisabled\n }\n\n return Object.entries(autoGeneratedHeaders).map(([name, value]) => {\n return {\n name,\n value,\n schema: undefined,\n isOverridden: isOverridden(name),\n isReadonly: true,\n isDisabled: disableParameters[name.toLowerCase()] ?? false,\n } satisfies TableRow\n })\n})\n\nconst headers = computed(() => [\n ...defaultHeaders.value,\n ...(sections.value.header ?? []),\n])\n\nconst defaultCookies = computed(() => {\n const environmentVariables = getEnvironmentVariables(environment)\n const resolvedUrl = getResolvedUrl({\n server,\n path,\n })\n const url = replaceEnvVariables(resolvedUrl, environmentVariables)\n\n const disabledGlobalCookies =\n operation['x-scalar-disable-parameters']?.['global-cookies']?.[\n exampleKey\n ] ?? {}\n\n const transform = (\n cookie: XScalarCookie,\n location: 'document' | 'workspace',\n ) => {\n return {\n name: cookie.name,\n value: cookie.value,\n globalRoute: { page: location, path: 'cookies' } as const,\n isReadonly: true,\n isDisabled: disabledGlobalCookies[cookie.name.toLowerCase()] ?? false,\n } satisfies TableRow\n }\n\n const globalCookies = [\n {\n location: 'workspace',\n cookies: workspaceCookies,\n },\n {\n location: 'document',\n cookies: documentCookies,\n },\n ] as const\n\n return globalCookies.flatMap(({ location, cookies }) => {\n return cookies\n .filter((cookie) =>\n filterGlobalCookie({\n cookie,\n url,\n disabledGlobalCookies: {},\n }),\n )\n .map((cookie) => transform(cookie, location))\n })\n})\n\nconst cookies = computed(() => [\n ...(defaultCookies.value ?? []),\n ...(sections.value.cookie ?? []),\n])\n\n/** Currently selected filter for the request sections */\nconst selectedFilter = ref<Filter>('All')\n\n/** Available operation sections */\nconst OPERATION_SECTIONS: readonly Filter[] = [\n 'Auth',\n 'Variables',\n 'Cookies',\n 'Headers',\n 'Query',\n 'Body',\n] as const\n\n/**\n * Pre-generated stable IDs for all possible filter sections.\n * These are created once at setup time to avoid regenerating IDs on re-render.\n */\nconst sectionIds: Record<Filter, string> = {\n All: useId(),\n Auth: useId(),\n Variables: useId(),\n Cookies: useId(),\n Headers: useId(),\n Query: useId(),\n Body: useId(),\n}\n\n/** Filters available based on operation state */\nconst filters = computed<Filter[]>(() => {\n const availableFilters = new Set<Filter>(['All', ...OPERATION_SECTIONS])\n\n if (!sections.value.path?.length) {\n availableFilters.delete('Variables')\n }\n if (!canMethodHaveBody(method)) {\n availableFilters.delete('Body')\n }\n if (isAuthHidden.value) {\n availableFilters.delete('Auth')\n }\n\n return [...availableFilters]\n})\n\n/**\n * Map available filters to their pre-generated stable IDs.\n * Only includes IDs for filters that are currently available.\n */\nconst filterIds = computed(\n () =>\n Object.fromEntries(\n filters.value.map((section) => [section, sectionIds[section]]),\n ) as Record<Filter, string>,\n)\n\n/**\n * Hide auth selector in readonly mode when no security schemes are defined.\n * This keeps the UI clean when there are no authentication options available.\n */\nconst isAuthHidden = computed(\n () => layout === 'modal' && !Object.keys(securitySchemes ?? {}).length,\n)\n\n/**\n * Keep auth available for unauthenticated operations, but collapse it by default\n * in readonly modal layouts unless a requirement or manual selection exists.\n */\nconst isAuthDefaultOpen = computed(\n () =>\n layout !== 'modal' ||\n Boolean(\n securityRequirements?.length || selectedSecurity.selectedSchemes.length,\n ),\n)\n\n/** Get a sensible placeholder for the request name input */\nconst requestNamePlaceholder = computed(() => {\n if (operation.summary) {\n return operation.summary\n }\n const cleanPath = path.replace(REGEX.PROTOCOL, '')\n return cleanPath || 'Request Name'\n})\n\n/** Check if the section should be shown based on the selected filter */\nconst isSectionVisible = (section: Filter): boolean => {\n return selectedFilter.value === 'All' || selectedFilter.value === section\n}\n\n/**\n * Reset filter to 'All' if Body filter is selected but method changes to one that cannot have a body.\n * This prevents showing an empty Body section when switching methods.\n */\nwatch(\n () => method,\n (newMethod) => {\n if (selectedFilter.value === 'Body' && !canMethodHaveBody(newMethod)) {\n selectedFilter.value = 'All'\n }\n },\n)\n\n// Expanded-row bookkeeping is keyed by `in:name`, which is not unique across operations or\n// examples. Reset both maps when the operation or example changes so stale delete/rename mappings\n// do not leak onto another request that happens to share a query parameter name.\nwatch(\n () => [method, path, exampleKey],\n () => {\n deletedExpandedParameterPaths.value = {}\n renamedExpandedParameterPaths.value = {}\n },\n)\n\n/** Handle operation summary updates */\nconst handleSummaryUpdate = (event: Event): void => {\n const summary = (event.target as HTMLInputElement).value\n eventBus.emit('operation:update:meta', {\n meta: meta.value,\n payload: { summary: summary.trim() },\n })\n}\n\n/** Parameter handlers */\nconst parameterHandlers = computed(() => ({\n path: createParameterHandlers('path', eventBus, meta.value, {\n context: sections.value.path ?? [],\n }),\n cookie: createParameterHandlers('cookie', eventBus, meta.value, {\n context: cookies.value ?? [],\n globalParameters: defaultCookies.value.length,\n }),\n header: createParameterHandlers('header', eventBus, meta.value, {\n context: headers.value,\n defaultParameters: defaultHeaders.value.length,\n }),\n query: createParameterHandlers('query', eventBus, meta.value, {\n context: sections.value.query ?? [],\n onDeleteExpandedRow: hideExpandedRowPath,\n onRenameExpandedRow: recordExpandedRowRename,\n }),\n}))\n\n/** Handle request body content type update */\nconst handleUpdateContentType = (payload: { value: string }): void =>\n eventBus.emit('operation:update:requestBody:contentType', {\n payload: { contentType: payload.value },\n meta: meta.value,\n })\n\n/** Handle request body value update */\nconst handleUpdateBodyValue = ({\n payload,\n contentType,\n}: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n>): void => {\n const debounceKey =\n typeof payload === 'string'\n ? `update:requestBody:value-${contentType}`\n : undefined\n\n eventBus.emit(\n 'operation:update:requestBody:value',\n {\n payload,\n contentType,\n meta: meta.value,\n },\n {\n debounceKey,\n },\n )\n}\n\n/** Handle request body value update */\nconst handleUpdateBodyFormValue = ({\n payload,\n contentType,\n}: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n>): void => {\n const debounceKey = `update:requestBody:${contentType}-form-value`\n\n eventBus.emit(\n 'operation:update:requestBody:formValue',\n {\n payload: payload.map((row) => unpackProxyObject(row, { depth: 1 })),\n contentType,\n meta: meta.value,\n },\n {\n debounceKey,\n },\n )\n}\n\nconst labelRequestNameId = useId()\n\nconst globalCookies = computed(() => [...workspaceCookies, ...documentCookies])\n\n/** Allow updating the operation extensions for the plugins */\nconst updateOperationExtension = (\n payload: ApiReferenceEvents['operation:update:extension']['payload'],\n): void =>\n eventBus.emit('operation:update:extension', { payload, meta: meta.value })\n</script>\n<template>\n <ViewLayoutSection :aria-label=\"`Request: ${operation.summary}`\">\n <template #title>\n <div\n class=\"group pointer-events-none flex flex-1 items-center gap-1 lg:pr-24\">\n <label\n v-if=\"layout !== 'modal'\"\n class=\"pointer-events-auto absolute top-0 left-0 h-full w-full cursor-text opacity-0\"\n :for=\"labelRequestNameId\" />\n <input\n v-if=\"layout !== 'modal'\"\n :id=\"labelRequestNameId\"\n class=\"text-c-1 group-hover-input pointer-events-auto relative z-10 -ml-0.5 h-8 w-full rounded pl-1.25 has-[:focus-visible]:outline md:-ml-1.25\"\n :placeholder=\"requestNamePlaceholder\"\n :value=\"operation.summary\"\n @blur=\"handleSummaryUpdate\" />\n <span\n v-else\n class=\"text-c-1 flex h-8 items-center\">\n {{ operation.summary }}\n </span>\n </div>\n <SectionFilter\n v-model=\"selectedFilter\"\n :filterIds=\"filterIds\"\n :filters=\"filters\" />\n </template>\n\n <div\n :id=\"filterIds.All\"\n class=\"request-section-content custom-scroll relative flex flex-1 flex-col\"\n :role=\"selectedFilter === 'All' ? 'tabpanel' : 'none'\">\n <!-- Auth Selector -->\n <AuthSelector\n v-show=\"isSectionVisible('Auth') && !isAuthHidden\"\n :id=\"filterIds.Auth\"\n :createAnySecurityScheme=\"layout !== 'modal'\"\n :defaultOpen=\"isAuthDefaultOpen\"\n :environment\n :eventBus\n :meta=\"authMeta\"\n :options\n :proxyUrl\n :securityRequirements\n :securitySchemes\n :selectedSecurity\n :selectedSecuritySchemes\n :server\n title=\"Authentication\" />\n\n <!-- Variables (Path Parameters) -->\n <RequestParams\n v-show=\"isSectionVisible('Variables') && sections.path?.length\"\n :id=\"filterIds.Variables\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"sections.path ?? []\"\n :showAddRowPlaceholder=\"false\"\n title=\"Variables\"\n v-on=\"parameterHandlers.path\" />\n\n <!-- Cookies -->\n <RequestParams\n v-show=\"isSectionVisible('Cookies')\"\n :id=\"filterIds.Cookies\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"cookies ?? []\"\n :showAddRowPlaceholder=\"true\"\n title=\"Cookies\"\n v-on=\"parameterHandlers.cookie\" />\n\n <!-- Headers -->\n <RequestParams\n v-show=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"headers ?? []\"\n title=\"Headers\"\n v-on=\"parameterHandlers.header\" />\n\n <!-- Query Parameters -->\n <RequestParams\n v-show=\"isSectionVisible('Query')\"\n :id=\"filterIds.Query\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"sections.query ?? []\"\n title=\"Query Parameters\"\n v-on=\"parameterHandlers.query\" />\n\n <!-- Request Body -->\n <RequestBody\n v-show=\"isSectionVisible('Body') && canMethodHaveBody(method)\"\n :id=\"filterIds.Body\"\n :environment\n :exampleKey\n :requestBody=\"getResolvedRef(operation.requestBody)\"\n :requestBodyCompositionSelection\n title=\"Request Body\"\n @update:contentType=\"handleUpdateContentType\"\n @update:formValue=\"handleUpdateBodyFormValue\"\n @update:value=\"handleUpdateBodyValue\" />\n\n <!-- Inject request section plugin components -->\n <ScalarErrorBoundary\n v-for=\"(plugin, index) in plugins\"\n :key=\"index\">\n <component\n :is=\"plugin.components.request.component\"\n v-if=\"plugin?.components?.request\"\n v-show=\"selectedFilter === 'All'\"\n :operation\n v-bind=\"plugin.components.request.additionalProps\"\n @operation:update:extension=\"updateOperationExtension\" />\n </ScalarErrorBoundary>\n\n <!-- Spacer -->\n <div class=\"flex grow\" />\n <!-- Code Snippet -->\n <RequestCodeSnippet\n v-show=\"selectedFilter === 'All'\"\n :clientOptions\n :eventBus\n :globalCookies\n integration=\"client\"\n :method\n :operation\n :path\n :securitySchemes=\"selectedSecuritySchemes\"\n :selectedClient\n :selectedContentType=\"\n getResolvedRef(operation.requestBody)?.[\n 'x-scalar-selected-content-type'\n ]?.[exampleKey]\n \"\n :selectedServer=\"server ?? undefined\" />\n </div>\n </ViewLayoutSection>\n</template>\n<style scoped>\n.request-section-content {\n --scalar-border-width: 0.5px;\n}\n.request-section-content-filter {\n box-shadow: 0 -10px 0 10px var(--scalar-background-1);\n}\n.request-item:focus-within .request-meta-buttons {\n opacity: 1;\n}\n.group-hover-input {\n border-width: var(--scalar-border-width);\n border-color: transparent;\n}\n.group:hover .group-hover-input {\n background: color-mix(\n in srgb,\n var(--scalar-background-1),\n var(--scalar-background-2)\n );\n border-color: var(--scalar-border-color);\n}\n.group-hover-input:focus {\n background: transparent !important;\n border-color: var(--scalar-border-color) !important;\n}\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"RequestBlock.vue.script.js","names":[],"sources":["../../../../src/v2/blocks/request-block/RequestBlock.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ClientOptionGroup } from '@scalar/blocks/code-example'\nimport { ScalarErrorBoundary } from '@scalar/components/error-boundary'\nimport { canMethodHaveBody } from '@scalar/helpers/http/can-method-have-body'\nimport type { HttpMethod } from '@scalar/helpers/http/http-methods'\nimport { REGEX } from '@scalar/helpers/regex/regex-helpers'\nimport { replaceEnvVariables } from '@scalar/helpers/regex/replace-variables'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { SelectedSecurity } from '@scalar/workspace-store/entities/auth'\nimport type {\n ApiReferenceEvents,\n AuthMeta,\n WorkspaceEventBus,\n} from '@scalar/workspace-store/events'\nimport { getResolvedRef } from '@scalar/workspace-store/helpers/get-resolved-ref'\nimport { unpackProxyObject } from '@scalar/workspace-store/helpers/unpack-proxy'\nimport {\n filterGlobalCookie,\n getEnvironmentVariables,\n getResolvedUrl,\n type MergedSecuritySchemes,\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 OperationObject,\n ServerObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, useId, watch } from 'vue'\n\nimport SectionFilter from '@/components/SectionFilter.vue'\nimport ViewLayoutSection from '@/components/ViewLayout/ViewLayoutSection.vue'\nimport RequestBody from '@/v2/blocks/request-block/components/RequestBody.vue'\nimport RequestCodeSnippet from '@/v2/blocks/request-block/components/RequestCodeSnippet.vue'\nimport RequestParams from '@/v2/blocks/request-block/components/RequestParams.vue'\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\nimport { createParameterHandlers } from '@/v2/blocks/request-block/helpers/create-parameter-handlers'\nimport { createParameterRows } from '@/v2/blocks/request-block/helpers/create-parameter-rows'\nimport { groupBy } from '@/v2/blocks/request-block/helpers/group-by'\nimport { AuthSelector } from '@/v2/blocks/scalar-auth-selector-block'\nimport type { OAuth2Options } from '@/v2/blocks/scalar-auth-selector-block/components/OAuth2.vue'\nimport type { ClientLayout } from '@/v2/types/layout'\n\ntype Filter =\n | 'All'\n | 'Auth'\n | 'Variables'\n | 'Cookies'\n | 'Headers'\n | 'Query'\n | 'Body'\n\nexport type RequestBlockProps = {\n authMeta: AuthMeta\n clientOptions: ClientOptionGroup[]\n environment: XScalarEnvironment\n eventBus: WorkspaceEventBus\n exampleKey: string\n workspaceCookies: XScalarCookie[]\n documentCookies: XScalarCookie[]\n layout: ClientLayout\n method: HttpMethod\n operation: OperationObject\n path: string\n plugins: ClientPlugin[]\n proxyUrl: string\n securityRequirements: OpenApiDocument['security']\n securitySchemes: MergedSecuritySchemes\n requestBodyCompositionSelection?: Record<string, number>\n selectedClient: WorkspaceStore['workspace']['x-scalar-default-client']\n selectedSecurity: SelectedSecurity\n selectedSecuritySchemes: SecuritySchemeObjectSecret[]\n server: ServerObject | null\n defaultHeaders: Record<string, string>\n /** Any config options required for the OAuth2 flow */\n options?: OAuth2Options\n}\n\nconst {\n authMeta = { type: 'document' },\n clientOptions,\n environment,\n eventBus,\n exampleKey,\n workspaceCookies,\n documentCookies,\n layout,\n method,\n operation,\n path,\n plugins,\n proxyUrl,\n requestBodyCompositionSelection,\n securityRequirements,\n securitySchemes,\n selectedClient,\n selectedSecurity,\n selectedSecuritySchemes,\n server,\n defaultHeaders: autoGeneratedHeaders,\n} = defineProps<RequestBlockProps>()\n\n/** Operation metadata used across event emissions */\nconst meta = computed(() => ({\n method,\n path,\n exampleKey,\n}))\n\nconst deletedExpandedParameterPaths = ref<Record<string, string[][]>>({})\n\n/** Renamed expanded rows, tracked as old-schema-path -> typed-value-path per parameter. */\nconst renamedExpandedParameterPaths = ref<\n Record<string, { from: string[]; to: string[] }[]>\n>({})\n\nconst getExpandedParameterKey = (parameter: {\n in: string\n name: string\n}): string => `${parameter.in}:${parameter.name}`\n\nconst getHiddenValuePaths = (parameter: {\n in: string\n name: string\n}): string[][] =>\n deletedExpandedParameterPaths.value[getExpandedParameterKey(parameter)] ?? []\n\nconst getRenamedValuePaths = (parameter: {\n in: string\n name: string\n}): { from: string[]; to: string[] }[] =>\n renamedExpandedParameterPaths.value[getExpandedParameterKey(parameter)] ?? []\n\nconst pathsEqual = (a: string[], b: string[]): boolean =>\n a.length === b.length && a.every((segment, index) => segment === b[index])\n\n/**\n * Hides the schema path of an expanded row so it does not reappear as an empty suggestion. Used\n * both when a row is deleted and when its key is renamed (the old key should not pop back up).\n */\nconst hideExpandedRowPath = (row: TableRow): void => {\n if (!row.originalParameter || !row.sourceParameterValuePath) {\n return\n }\n\n const key = getExpandedParameterKey(row.originalParameter)\n deletedExpandedParameterPaths.value = {\n ...deletedExpandedParameterPaths.value,\n [key]: [\n ...(deletedExpandedParameterPaths.value[key] ?? []),\n row.sourceParameterValuePath,\n ],\n }\n}\n\n/**\n * Records that an expanded row was renamed from its current value path to the typed one, so the\n * read side can render the renamed key in the original property's slot instead of appending it to\n * the end of the table. Repeated renames of the same row stay anchored to the original schema path.\n */\nconst recordExpandedRowRename = (\n row: TableRow,\n newValuePath: string[],\n): void => {\n if (!row.originalParameter || !row.sourceParameterValuePath) {\n return\n }\n\n const from = row.sourceParameterValuePath\n const key = getExpandedParameterKey(row.originalParameter)\n const existing = renamedExpandedParameterPaths.value[key] ?? []\n\n // If this row was already renamed, the row's current path is the previous target. Re-anchor that\n // entry to the new target so a second rename does not create an orphaned mapping.\n const chained = existing.find((entry) => pathsEqual(entry.to, from))\n const next = chained\n ? existing.map((entry) =>\n entry === chained ? { from: entry.from, to: newValuePath } : entry,\n )\n : [...existing, { from, to: newValuePath }]\n\n renamedExpandedParameterPaths.value = {\n ...renamedExpandedParameterPaths.value,\n [key]: next,\n }\n}\n\n/** Parameters grouped by type (path, query, header, cookie) */\nconst sections = computed(() =>\n groupBy(\n operation.parameters\n ?.map((param) => getResolvedRef(param))\n .flatMap((param) =>\n createParameterRows(param, exampleKey, {\n hiddenValuePaths:\n param.in === 'query' ? getHiddenValuePaths(param) : [],\n renamedValuePaths:\n param.in === 'query' ? getRenamedValuePaths(param) : [],\n }).map((row) => ({\n ...row,\n in: param.in,\n })),\n ) ?? [],\n 'in',\n ({ in: _in, ...row }) => {\n return row as TableRow\n },\n ),\n)\n\n// Generate a reverse map for fast lookup of headers by the name\nconst headersMap = computed(() =>\n groupBy(\n sections.value.header?.map((it) => ({\n ...it,\n name: it.name.toLowerCase(),\n })) ?? [],\n 'name',\n ),\n)\n\nconst defaultHeaders = computed(() => {\n const disableParameters =\n operation['x-scalar-disable-parameters']?.['default-headers']?.[\n exampleKey\n ] ?? {}\n\n const isOverridden = (name: string) => {\n const header = headersMap.value[name.toLowerCase()]?.[0]\n\n if (!header) {\n return false\n }\n\n return !header.isDisabled\n }\n\n return Object.entries(autoGeneratedHeaders).map(([name, value]) => {\n return {\n name,\n value,\n schema: undefined,\n isOverridden: isOverridden(name),\n isReadonly: true,\n isDisabled: disableParameters[name.toLowerCase()] ?? false,\n } satisfies TableRow\n })\n})\n\nconst headers = computed(() => [\n ...defaultHeaders.value,\n ...(sections.value.header ?? []),\n])\n\nconst defaultCookies = computed(() => {\n const environmentVariables = getEnvironmentVariables(environment)\n const resolvedUrl = getResolvedUrl({\n server,\n path,\n })\n const url = replaceEnvVariables(resolvedUrl, environmentVariables)\n\n const disabledGlobalCookies =\n operation['x-scalar-disable-parameters']?.['global-cookies']?.[\n exampleKey\n ] ?? {}\n\n const transform = (\n cookie: XScalarCookie,\n location: 'document' | 'workspace',\n ) => {\n return {\n name: cookie.name,\n value: cookie.value,\n globalRoute: { page: location, path: 'cookies' } as const,\n isReadonly: true,\n isDisabled: disabledGlobalCookies[cookie.name.toLowerCase()] ?? false,\n } satisfies TableRow\n }\n\n const globalCookies = [\n {\n location: 'workspace',\n cookies: workspaceCookies,\n },\n {\n location: 'document',\n cookies: documentCookies,\n },\n ] as const\n\n return globalCookies.flatMap(({ location, cookies }) => {\n return cookies\n .filter((cookie) =>\n filterGlobalCookie({\n cookie,\n url,\n disabledGlobalCookies: {},\n }),\n )\n .map((cookie) => transform(cookie, location))\n })\n})\n\nconst cookies = computed(() => [\n ...(defaultCookies.value ?? []),\n ...(sections.value.cookie ?? []),\n])\n\n/** Currently selected filter for the request sections */\nconst selectedFilter = ref<Filter>('All')\n\n/** Available operation sections */\nconst OPERATION_SECTIONS: readonly Filter[] = [\n 'Auth',\n 'Variables',\n 'Cookies',\n 'Headers',\n 'Query',\n 'Body',\n] as const\n\n/**\n * Pre-generated stable IDs for all possible filter sections.\n * These are created once at setup time to avoid regenerating IDs on re-render.\n */\nconst sectionIds: Record<Filter, string> = {\n All: useId(),\n Auth: useId(),\n Variables: useId(),\n Cookies: useId(),\n Headers: useId(),\n Query: useId(),\n Body: useId(),\n}\n\n/** Filters available based on operation state */\nconst filters = computed<Filter[]>(() => {\n const availableFilters = new Set<Filter>(['All', ...OPERATION_SECTIONS])\n\n if (!sections.value.path?.length) {\n availableFilters.delete('Variables')\n }\n if (!canMethodHaveBody(method)) {\n availableFilters.delete('Body')\n }\n if (isAuthHidden.value) {\n availableFilters.delete('Auth')\n }\n\n return [...availableFilters]\n})\n\n/**\n * Map available filters to their pre-generated stable IDs.\n * Only includes IDs for filters that are currently available.\n */\nconst filterIds = computed(\n () =>\n Object.fromEntries(\n filters.value.map((section) => [section, sectionIds[section]]),\n ) as Record<Filter, string>,\n)\n\n/**\n * Hide auth selector in readonly mode when no security schemes are defined.\n * This keeps the UI clean when there are no authentication options available.\n */\nconst isAuthHidden = computed(\n () => layout === 'modal' && !Object.keys(securitySchemes ?? {}).length,\n)\n\n/**\n * Keep auth available for unauthenticated operations, but collapse it by default\n * in readonly modal layouts unless a requirement or manual selection exists.\n */\nconst isAuthDefaultOpen = computed(\n () =>\n layout !== 'modal' ||\n Boolean(\n securityRequirements?.length || selectedSecurity.selectedSchemes.length,\n ),\n)\n\n/** Get a sensible placeholder for the request name input */\nconst requestNamePlaceholder = computed(() => {\n if (operation.summary) {\n return operation.summary\n }\n const cleanPath = path.replace(REGEX.PROTOCOL, '')\n return cleanPath || 'Request Name'\n})\n\n/** Check if the section should be shown based on the selected filter */\nconst isSectionVisible = (section: Filter): boolean => {\n return selectedFilter.value === 'All' || selectedFilter.value === section\n}\n\n/**\n * Reset filter to 'All' if Body filter is selected but method changes to one that cannot have a body.\n * This prevents showing an empty Body section when switching methods.\n */\nwatch(\n () => method,\n (newMethod) => {\n if (selectedFilter.value === 'Body' && !canMethodHaveBody(newMethod)) {\n selectedFilter.value = 'All'\n }\n },\n)\n\n// Expanded-row bookkeeping is keyed by `in:name`, which is not unique across operations or\n// examples. Reset both maps when the operation or example changes so stale delete/rename mappings\n// do not leak onto another request that happens to share a query parameter name.\nwatch(\n () => [method, path, exampleKey],\n () => {\n deletedExpandedParameterPaths.value = {}\n renamedExpandedParameterPaths.value = {}\n },\n)\n\n/** Handle operation summary updates */\nconst handleSummaryUpdate = (event: Event): void => {\n const summary = (event.target as HTMLInputElement).value\n eventBus.emit('operation:update:meta', {\n meta: meta.value,\n payload: { summary: summary.trim() },\n })\n}\n\n/** Parameter handlers */\nconst parameterHandlers = computed(() => ({\n path: createParameterHandlers('path', eventBus, meta.value, {\n context: sections.value.path ?? [],\n }),\n cookie: createParameterHandlers('cookie', eventBus, meta.value, {\n context: cookies.value ?? [],\n globalParameters: defaultCookies.value.length,\n }),\n header: createParameterHandlers('header', eventBus, meta.value, {\n context: headers.value,\n defaultParameters: defaultHeaders.value.length,\n }),\n query: createParameterHandlers('query', eventBus, meta.value, {\n context: sections.value.query ?? [],\n onDeleteExpandedRow: hideExpandedRowPath,\n onRenameExpandedRow: recordExpandedRowRename,\n }),\n}))\n\n/** Handle request body content type update */\nconst handleUpdateContentType = (payload: { value: string }): void =>\n eventBus.emit('operation:update:requestBody:contentType', {\n payload: { contentType: payload.value },\n meta: meta.value,\n })\n\n/** Handle request body value update */\nconst handleUpdateBodyValue = ({\n payload,\n contentType,\n}: Pick<\n ApiReferenceEvents['operation:update:requestBody:value'],\n 'payload' | 'contentType'\n>): void => {\n const debounceKey =\n typeof payload === 'string'\n ? `update:requestBody:value-${contentType}`\n : undefined\n\n eventBus.emit(\n 'operation:update:requestBody:value',\n {\n payload,\n contentType,\n meta: meta.value,\n },\n {\n debounceKey,\n },\n )\n}\n\n/** Handle request body value update */\nconst handleUpdateBodyFormValue = ({\n payload,\n contentType,\n}: Pick<\n ApiReferenceEvents['operation:update:requestBody:formValue'],\n 'payload' | 'contentType'\n>): void => {\n const debounceKey = `update:requestBody:${contentType}-form-value`\n\n eventBus.emit(\n 'operation:update:requestBody:formValue',\n {\n payload: payload.map((row) => unpackProxyObject(row, { depth: 1 })),\n contentType,\n meta: meta.value,\n },\n {\n debounceKey,\n },\n )\n}\n\nconst labelRequestNameId = useId()\n\nconst globalCookies = computed(() => [...workspaceCookies, ...documentCookies])\n\n/** Allow updating the operation extensions for the plugins */\nconst updateOperationExtension = (\n payload: ApiReferenceEvents['operation:update:extension']['payload'],\n): void =>\n eventBus.emit('operation:update:extension', { payload, meta: meta.value })\n</script>\n<template>\n <ViewLayoutSection :aria-label=\"`Request: ${operation.summary}`\">\n <template #title>\n <div\n class=\"group pointer-events-none flex flex-1 items-center gap-1 lg:pr-24\">\n <label\n v-if=\"layout !== 'modal'\"\n class=\"pointer-events-auto absolute top-0 left-0 h-full w-full cursor-text opacity-0\"\n :for=\"labelRequestNameId\" />\n <input\n v-if=\"layout !== 'modal'\"\n :id=\"labelRequestNameId\"\n class=\"text-c-1 group-hover-input pointer-events-auto relative z-10 -ml-0.5 h-8 w-full rounded pl-1.25 has-[:focus-visible]:outline md:-ml-1.25\"\n :placeholder=\"requestNamePlaceholder\"\n :value=\"operation.summary\"\n @blur=\"handleSummaryUpdate\" />\n <span\n v-else\n class=\"text-c-1 flex h-8 items-center\">\n {{ operation.summary }}\n </span>\n </div>\n <SectionFilter\n v-model=\"selectedFilter\"\n :filterIds=\"filterIds\"\n :filters=\"filters\" />\n </template>\n\n <div\n :id=\"filterIds.All\"\n class=\"request-section-content custom-scroll relative flex flex-1 flex-col\"\n :role=\"selectedFilter === 'All' ? 'tabpanel' : 'none'\">\n <!-- Auth Selector -->\n <AuthSelector\n v-show=\"isSectionVisible('Auth') && !isAuthHidden\"\n :id=\"filterIds.Auth\"\n :createAnySecurityScheme=\"layout !== 'modal'\"\n :defaultOpen=\"isAuthDefaultOpen\"\n :environment\n :eventBus\n :meta=\"authMeta\"\n :options\n :proxyUrl\n :securityRequirements\n :securitySchemes\n :selectedSecurity\n :selectedSecuritySchemes\n :server\n title=\"Authentication\" />\n\n <!-- Variables (Path Parameters) -->\n <RequestParams\n v-show=\"isSectionVisible('Variables') && sections.path?.length\"\n :id=\"filterIds.Variables\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"sections.path ?? []\"\n :showAddRowPlaceholder=\"false\"\n title=\"Variables\"\n v-on=\"parameterHandlers.path\" />\n\n <!-- Cookies -->\n <RequestParams\n v-show=\"isSectionVisible('Cookies')\"\n :id=\"filterIds.Cookies\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"cookies ?? []\"\n :showAddRowPlaceholder=\"true\"\n title=\"Cookies\"\n v-on=\"parameterHandlers.cookie\" />\n\n <!-- Headers -->\n <RequestParams\n v-show=\"isSectionVisible('Headers')\"\n :id=\"filterIds.Headers\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"headers ?? []\"\n title=\"Headers\"\n v-on=\"parameterHandlers.header\" />\n\n <!-- Query Parameters -->\n <RequestParams\n v-show=\"isSectionVisible('Query')\"\n :id=\"filterIds.Query\"\n :environment\n :eventBus\n :exampleKey\n :rows=\"sections.query ?? []\"\n title=\"Query Parameters\"\n v-on=\"parameterHandlers.query\" />\n\n <!-- Request Body -->\n <RequestBody\n v-show=\"isSectionVisible('Body') && canMethodHaveBody(method)\"\n :id=\"filterIds.Body\"\n :environment\n :exampleKey\n :requestBody=\"getResolvedRef(operation.requestBody)\"\n :requestBodyCompositionSelection\n title=\"Request Body\"\n @update:contentType=\"handleUpdateContentType\"\n @update:formValue=\"handleUpdateBodyFormValue\"\n @update:value=\"handleUpdateBodyValue\" />\n\n <!-- Inject request section plugin components -->\n <ScalarErrorBoundary\n v-for=\"(plugin, index) in plugins\"\n :key=\"index\">\n <component\n :is=\"plugin.components.request.component\"\n v-if=\"plugin?.components?.request\"\n v-show=\"selectedFilter === 'All'\"\n :operation\n v-bind=\"plugin.components.request.additionalProps\"\n @operation:update:extension=\"updateOperationExtension\" />\n </ScalarErrorBoundary>\n\n <!-- Spacer -->\n <div class=\"flex grow\" />\n <!-- Code Snippet -->\n <RequestCodeSnippet\n v-show=\"selectedFilter === 'All'\"\n :clientOptions\n :eventBus\n :globalCookies\n integration=\"client\"\n :method\n :operation\n :path\n :securitySchemes=\"selectedSecuritySchemes\"\n :selectedClient\n :selectedContentType=\"\n getResolvedRef(operation.requestBody)?.[\n 'x-scalar-selected-content-type'\n ]?.[exampleKey]\n \"\n :selectedServer=\"server ?? undefined\" />\n </div>\n </ViewLayoutSection>\n</template>\n<style scoped>\n.request-section-content {\n --scalar-border-width: 0.5px;\n}\n.request-section-content-filter {\n box-shadow: 0 -10px 0 10px var(--scalar-background-1);\n}\n.request-item:focus-within .request-meta-buttons {\n opacity: 1;\n}\n.group-hover-input {\n border-width: var(--scalar-border-width);\n border-color: transparent;\n}\n.group:hover .group-hover-input {\n background: color-mix(\n in srgb,\n var(--scalar-background-1),\n var(--scalar-background-2)\n );\n border-color: var(--scalar-border-color);\n}\n.group-hover-input:focus {\n background: transparent !important;\n border-color: var(--scalar-border-color) !important;\n}\n</style>\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
+ import { type CodeExampleProps } from '@scalar/blocks/code-example';
1
2
  import type { WorkspaceEventBus } from '@scalar/workspace-store/events';
2
- import type { OperationCodeSampleProps } from '../../../../v2/blocks/operation-code-sample/components/OperationCodeSample.vue.js';
3
- type __VLS_Props = OperationCodeSampleProps & {
3
+ type __VLS_Props = CodeExampleProps & {
4
4
  eventBus: WorkspaceEventBus;
5
5
  };
6
6
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -1 +1 @@
1
- {"version":3,"file":"RequestCodeSnippet.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestCodeSnippet.vue"],"names":[],"mappings":"AAuKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAQvE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sEAAsE,CAAA;AAQpH,KAAK,WAAW,GAAG,wBAAwB,GAAG;IAAE,QAAQ,EAAE,iBAAiB,CAAA;CAAE,CAAC;AA2S9E,QAAA,MAAM,YAAY,kSAEhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
1
+ {"version":3,"file":"RequestCodeSnippet.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/components/RequestCodeSnippet.vue"],"names":[],"mappings":"AAkKA,OAAO,EAOL,KAAK,gBAAgB,EAEtB,MAAM,6BAA6B,CAAA;AAMpC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAMvE,KAAK,WAAW,GAAG,gBAAgB,GAAG;IAAE,QAAQ,EAAE,iBAAiB,CAAA;CAAE,CAAC;AA2StE,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 { 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 {\n findClient,\n type ClientOption,\n type CustomClientOption,\n} from '@/v2/blocks/operation-code-sample'\nimport type { OperationCodeSampleProps } from '@/v2/blocks/operation-code-sample/components/OperationCodeSample.vue'\nimport { generateCodeSnippet } from '@/v2/blocks/operation-code-sample/helpers/generate-code-snippet'\nimport { getClients } from '@/v2/blocks/operation-code-sample/helpers/get-clients'\nimport { getCustomCodeSamples } from '@/v2/blocks/operation-code-sample/helpers/get-custom-code-samples'\nimport { getSecrets } from '@/v2/blocks/operation-code-sample/helpers/get-secrets'\nimport { DataTable, DataTableRow } from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\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 integration,\n} = defineProps<OperationCodeSampleProps & { eventBus: WorkspaceEventBus }>()\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>(() =>\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 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-show=\"hasClients\"\n class=\"group/preview w-full border-t\"\n :defaultOpen=\"false\">\n <template #title>Code Snippet</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 <ScalarCodeBlock\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'\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 integration,\n} = defineProps<CodeExampleProps & { eventBus: WorkspaceEventBus }>()\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>(() =>\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 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-show=\"hasClients\"\n class=\"group/preview w-full border-t\"\n :defaultOpen=\"false\">\n <template #title>Code Snippet</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 <ScalarCodeBlock\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,17 +1,13 @@
1
1
  import DataTable_default from "../../../components/data-table/DataTable.vue.js";
2
2
  import DataTableRow_default from "../../../components/data-table/DataTableRow.vue.js";
3
- import { findClient } from "../../operation-code-sample/helpers/find-client.js";
4
- import { getCustomCodeSamples } from "../../operation-code-sample/helpers/get-custom-code-samples.js";
5
- import { getClients } from "../../operation-code-sample/helpers/get-clients.js";
6
- import { getSecrets } from "../../operation-code-sample/helpers/get-secrets.js";
7
- import { generateCodeSnippet } from "../../operation-code-sample/helpers/generate-code-snippet.js";
8
3
  import CollapsibleSection_default from "../../../components/layout/CollapsibleSection.vue.js";
9
4
  import { computed, createBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, openBlock, ref, toDisplayString, unref, vShow, watch, withCtx, withDirectives } from "vue";
10
5
  import { ScalarButton } from "@scalar/components/button";
11
6
  import { ScalarIconCaretDown } from "@scalar/icons";
12
7
  import { ScalarCombobox } from "@scalar/components/combobox";
13
- import { ScalarCodeBlock } from "@scalar/components/code-block";
8
+ import { findClient, generateCodeSnippet, getClients, getCustomCodeSamples, getSecrets } from "@scalar/blocks/code-example";
14
9
  import { ScalarErrorBoundary } from "@scalar/components/error-boundary";
10
+ import { ScalarCodeBlock } from "@scalar/components/code-block";
15
11
  //#region src/v2/blocks/request-block/components/RequestCodeSnippet.vue?vue&type=script&setup=true&lang.ts
16
12
  var _hoisted_1 = { class: "flex flex-1" };
17
13
  var _hoisted_2 = { class: "overflow-hidden" };
@@ -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 { 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 {\n findClient,\n type ClientOption,\n type CustomClientOption,\n} from '@/v2/blocks/operation-code-sample'\nimport type { OperationCodeSampleProps } from '@/v2/blocks/operation-code-sample/components/OperationCodeSample.vue'\nimport { generateCodeSnippet } from '@/v2/blocks/operation-code-sample/helpers/generate-code-snippet'\nimport { getClients } from '@/v2/blocks/operation-code-sample/helpers/get-clients'\nimport { getCustomCodeSamples } from '@/v2/blocks/operation-code-sample/helpers/get-custom-code-samples'\nimport { getSecrets } from '@/v2/blocks/operation-code-sample/helpers/get-secrets'\nimport { DataTable, DataTableRow } from '@/v2/components/data-table'\nimport { CollapsibleSection } from '@/v2/components/layout'\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 integration,\n} = defineProps<OperationCodeSampleProps & { eventBus: WorkspaceEventBus }>()\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>(() =>\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 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-show=\"hasClients\"\n class=\"group/preview w-full border-t\"\n :defaultOpen=\"false\">\n <template #title>Code Snippet</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 <ScalarCodeBlock\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsCA,MAAM,oBAAoB,eAAe,qBAAqB,QAAA,UAAU,CAAA;;EAGxE,MAAM,UAAU,eACd,WACE,kBAAkB,MAAM,SACxB,QAAA,eACA,kBAAkB,MAAM,MACzB,CACH;;;;;EAMA,MAAM,sBAAsB,IAC1B,WAAW,QAAQ,OAAO,QAAA,eAAe,CAC3C;;;;;;;AAQA,QAAM,OAAO,QAAA,gBAAgB,QAAQ,GAAG,CAAC,eAAe;GACtD,MAAM,SAAS,WAAW,QAAQ,OAAO,UAAS;AAClD,OAAI,OACF,qBAAoB,QAAQ;IAE/B;;EAGD,MAAM,oBAAoB,eAAe,WAAW,QAAA,mBAAmB,EAAE,CAAC,CAAA;;EAG1E,MAAM,sBAAsB,WAAqC;AAC/D,uBAAoB,QAAQ;AAG5B,OAAI,OACF,SAAA,SAAS,KAAK,oCAAoC,OAAO,GAAE;;;EAK/D,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,uBAAuB,QAAA,gBAAgB;GACxC,CAAC,CACJ;;EAGA,MAAM,aAAa,eACjB,QAAQ,MAAM,MAAM,UAAU,MAAM,QAAQ,SAAS,EAAE,CACzD;;uCAIE,YAiDqB,MAAA,2BAAA,EAAA;IA/CnB,OAAM;IACL,aAAa;;IACH,OAAK,cAAa,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAAZ,gBAAY,GAAA,CAAA,EAAA,CAAA;IAGlB,SAAO,cAsBV,CArBN,mBAqBM,OArBN,YAqBM,CApBJ,YAmBiB,MAAA,eAAA,EAAA;KAlBd,YAAY,oBAAA;KACZ,SAAS,QAAA;KACV,WAAU;KACT,uBAAiB,OAAA,OAAA,OAAA,MAAgB,OAAO,mBAAmB,GAAE;;KAGnD,SAAO,SAUD,EAVK,WAAI,CACxB,YASe,MAAA,aAAA,EAAA;MARb,OAAM;MACN,eAAY;MACZ,SAAQ;;6BACwB,CAAA,gBAAA,gBAA7B,oBAAA,OAAqB,MAAK,GAAG,KAChC,EAAA,EAAA,YAGkB,MAAA,oBAAA,EAAA;OAFhB,OAAK,eAAA,CAAC,oDACE,QAAI,aAAA,CAAA;OACZ,QAAO;;;;;;2BAuBG,CAftB,YAesB,MAAA,oBAAA,EAAA,MAAA;4BADR,CAbZ,YAaY,MAAA,kBAAA,EAAA;MAZT,SAAS,CAAA,GAAI;MACd,gBAAA;;6BAUe,CATf,YASe,MAAA,qBAAA,EAAA,MAAA;8BADP,CAPN,mBAOM,OAPN,YAOM,CANJ,YAKgB,MAAA,gBAAA,EAAA;QAJd,OAAM;QACL,SAAS,cAAA;QACT,iBAAiB,kBAAA;QACjB,MAAM,oBAAA,OAAqB,QAAI;QAChC,aAAA;;;;;;;;;;;;;sBA3CF,WAAA,MAAU,CAAA,CAAA"}
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'\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 integration,\n} = defineProps<CodeExampleProps & { eventBus: WorkspaceEventBus }>()\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>(() =>\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 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-show=\"hasClients\"\n class=\"group/preview w-full border-t\"\n :defaultOpen=\"false\">\n <template #title>Code Snippet</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 <ScalarCodeBlock\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsCA,MAAM,oBAAoB,eAAe,qBAAqB,QAAA,UAAU,CAAA;;EAGxE,MAAM,UAAU,eACd,WACE,kBAAkB,MAAM,SACxB,QAAA,eACA,kBAAkB,MAAM,MACzB,CACH;;;;;EAMA,MAAM,sBAAsB,IAC1B,WAAW,QAAQ,OAAO,QAAA,eAAe,CAC3C;;;;;;;AAQA,QAAM,OAAO,QAAA,gBAAgB,QAAQ,GAAG,CAAC,eAAe;GACtD,MAAM,SAAS,WAAW,QAAQ,OAAO,UAAS;AAClD,OAAI,OACF,qBAAoB,QAAQ;IAE/B;;EAGD,MAAM,oBAAoB,eAAe,WAAW,QAAA,mBAAmB,EAAE,CAAC,CAAA;;EAG1E,MAAM,sBAAsB,WAAqC;AAC/D,uBAAoB,QAAQ;AAG5B,OAAI,OACF,SAAA,SAAS,KAAK,oCAAoC,OAAO,GAAE;;;EAK/D,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,uBAAuB,QAAA,gBAAgB;GACxC,CAAC,CACJ;;EAGA,MAAM,aAAa,eACjB,QAAQ,MAAM,MAAM,UAAU,MAAM,QAAQ,SAAS,EAAE,CACzD;;uCAIE,YAiDqB,MAAA,2BAAA,EAAA;IA/CnB,OAAM;IACL,aAAa;;IACH,OAAK,cAAa,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAAZ,gBAAY,GAAA,CAAA,EAAA,CAAA;IAGlB,SAAO,cAsBV,CArBN,mBAqBM,OArBN,YAqBM,CApBJ,YAmBiB,MAAA,eAAA,EAAA;KAlBd,YAAY,oBAAA;KACZ,SAAS,QAAA;KACV,WAAU;KACT,uBAAiB,OAAA,OAAA,OAAA,MAAgB,OAAO,mBAAmB,GAAE;;KAGnD,SAAO,SAUD,EAVK,WAAI,CACxB,YASe,MAAA,aAAA,EAAA;MARb,OAAM;MACN,eAAY;MACZ,SAAQ;;6BACwB,CAAA,gBAAA,gBAA7B,oBAAA,OAAqB,MAAK,GAAG,KAChC,EAAA,EAAA,YAGkB,MAAA,oBAAA,EAAA;OAFhB,OAAK,eAAA,CAAC,oDACE,QAAI,aAAA,CAAA;OACZ,QAAO;;;;;;2BAuBG,CAftB,YAesB,MAAA,oBAAA,EAAA,MAAA;4BADR,CAbZ,YAaY,MAAA,kBAAA,EAAA;MAZT,SAAS,CAAA,GAAI;MACd,gBAAA;;6BAUe,CATf,YASe,MAAA,qBAAA,EAAA,MAAA;8BADP,CAPN,mBAOM,OAPN,YAOM,CANJ,YAKgB,MAAA,gBAAA,EAAA;QAJd,OAAM;QACL,SAAS,cAAA;QACT,iBAAiB,kBAAA;QACjB,MAAM,oBAAA,OAAqB,QAAI;QAChC,aAAA;;;;;;;;;;;;;sBA3CF,WAAA,MAAU,CAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"create-parameter-handlers.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/helpers/create-parameter-handlers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAE7F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0DAA0D,CAAA;AAExF,KAAK,aAAa,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAA;AAE3D,KAAK,sBAAsB,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,OAAO,CAAA;IACnB,uBAAuB,CAAC,EAAE,OAAO,CAAA;CAClC,CAAA;AA0ED,uDAAuD;AACvD,eAAO,MAAM,uBAAuB,GAClC,MAAM,aAAa,EACnB,UAAU,iBAAiB,EAC3B,MAAM,oBAAoB,EAC1B,6FAMG;IACD,OAAO,EAAE,QAAQ,EAAE,CAAA;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAA;IAC7C,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,IAAI,CAAA;CACtE;sBAKmB;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE;;oBAuCnB,MAAM,WAAW,sBAAsB;CA+C1D,CAAA"}
1
+ {"version":3,"file":"create-parameter-handlers.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/helpers/create-parameter-handlers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAG7F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0DAA0D,CAAA;AAExF,KAAK,aAAa,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAA;AAE3D,KAAK,sBAAsB,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,OAAO,CAAA;IACnB,uBAAuB,CAAC,EAAE,OAAO,CAAA;CAClC,CAAA;AAkHD,uDAAuD;AACvD,eAAO,MAAM,uBAAuB,GAClC,MAAM,aAAa,EACnB,UAAU,iBAAiB,EAC3B,MAAM,oBAAoB,EAC1B,6FAMG;IACD,OAAO,EAAE,QAAQ,EAAE,CAAA;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAA;IAC7C,mBAAmB,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,IAAI,CAAA;CACtE;sBAKmB;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE;;oBAuCnB,MAAM,WAAW,sBAAsB;CA+C1D,CAAA"}
@@ -1,12 +1,21 @@
1
+ import { deSerializeSchemaValue } from "@scalar/workspace-store/request-example";
1
2
  import { setValueAtPath } from "@scalar/helpers/object/set-value-at-path";
2
3
  //#region src/v2/blocks/request-block/helpers/create-parameter-handlers.ts
3
4
  var isEmptyValue = (value) => value === void 0 || value === null || value === "";
5
+ /**
6
+ * Whether a row name carries the display-only deepObject array marker (`filters[id][in][]`). The
7
+ * marker is only ever appended after a real path bracket, so it always shows up as `][]`. That lets
8
+ * us tell it apart from a genuinely empty key: an interior empty (`filters[][in]`) or a lone empty
9
+ * group (`filters[]`, value path `['']`) is not a marker and keeps its segment.
10
+ */
11
+ var hasArrayMarker = (name) => name.endsWith("][]");
4
12
  /** Parse a parameter key like `filter[a][b]` into its path segments `['filter', 'a', 'b']`. */
5
13
  var parseBracketKey = (name) => {
14
+ const withoutArrayMarker = hasArrayMarker(name) ? name.slice(0, -2) : name;
6
15
  const segments = [];
7
- const head = name.match(/^[^[\]]*/)?.[0] ?? "";
16
+ const head = withoutArrayMarker.match(/^[^[\]]*/)?.[0] ?? "";
8
17
  if (head) segments.push(head);
9
- for (const match of name.matchAll(/\[([^\]]*)\]/g)) segments.push(match[1] ?? "");
18
+ for (const match of withoutArrayMarker.matchAll(/\[([^\]]*)\]/g)) segments.push(match[1] ?? "");
10
19
  return segments;
11
20
  };
12
21
  /**
@@ -23,13 +32,18 @@ var getEditedValuePath = (typedName, parameterName, fallback) => {
23
32
  };
24
33
  var getExpandedObjectPayload = (row, context, payload) => {
25
34
  const value = {};
35
+ const parameter = row.originalParameter;
36
+ const isDeepObjectParameter = Boolean(parameter && "style" in parameter && parameter.style === "deepObject");
26
37
  for (const contextRow of context) {
27
38
  if (contextRow.originalParameter !== row.originalParameter || !contextRow.sourceParameterValuePath) continue;
28
39
  if (contextRow === row && !payload) continue;
29
40
  const isEditedRow = contextRow === row && payload !== void 0;
30
41
  const nextValue = isEditedRow ? payload.value : contextRow.value;
31
42
  if (isEmptyValue(nextValue)) continue;
32
- setValueAtPath(value, isEditedRow ? payload.shouldRenameExpandedRow ? getEditedValuePath(payload.name, row.originalParameter?.name, contextRow.sourceParameterValuePath) : contextRow.sourceParameterValuePath : contextRow.sourceParameterValuePath, nextValue);
43
+ const path = isEditedRow ? payload.shouldRenameExpandedRow ? getEditedValuePath(payload.name, row.originalParameter?.name, contextRow.sourceParameterValuePath) : contextRow.sourceParameterValuePath : contextRow.sourceParameterValuePath;
44
+ const isCommittedRename = isEditedRow && Boolean(payload.shouldRenameExpandedRow);
45
+ const leafSchema = hasArrayMarker(isCommittedRename ? payload.name : contextRow.name) ? { type: "array" } : isCommittedRename ? void 0 : contextRow.schema;
46
+ setValueAtPath(value, path, isDeepObjectParameter && leafSchema ? deSerializeSchemaValue(nextValue, leafSchema) : nextValue);
33
47
  }
34
48
  return {
35
49
  name: row.originalParameter?.name ?? payload?.name ?? row.name,
@@ -1 +1 @@
1
- {"version":3,"file":"create-parameter-handlers.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/helpers/create-parameter-handlers.ts"],"sourcesContent":["import { setValueAtPath } from '@scalar/helpers/object/set-value-at-path'\nimport type { OperationExampleMeta, WorkspaceEventBus } from '@scalar/workspace-store/events'\n\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\n\ntype ParameterType = 'path' | 'cookie' | 'header' | 'query'\n\ntype ParameterUpsertPayload = {\n name: string\n value: string\n isDisabled: boolean\n shouldRenameExpandedRow?: boolean\n}\n\nconst isEmptyValue = (value: unknown): boolean => value === undefined || value === null || value === ''\n\n/** Parse a parameter key like `filter[a][b]` into its path segments `['filter', 'a', 'b']`. */\nconst parseBracketKey = (name: string): string[] => {\n const segments: string[] = []\n const head = name.match(/^[^[\\]]*/)?.[0] ?? ''\n if (head) {\n segments.push(head)\n }\n for (const match of name.matchAll(/\\[([^\\]]*)\\]/g)) {\n segments.push(match[1] ?? '')\n }\n return segments\n}\n\n/**\n * Derives the value path for an edited expanded row from the key the user typed, so renaming a\n * property actually moves the value to the new key instead of being dropped. deepObject rows are\n * prefixed with the parent parameter name (`filter[a]`), which we strip to get the path inside the\n * value. Falls back to the row's original path when the typed name cannot be parsed.\n */\nconst getEditedValuePath = (typedName: string, parameterName: string | undefined, fallback: string[]): string[] => {\n const segments = parseBracketKey(typedName)\n if (segments.length === 0) {\n return fallback\n }\n if (parameterName && segments[0] === parameterName && segments.length > 1) {\n return segments.slice(1)\n }\n return segments\n}\n\nconst getExpandedObjectPayload = (\n row: TableRow,\n context: TableRow[],\n payload?: ParameterUpsertPayload,\n): { name: string; value: Record<string, unknown>; isDisabled: boolean } => {\n const value: Record<string, unknown> = {}\n\n for (const contextRow of context) {\n if (contextRow.originalParameter !== row.originalParameter || !contextRow.sourceParameterValuePath) {\n continue\n }\n\n if (contextRow === row && !payload) {\n continue\n }\n\n const isEditedRow = contextRow === row && payload !== undefined\n const nextValue = isEditedRow ? payload.value : contextRow.value\n if (isEmptyValue(nextValue)) {\n continue\n }\n\n // Key edits are debounced while the user is still typing. Only committed key edits can move\n // the value to a new object path; regular value updates keep the stable source path.\n const path = isEditedRow\n ? payload.shouldRenameExpandedRow\n ? getEditedValuePath(payload.name, row.originalParameter?.name, contextRow.sourceParameterValuePath)\n : contextRow.sourceParameterValuePath\n : contextRow.sourceParameterValuePath\n\n setValueAtPath(value, path, nextValue)\n }\n\n return {\n name: row.originalParameter?.name ?? payload?.name ?? row.name,\n value,\n isDisabled: payload?.isDisabled ?? row.isDisabled ?? false,\n }\n}\n\n/** Create parameter event handlers for a given type */\nexport const createParameterHandlers = (\n type: ParameterType,\n eventBus: WorkspaceEventBus,\n meta: OperationExampleMeta,\n {\n context,\n defaultParameters = 0,\n globalParameters = 0,\n onDeleteExpandedRow,\n onRenameExpandedRow,\n }: {\n context: TableRow[]\n defaultParameters?: number\n globalParameters?: number\n onDeleteExpandedRow?: (row: TableRow) => void\n onRenameExpandedRow?: (row: TableRow, newValuePath: string[]) => void\n },\n) => {\n const offset = defaultParameters + globalParameters\n\n return {\n delete: (payload: { index: number }) => {\n const row = context[payload.index]\n if (!row?.originalParameter) {\n return\n }\n\n if (row.sourceParameterValuePath) {\n onDeleteExpandedRow?.(row)\n\n return eventBus.emit(\n 'operation:upsert:parameter',\n {\n type,\n payload: getExpandedObjectPayload(row, context),\n originalParameter: row.originalParameter,\n meta,\n },\n {\n skipUnpackProxy: true,\n },\n )\n }\n\n eventBus.emit(\n 'operation:delete:parameter',\n {\n originalParameter: row.originalParameter,\n meta,\n },\n {\n skipUnpackProxy: true,\n },\n )\n },\n deleteAll: () =>\n eventBus.emit('operation:delete-all:parameters', {\n type,\n meta,\n }),\n upsert: (index: number, payload: ParameterUpsertPayload) => {\n const row = context[index]\n const { shouldRenameExpandedRow, ...parameterPayload } = payload\n\n if (index < defaultParameters + globalParameters) {\n const extraParameterType = index < defaultParameters ? 'default' : 'global'\n\n return eventBus.emit('operation:update:extra-parameters', {\n type: extraParameterType,\n in: type,\n meta: { ...meta, name: row?.name?.toLowerCase?.() ?? 'NON_VALID' },\n payload: { isDisabled: payload.isDisabled ?? false },\n })\n }\n\n if (index >= offset) {\n const isExpandedRow = Boolean(row?.sourceParameterValuePath && row.originalParameter)\n\n // When the key of an expanded row changes, report the new value path so the row keeps its\n // original slot (rendered in place of the old schema property) instead of jumping to the end.\n if (isExpandedRow && row && shouldRenameExpandedRow && payload.name !== row.name) {\n const newValuePath = getEditedValuePath(\n payload.name,\n row.originalParameter?.name,\n row.sourceParameterValuePath ?? [],\n )\n onRenameExpandedRow?.(row, newValuePath)\n }\n\n const nextPayload = isExpandedRow && row ? getExpandedObjectPayload(row, context, payload) : parameterPayload\n\n return eventBus.emit(\n 'operation:upsert:parameter',\n {\n type,\n payload: nextPayload,\n originalParameter: row?.originalParameter ?? null,\n meta,\n },\n {\n skipUnpackProxy: true,\n debounceKey: `update:parameter-${type}-${index - offset}`,\n },\n )\n }\n },\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"create-parameter-handlers.js","names":[],"sources":["../../../../../src/v2/blocks/request-block/helpers/create-parameter-handlers.ts"],"sourcesContent":["import { setValueAtPath } from '@scalar/helpers/object/set-value-at-path'\nimport type { OperationExampleMeta, WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { deSerializeSchemaValue } from '@scalar/workspace-store/request-example'\n\nimport type { TableRow } from '@/v2/blocks/request-block/components/RequestTableRow.vue'\n\ntype ParameterType = 'path' | 'cookie' | 'header' | 'query'\n\ntype ParameterUpsertPayload = {\n name: string\n value: string\n isDisabled: boolean\n shouldRenameExpandedRow?: boolean\n}\n\nconst isEmptyValue = (value: unknown): boolean => value === undefined || value === null || value === ''\n\n/**\n * Whether a row name carries the display-only deepObject array marker (`filters[id][in][]`). The\n * marker is only ever appended after a real path bracket, so it always shows up as `][]`. That lets\n * us tell it apart from a genuinely empty key: an interior empty (`filters[][in]`) or a lone empty\n * group (`filters[]`, value path `['']`) is not a marker and keeps its segment.\n */\nconst hasArrayMarker = (name: string): boolean => name.endsWith('][]')\n\n/** Parse a parameter key like `filter[a][b]` into its path segments `['filter', 'a', 'b']`. */\nconst parseBracketKey = (name: string): string[] => {\n // Strip the trailing array marker first. The trailing brackets on a deepObject array leaf are\n // display-only, not part of the value path — keeping them would add a bogus empty key that drops\n // the value on write-back and corrupts rename tracking.\n const withoutArrayMarker = hasArrayMarker(name) ? name.slice(0, -2) : name\n\n const segments: string[] = []\n const head = withoutArrayMarker.match(/^[^[\\]]*/)?.[0] ?? ''\n if (head) {\n segments.push(head)\n }\n for (const match of withoutArrayMarker.matchAll(/\\[([^\\]]*)\\]/g)) {\n segments.push(match[1] ?? '')\n }\n return segments\n}\n\n/**\n * Derives the value path for an edited expanded row from the key the user typed, so renaming a\n * property actually moves the value to the new key instead of being dropped. deepObject rows are\n * prefixed with the parent parameter name (`filter[a]`), which we strip to get the path inside the\n * value. Falls back to the row's original path when the typed name cannot be parsed.\n */\nconst getEditedValuePath = (typedName: string, parameterName: string | undefined, fallback: string[]): string[] => {\n const segments = parseBracketKey(typedName)\n if (segments.length === 0) {\n return fallback\n }\n if (parameterName && segments[0] === parameterName && segments.length > 1) {\n return segments.slice(1)\n }\n return segments\n}\n\nconst getExpandedObjectPayload = (\n row: TableRow,\n context: TableRow[],\n payload?: ParameterUpsertPayload,\n): { name: string; value: Record<string, unknown>; isDisabled: boolean } => {\n const value: Record<string, unknown> = {}\n\n // Only deepObject leaves use the comma-to-array coercion below. The trailing-bracket array\n // convention (`key[]=1&key[]=2`) is deepObject-specific, and deepObject leaves never carry a\n // meaningful comma. Form-style object parameters can (e.g. Spring `sort=username,asc`), so they\n // keep their leaves verbatim.\n const parameter = row.originalParameter\n const isDeepObjectParameter = Boolean(parameter && 'style' in parameter && parameter.style === 'deepObject')\n\n for (const contextRow of context) {\n if (contextRow.originalParameter !== row.originalParameter || !contextRow.sourceParameterValuePath) {\n continue\n }\n\n if (contextRow === row && !payload) {\n continue\n }\n\n const isEditedRow = contextRow === row && payload !== undefined\n const nextValue = isEditedRow ? payload.value : contextRow.value\n if (isEmptyValue(nextValue)) {\n continue\n }\n\n // Key edits are debounced while the user is still typing. Only committed key edits can move\n // the value to a new object path; regular value updates keep the stable source path.\n const path = isEditedRow\n ? payload.shouldRenameExpandedRow\n ? getEditedValuePath(payload.name, row.originalParameter?.name, contextRow.sourceParameterValuePath)\n : contextRow.sourceParameterValuePath\n : contextRow.sourceParameterValuePath\n\n // Rows always hold the string the user sees, so a deepObject array leaf arrives comma-joined\n // (\"1,2\"). Coerce it back to an array before storing — otherwise deepObject serialization\n // re-collapses it into a single `key[in]=1,2` entry instead of repeating `key[in][]=1&key[in][]=2`.\n //\n // The display-only `][]` marker is the authoritative array signal: a leaf gets it whenever its\n // schema OR its stored value is an array, so it must win over a non-array property schema, which\n // would otherwise skip the coercion and serialize the array comma-joined. A committed rename\n // re-derives the marker from the freshly typed name, since the row's `schema` and `name` still\n // describe the old key — renaming an array leaf to a scalar key must not store a one-element array.\n // Non-array leaves fall back to the property schema so object leaves still coerce; renamed rows\n // have no reliable schema, so they rely on the marker alone.\n const isCommittedRename = isEditedRow && Boolean(payload.shouldRenameExpandedRow)\n const hasArrayLeafMarker = hasArrayMarker(isCommittedRename ? payload.name : contextRow.name)\n const leafSchema = hasArrayLeafMarker\n ? ({ type: 'array' } as const)\n : isCommittedRename\n ? undefined\n : contextRow.schema\n const leafValue = isDeepObjectParameter && leafSchema ? deSerializeSchemaValue(nextValue, leafSchema) : nextValue\n\n setValueAtPath(value, path, leafValue)\n }\n\n return {\n name: row.originalParameter?.name ?? payload?.name ?? row.name,\n value,\n isDisabled: payload?.isDisabled ?? row.isDisabled ?? false,\n }\n}\n\n/** Create parameter event handlers for a given type */\nexport const createParameterHandlers = (\n type: ParameterType,\n eventBus: WorkspaceEventBus,\n meta: OperationExampleMeta,\n {\n context,\n defaultParameters = 0,\n globalParameters = 0,\n onDeleteExpandedRow,\n onRenameExpandedRow,\n }: {\n context: TableRow[]\n defaultParameters?: number\n globalParameters?: number\n onDeleteExpandedRow?: (row: TableRow) => void\n onRenameExpandedRow?: (row: TableRow, newValuePath: string[]) => void\n },\n) => {\n const offset = defaultParameters + globalParameters\n\n return {\n delete: (payload: { index: number }) => {\n const row = context[payload.index]\n if (!row?.originalParameter) {\n return\n }\n\n if (row.sourceParameterValuePath) {\n onDeleteExpandedRow?.(row)\n\n return eventBus.emit(\n 'operation:upsert:parameter',\n {\n type,\n payload: getExpandedObjectPayload(row, context),\n originalParameter: row.originalParameter,\n meta,\n },\n {\n skipUnpackProxy: true,\n },\n )\n }\n\n eventBus.emit(\n 'operation:delete:parameter',\n {\n originalParameter: row.originalParameter,\n meta,\n },\n {\n skipUnpackProxy: true,\n },\n )\n },\n deleteAll: () =>\n eventBus.emit('operation:delete-all:parameters', {\n type,\n meta,\n }),\n upsert: (index: number, payload: ParameterUpsertPayload) => {\n const row = context[index]\n const { shouldRenameExpandedRow, ...parameterPayload } = payload\n\n if (index < defaultParameters + globalParameters) {\n const extraParameterType = index < defaultParameters ? 'default' : 'global'\n\n return eventBus.emit('operation:update:extra-parameters', {\n type: extraParameterType,\n in: type,\n meta: { ...meta, name: row?.name?.toLowerCase?.() ?? 'NON_VALID' },\n payload: { isDisabled: payload.isDisabled ?? false },\n })\n }\n\n if (index >= offset) {\n const isExpandedRow = Boolean(row?.sourceParameterValuePath && row.originalParameter)\n\n // When the key of an expanded row changes, report the new value path so the row keeps its\n // original slot (rendered in place of the old schema property) instead of jumping to the end.\n if (isExpandedRow && row && shouldRenameExpandedRow && payload.name !== row.name) {\n const newValuePath = getEditedValuePath(\n payload.name,\n row.originalParameter?.name,\n row.sourceParameterValuePath ?? [],\n )\n onRenameExpandedRow?.(row, newValuePath)\n }\n\n const nextPayload = isExpandedRow && row ? getExpandedObjectPayload(row, context, payload) : parameterPayload\n\n return eventBus.emit(\n 'operation:upsert:parameter',\n {\n type,\n payload: nextPayload,\n originalParameter: row?.originalParameter ?? null,\n meta,\n },\n {\n skipUnpackProxy: true,\n debounceKey: `update:parameter-${type}-${index - offset}`,\n },\n )\n }\n },\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"create-parameter-rows.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/helpers/create-parameter-rows.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,8DAA8D,CAAA;AAGrE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAA;AAiUjE;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,GAC9B,WAAW,eAAe,EAC1B,YAAY,MAAM,EAClB,UAAS;IACP,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,EAAE,CAAA;IACtC,iBAAiB,CAAC,EAAE,SAAS;QAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,EAAE,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAA;CAC3D,KACL,QAAQ,EAmDV,CAAA"}
1
+ {"version":3,"file":"create-parameter-rows.d.ts","sourceRoot":"","sources":["../../../../../src/v2/blocks/request-block/helpers/create-parameter-rows.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,8DAA8D,CAAA;AAGrE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAA;AAqVjE;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,GAC9B,WAAW,eAAe,EAC1B,YAAY,MAAM,EAClB,UAAS;IACP,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,EAAE,CAAA;IACtC,iBAAiB,CAAC,EAAE,SAAS;QAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,EAAE,EAAE,MAAM,EAAE,CAAA;KAAE,EAAE,CAAA;CAC3D,KACL,QAAQ,EAmDV,CAAA"}
@@ -1,10 +1,9 @@
1
- import { isParamDisabled } from "./is-param-disabled.js";
2
1
  import { getParameterSchema } from "./get-parameter-schema.js";
3
2
  import { getValueAtPath } from "@scalar/helpers/object/get-value-at-path";
4
- import { deSerializeParameter, getExample } from "@scalar/workspace-store/request-example";
3
+ import { deSerializeParameter, getExample, isParamDisabled } from "@scalar/workspace-store/request-example";
5
4
  import { getResolvedRef } from "@scalar/workspace-store/helpers/get-resolved-ref";
6
5
  import { isObject } from "@scalar/helpers/object/is-object";
7
- import { isObjectSchema } from "@scalar/workspace-store/schemas/v3.1/strict/type-guards";
6
+ import { isArraySchema, isObjectSchema } from "@scalar/workspace-store/schemas/v3.1/strict/type-guards";
8
7
  //#region src/v2/blocks/request-block/helpers/create-parameter-rows.ts
9
8
  var isParameterWithSchema = (parameter) => "schema" in parameter && parameter.schema !== void 0;
10
9
  var resolveSchema = (schema) => {
@@ -56,6 +55,13 @@ var toTableRow = ({ parameter, name, value, description, schema, isRequired, isD
56
55
  * wire format (`parent[a][b]`); form-style explode uses the bare top-level key.
57
56
  */
58
57
  var getExpandedRowName = (parameter, path, mode) => mode === "deepObject" ? `${parameter.name}${path.map((segment) => `[${segment}]`).join("")}` : path[0] ?? "";
58
+ /**
59
+ * Appends the display-only trailing `[]` to deepObject array leaves so the name matches the
60
+ * serialized `parent[ids][]=1&parent[ids][]=2` form. The bracket is display-only — the row's
61
+ * `sourceParameterValuePath` stays bracket-free. It also lets write-back recognize the leaf as an
62
+ * array even on renamed and unmapped rows, which carry no schema.
63
+ */
64
+ var withArrayBracket = (name, mode, isArray) => mode === "deepObject" && isArray ? `${name}[]` : name;
59
65
  /** Build the single-row representation used when a parameter is not expanded. */
60
66
  var toSingleParameterRow = (parameter, schema, value, isDisabled) => toTableRow({
61
67
  parameter,
@@ -90,10 +96,11 @@ var getExpandedPropertyRows = ({ parameter, schema, value, pathPrefix, namePrefi
90
96
  if (hiddenValuePaths.has(toPathKey(effectivePath))) return [];
91
97
  if (renamedTo) {
92
98
  const renamedValue = getValueAtPath(value, renamedTo);
99
+ const effectiveValue = renamedValue === void 0 ? getValueAtPath(value, path) : renamedValue;
93
100
  return [toTableRow({
94
101
  parameter,
95
- name: getExpandedRowName(parameter, renamedTo, mode),
96
- value: renamedValue === void 0 ? getValueAtPath(value, path) : renamedValue,
102
+ name: withArrayBracket(getExpandedRowName(parameter, renamedTo, mode), mode, Array.isArray(effectiveValue)),
103
+ value: effectiveValue,
97
104
  description: parameter.description,
98
105
  schema: void 0,
99
106
  isRequired: false,
@@ -114,10 +121,11 @@ var getExpandedPropertyRows = ({ parameter, schema, value, pathPrefix, namePrefi
114
121
  renamedValuePaths,
115
122
  renameTargetPaths
116
123
  });
124
+ const leafValue = getValueAtPath(value, path);
117
125
  return [toTableRow({
118
126
  parameter,
119
- name,
120
- value: getValueAtPath(value, path),
127
+ name: withArrayBracket(name, mode, isArraySchema(resolvedPropertySchema) || Array.isArray(leafValue)),
128
+ value: leafValue,
121
129
  description: resolvedPropertySchema.description ?? parameter.description,
122
130
  schema: resolvedPropertySchema,
123
131
  isRequired: requiredProperties.has(propertyName),
@@ -151,16 +159,19 @@ var collectValueLeafPaths = (value, mode) => {
151
159
  */
152
160
  var getUnmappedValueRows = ({ parameter, value, schemaRows, mode, isDisabled, renamedValuePaths }) => {
153
161
  const seen = new Set([...schemaRows.map((row) => toPathKey(row.sourceParameterValuePath ?? [])), ...renamedValuePaths.keys()]);
154
- return collectValueLeafPaths(value, mode).filter((path) => !seen.has(toPathKey(path))).map((path) => toTableRow({
155
- parameter,
156
- name: getExpandedRowName(parameter, path, mode),
157
- value: getValueAtPath(value, path),
158
- description: parameter.description,
159
- schema: void 0,
160
- isRequired: false,
161
- isDisabled,
162
- sourceParameterValuePath: path
163
- }));
162
+ return collectValueLeafPaths(value, mode).filter((path) => !seen.has(toPathKey(path))).map((path) => {
163
+ const leafValue = getValueAtPath(value, path);
164
+ return toTableRow({
165
+ parameter,
166
+ name: withArrayBracket(getExpandedRowName(parameter, path, mode), mode, Array.isArray(leafValue)),
167
+ value: leafValue,
168
+ description: parameter.description,
169
+ schema: void 0,
170
+ isRequired: false,
171
+ isDisabled,
172
+ sourceParameterValuePath: path
173
+ });
174
+ });
164
175
  };
165
176
  /**
166
177
  * Turns a single OpenAPI parameter into one or more table rows.