@scalar/api-client 3.0.0 → 3.1.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 (96) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +41 -0
  3. package/dist/plugins/posthog/index.d.ts +23 -0
  4. package/dist/plugins/posthog/index.d.ts.map +1 -0
  5. package/dist/plugins/posthog/index.js +58 -0
  6. package/dist/plugins/posthog/index.js.map +1 -0
  7. package/dist/style.css +78 -18
  8. package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts.map +1 -1
  9. package/dist/v2/blocks/operation-block/OperationBlock.vue.js.map +1 -1
  10. package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js +14 -12
  11. package/dist/v2/blocks/operation-block/OperationBlock.vue.script.js.map +1 -1
  12. package/dist/v2/blocks/operation-block/helpers/decode-buffer.d.ts +5 -2
  13. package/dist/v2/blocks/operation-block/helpers/decode-buffer.d.ts.map +1 -1
  14. package/dist/v2/blocks/operation-block/helpers/decode-buffer.js +5 -2
  15. package/dist/v2/blocks/operation-block/helpers/decode-buffer.js.map +1 -1
  16. package/dist/v2/blocks/operation-block/helpers/har-to-fetch-request.d.ts +8 -9
  17. package/dist/v2/blocks/operation-block/helpers/har-to-fetch-request.d.ts.map +1 -1
  18. package/dist/v2/blocks/operation-block/helpers/har-to-fetch-request.js +8 -10
  19. package/dist/v2/blocks/operation-block/helpers/har-to-fetch-request.js.map +1 -1
  20. package/dist/v2/blocks/operation-block/helpers/response-cache.d.ts +2 -1
  21. package/dist/v2/blocks/operation-block/helpers/response-cache.d.ts.map +1 -1
  22. package/dist/v2/blocks/operation-block/helpers/response-cache.js.map +1 -1
  23. package/dist/v2/blocks/operation-block/helpers/send-request.d.ts +7 -3
  24. package/dist/v2/blocks/operation-block/helpers/send-request.d.ts.map +1 -1
  25. package/dist/v2/blocks/operation-block/helpers/send-request.js +19 -12
  26. package/dist/v2/blocks/operation-block/helpers/send-request.js.map +1 -1
  27. package/dist/v2/blocks/request-block/RequestBlock.vue.script.js +1 -1
  28. package/dist/v2/blocks/request-block/RequestBlock.vue.script.js.map +1 -1
  29. package/dist/v2/blocks/request-block/helpers/get-default-headers.js +1 -1
  30. package/dist/v2/blocks/response-block/ResponseBlock.vue.d.ts +3 -2
  31. package/dist/v2/blocks/response-block/ResponseBlock.vue.d.ts.map +1 -1
  32. package/dist/v2/blocks/response-block/ResponseBlock.vue.js +1 -1
  33. package/dist/v2/blocks/response-block/ResponseBlock.vue.js.map +1 -1
  34. package/dist/v2/blocks/response-block/ResponseBlock.vue.script.js +12 -6
  35. package/dist/v2/blocks/response-block/ResponseBlock.vue.script.js.map +1 -1
  36. package/dist/v2/blocks/response-block/components/ResponseBody.vue.d.ts +2 -0
  37. package/dist/v2/blocks/response-block/components/ResponseBody.vue.d.ts.map +1 -1
  38. package/dist/v2/blocks/response-block/components/ResponseBody.vue.js +1 -1
  39. package/dist/v2/blocks/response-block/components/ResponseBody.vue.js.map +1 -1
  40. package/dist/v2/blocks/response-block/components/ResponseBody.vue.script.js +34 -14
  41. package/dist/v2/blocks/response-block/components/ResponseBody.vue.script.js.map +1 -1
  42. package/dist/v2/blocks/response-block/helpers/process-response-body.d.ts +1 -1
  43. package/dist/v2/blocks/response-block/helpers/process-response-body.js +2 -3
  44. package/dist/v2/blocks/response-block/helpers/process-response-body.js.map +1 -1
  45. package/dist/v2/blocks/response-block/helpers/resolve-response-body-handler.d.ts +11 -0
  46. package/dist/v2/blocks/response-block/helpers/resolve-response-body-handler.d.ts.map +1 -0
  47. package/dist/v2/blocks/response-block/helpers/resolve-response-body-handler.js +44 -0
  48. package/dist/v2/blocks/response-block/helpers/resolve-response-body-handler.js.map +1 -0
  49. package/dist/v2/blocks/response-block/helpers/resolve-response-content-type.d.ts +14 -0
  50. package/dist/v2/blocks/response-block/helpers/resolve-response-content-type.d.ts.map +1 -0
  51. package/dist/v2/blocks/response-block/helpers/resolve-response-content-type.js +13 -0
  52. package/dist/v2/blocks/response-block/helpers/resolve-response-content-type.js.map +1 -0
  53. package/dist/v2/blocks/scalar-auth-selector-block/components/AuthSelector.vue.script.js.map +1 -1
  54. package/dist/v2/constants.js +1 -1
  55. package/dist/v2/features/app/App.vue.d.ts.map +1 -1
  56. package/dist/v2/features/app/App.vue.js.map +1 -1
  57. package/dist/v2/features/app/App.vue.script.js +15 -3
  58. package/dist/v2/features/app/App.vue.script.js.map +1 -1
  59. package/dist/v2/features/app/helpers/create-temp-operation.d.ts.map +1 -1
  60. package/dist/v2/features/app/helpers/create-temp-operation.js +4 -1
  61. package/dist/v2/features/app/helpers/create-temp-operation.js.map +1 -1
  62. package/dist/v2/features/collection/components/Runner/hooks/use-runner-execution.js +1 -1
  63. package/dist/v2/features/collection/components/Runner/hooks/use-runner-execution.js.map +1 -1
  64. package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.d.ts.map +1 -1
  65. package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.js.map +1 -1
  66. package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.script.js +1 -1
  67. package/dist/v2/features/command-palette/components/CommandPaletteImport.vue.script.js.map +1 -1
  68. package/dist/v2/features/command-palette/components/CommandPaletteImportPostman.vue.d.ts.map +1 -1
  69. package/dist/v2/features/command-palette/components/CommandPaletteImportPostman.vue.js.map +1 -1
  70. package/dist/v2/features/command-palette/components/CommandPaletteImportPostman.vue.script.js +26 -21
  71. package/dist/v2/features/command-palette/components/CommandPaletteImportPostman.vue.script.js.map +1 -1
  72. package/dist/v2/features/command-palette/components/PostmanImportPreview.vue.js +1 -1
  73. package/dist/v2/features/command-palette/components/PostmanImportPreview.vue.js.map +1 -1
  74. package/dist/v2/features/command-palette/components/PostmanImportPreview.vue.script.js +1 -1
  75. package/dist/v2/features/command-palette/components/PostmanImportPreview.vue.script.js.map +1 -1
  76. package/dist/v2/features/command-palette/helpers/get-postman-convert-options.d.ts +14 -0
  77. package/dist/v2/features/command-palette/helpers/get-postman-convert-options.d.ts.map +1 -0
  78. package/dist/v2/features/command-palette/helpers/get-postman-convert-options.js +19 -0
  79. package/dist/v2/features/command-palette/helpers/get-postman-convert-options.js.map +1 -0
  80. package/dist/v2/features/command-palette/helpers/get-postman-document-details.js +1 -1
  81. package/dist/v2/features/command-palette/helpers/get-postman-document-details.js.map +1 -1
  82. package/dist/v2/features/command-palette/helpers/load-document-from-source.d.ts.map +1 -1
  83. package/dist/v2/features/command-palette/helpers/load-document-from-source.js +1 -1
  84. package/dist/v2/features/command-palette/helpers/load-document-from-source.js.map +1 -1
  85. package/dist/v2/features/modal/helpers/create-api-client-modal.d.ts.map +1 -1
  86. package/dist/v2/features/modal/helpers/create-api-client-modal.js +11 -0
  87. package/dist/v2/features/modal/helpers/create-api-client-modal.js.map +1 -1
  88. package/package.json +19 -14
  89. package/dist/v2/features/command-palette/helpers/is-postman-collection.d.ts +0 -11
  90. package/dist/v2/features/command-palette/helpers/is-postman-collection.d.ts.map +0 -1
  91. package/dist/v2/features/command-palette/helpers/is-postman-collection.js +0 -24
  92. package/dist/v2/features/command-palette/helpers/is-postman-collection.js.map +0 -1
  93. package/dist/v2/posthog.d.ts +0 -3
  94. package/dist/v2/posthog.d.ts.map +0 -1
  95. package/dist/v2/posthog.js +0 -20
  96. package/dist/v2/posthog.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"CommandPaletteImport.vue.script.js","names":[],"sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteImport.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Command Palette Import Component\n *\n * Provides a form for importing OpenAPI descriptions from URL, file, or pasted JSON/YAML.\n * Postman collection JSON and Postman files open {@link CommandPaletteImportPostman}.\n * cURL commands redirect to {@link CommandPaletteImportCurl}.\n *\n * Supports watch mode for URL imports to automatically update when content changes.\n */\nexport default {\n name: 'CommandPaletteImport',\n}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarCodeBlock,\n ScalarIcon,\n ScalarTooltip,\n useLoadingState,\n} from '@scalar/components'\nimport { isLocalUrl } from '@scalar/helpers/url/is-local-url'\nimport type { LoaderPlugin } from '@scalar/json-magic/bundle'\nimport { useToasts } from '@scalar/use-toasts'\nimport {\n createWorkspaceStore,\n type WorkspaceStore,\n} from '@scalar/workspace-store/client'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { computed, ref, watch } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport { useFileDialog } from '@/hooks/use-file-dialog'\nimport { getOpenApiDocumentDetails } from '@/v2/features/command-palette/helpers/get-openapi-document-details'\nimport { importDocumentToWorkspace } from '@/v2/features/command-palette/helpers/import-document-to-workspace'\nimport { isPostmanCollection } from '@/v2/features/command-palette/helpers/is-postman-collection'\nimport {\n loadDocumentFromSource,\n type ImportEventData,\n} from '@/v2/features/command-palette/helpers/load-document-from-source'\nimport { isUrl } from '@/v2/helpers/is-url'\n\nimport CommandActionForm from './CommandActionForm.vue'\nimport CommandActionInput from './CommandActionInput.vue'\nimport WatchModeToggle from './WatchModeToggle.vue'\n\nconst { workspaceStore, eventBus, fileLoader } = defineProps<{\n /** The workspace store for adding documents */\n workspaceStore: WorkspaceStore\n /** Event bus for emitting operation creation events */\n eventBus: WorkspaceEventBus\n /** Loader plugin for file import */\n fileLoader?: LoaderPlugin\n}>()\n\nconst emit = defineEmits<{\n /** Emitted when the import is complete or cancelled */\n (event: 'close'): void\n /** Emitted when user navigates back (e.g., backspace on empty input) */\n (event: 'back', keyboardEvent: KeyboardEvent): void\n}>()\n\ndefineSlots<{\n /** Slot for custom file upload component that can trigger import */\n fileUpload(props: {\n /** Function to trigger import with source content and type */\n import: (source: string, type: 'file' | 'raw') => Promise<void>\n }): void\n}>()\n\nconst { toast } = useToasts()\n\nconst router = useRouter()\nconst loader = useLoadingState()\n\nconst inputContent = ref('')\nconst watchMode = ref(false)\n\n/** Check if the input content is a URL */\nconst isUrlInput = computed<boolean>(() => isUrl(inputContent.value))\nconst isLocalUrlInput = computed<boolean>(\n () => isUrlInput.value && isLocalUrl(inputContent.value),\n)\n\nconst documentDetails = computed(() =>\n getOpenApiDocumentDetails(inputContent.value),\n)\n\n/** Get the document type for syntax highlighting */\nconst documentType = computed<string>(() =>\n documentDetails.value ? documentDetails.value.type : 'json',\n)\n\n/** Check if the form should be disabled (when input is empty) */\nconst isDisabled = computed<boolean>(() => {\n return !inputContent.value.trim()\n})\n\n/**\n * Toggle watchMode based on whether the input is a local URL.\n * Only enables watch mode for local URLs, not for files or pasted content.\n */\nwatch(isLocalUrlInput, (value: boolean) => {\n watchMode.value = value\n})\n\n/**\n * Handles errors during the import process.\n * Shows an error toast, invalidates the loader to show an error state,\n * and closes the command palette modal.\n *\n * @param errorMessage - The error message to display and log\n */\nconst handleImportError = async (errorMessage: string) => {\n // Log the error\n console.error(errorMessage)\n toast(errorMessage, 'error')\n\n // Invalidate the loader to show the error state\n await loader.invalidate()\n\n // Close the command palette\n emit('close')\n}\n\n/**\n * Directly imports a document into the workspace without showing the modal.\n * This is used when there is only one workspace and it is empty.\n */\nconst handleImport = async (\n newSource: string,\n type?: ImportEventData['type'],\n): Promise<void> => {\n loader.start()\n\n const TEMP_DOCUMENT_NAME = 'drafts'\n\n // First load the document into a draft store\n // This is to get the title of the document so we can generate a unique slug for store\n const draftStore = createWorkspaceStore({\n fileLoader,\n meta: {\n /** Ensure we use the active proxy to fetch documents */\n 'x-scalar-active-proxy':\n workspaceStore.workspace['x-scalar-active-proxy'],\n },\n })\n\n const eventType = (() => {\n if (type) {\n return type\n }\n\n if (isUrlInput.value) {\n return 'url'\n }\n\n return 'raw'\n })()\n\n const isSuccessfullyLoaded = await loadDocumentFromSource(\n draftStore,\n { source: newSource, type: eventType },\n TEMP_DOCUMENT_NAME,\n watchMode.value,\n )\n\n if (!isSuccessfullyLoaded) {\n return handleImportError('Failed to import document')\n }\n\n const importResult = await importDocumentToWorkspace({\n workspaceStore,\n workspaceState: draftStore.exportWorkspace(),\n name: TEMP_DOCUMENT_NAME,\n })\n\n if (!importResult.ok) {\n return handleImportError(importResult.error)\n }\n\n // Validate the loader to show the success state\n await loader.validate()\n\n // Navigate to the document overview page\n navigateToDocument(importResult.slug)\n\n // Close the command palette\n emit('close')\n}\n\n/** Navigate to the document overview page after successful import */\nconst navigateToDocument = (documentName: string): void => {\n router.push({\n name: 'document.overview',\n params: { documentSlug: documentName },\n })\n}\n\n/**\n * Handle file selection and import from file dialog.\n * Reads the file as text and imports it as OpenAPI or Postman collection.\n * Shows loading state during the import process.\n */\nconst { open: openSpecFileDialog } = useFileDialog({\n onChange: (files) => {\n const [file] = files ?? []\n\n if (!file) {\n return\n }\n\n loader.start()\n\n const onLoad = async (event: ProgressEvent<FileReader>): Promise<void> => {\n const text = event.target?.result as string\n if (isPostmanCollection(text)) {\n eventBus.emit('ui:open:command-palette', {\n action: 'import-postman-collection',\n payload: {\n inputValue: text,\n },\n })\n await loader.clear()\n return\n }\n await handleImport(text, 'raw')\n }\n\n const reader = new FileReader()\n reader.onload = onLoad\n reader.readAsText(file)\n },\n multiple: false,\n accept: '.json,.yaml,.yml',\n})\n\n/**\n * Handle input changes.\n * Detects cURL commands and redirects to the cURL import command.\n */\nconst handleInput = (value: string): void => {\n const trimmed = value.trim()\n\n if (trimmed.toLowerCase().startsWith('curl')) {\n return eventBus.emit('ui:open:command-palette', {\n action: 'import-curl-command',\n payload: {\n inputValue: value,\n },\n })\n }\n\n if (isPostmanCollection(trimmed)) {\n return eventBus.emit('ui:open:command-palette', {\n action: 'import-postman-collection',\n payload: {\n inputValue: value,\n },\n })\n }\n\n inputContent.value = value\n}\n\n/** Handle back navigation when user presses backspace on empty input */\nconst handleBack = (event: KeyboardEvent): void => {\n emit('back', event)\n}\n</script>\n<template>\n <CommandActionForm\n :disabled=\"isDisabled\"\n :loader\n @submit=\"handleImport(inputContent)\">\n <!-- URL or cURL input mode -->\n <template v-if=\"!documentDetails || isUrlInput\">\n <CommandActionInput\n :modelValue=\"inputContent\"\n placeholder=\"OpenAPI/Swagger/Postman URL or cURL\"\n @delete=\"handleBack\"\n @update:modelValue=\"handleInput\" />\n </template>\n\n <!-- Preview mode for pasted content -->\n <template v-else>\n <!-- Preview header with clear button -->\n <div class=\"flex justify-between\">\n <div class=\"text-c-2 min-h-8 w-full py-2 pl-12 text-center text-xs\">\n Preview\n </div>\n <ScalarButton\n class=\"hover:bg-b-2 relative ml-auto max-h-8 gap-1.5 p-2 text-xs\"\n variant=\"ghost\"\n @click=\"inputContent = ''\">\n Clear\n </ScalarButton>\n </div>\n\n <!-- Code preview with syntax highlighting -->\n <ScalarCodeBlock\n v-if=\"documentDetails && !isUrlInput\"\n class=\"bg-b-2 mt-1 max-h-[40dvh] rounded border px-2 py-1 text-sm\"\n :content=\"inputContent\"\n :copy=\"false\"\n :lang=\"documentType\" />\n </template>\n\n <!-- Actions: File upload and watch mode toggle -->\n <template #options>\n <div class=\"flex w-full flex-row items-center justify-between gap-3\">\n <!-- Custom file upload slot or default button -->\n <slot\n :import=\"handleImport\"\n name=\"fileUpload\">\n <!-- Default file upload button -->\n <ScalarButton\n class=\"hover:bg-b-2 relative max-h-8 gap-1.5 p-2 text-xs\"\n variant=\"outlined\"\n @click=\"openSpecFileDialog\">\n JSON, or YAML File\n <ScalarIcon\n class=\"text-c-3\"\n icon=\"Upload\"\n size=\"md\" />\n </ScalarButton>\n </slot>\n\n <!-- Watch mode toggle (only enabled for URL imports) -->\n <ScalarTooltip\n :content=\"\n isUrlInput\n ? 'Watch mode automatically updates the API client when the OpenAPI URL content changes, ensuring your client remains up-to-date.'\n : 'Watch mode is only available for URL imports. When enabled it automatically updates the API client when the OpenAPI URL content changes.'\n \"\n placement=\"bottom\">\n <WatchModeToggle\n v-model=\"watchMode\"\n :disabled=\"!isUrlInput\" />\n </ScalarTooltip>\n </div>\n </template>\n\n <!-- Dynamic submit button text based on import type -->\n <template #submit>\n Import\n <template v-if=\"isUrlInput\">from URL</template>\n <template v-else-if=\"documentDetails && documentType\">\n <template v-if=\"documentDetails.title\">\n \"{{ documentDetails.title }}\"\n </template>\n <template v-else>\n {{ documentDetails.version }}\n </template>\n </template>\n <template v-else>Collection</template>\n </template>\n </CommandActionForm>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"CommandPaletteImport.vue.script.js","names":[],"sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteImport.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Command Palette Import Component\n *\n * Provides a form for importing OpenAPI descriptions from URL, file, or pasted JSON/YAML.\n * Postman collection JSON and Postman files open {@link CommandPaletteImportPostman}.\n * cURL commands redirect to {@link CommandPaletteImportCurl}.\n *\n * Supports watch mode for URL imports to automatically update when content changes.\n */\nexport default {\n name: 'CommandPaletteImport',\n}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarCodeBlock,\n ScalarIcon,\n ScalarTooltip,\n useLoadingState,\n} from '@scalar/components'\nimport { isLocalUrl } from '@scalar/helpers/url/is-local-url'\nimport type { LoaderPlugin } from '@scalar/json-magic/bundle'\nimport { isPostmanCollection } from '@scalar/postman-to-openapi'\nimport { useToasts } from '@scalar/use-toasts'\nimport {\n createWorkspaceStore,\n type WorkspaceStore,\n} from '@scalar/workspace-store/client'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { computed, ref, watch } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport { useFileDialog } from '@/hooks/use-file-dialog'\nimport { getOpenApiDocumentDetails } from '@/v2/features/command-palette/helpers/get-openapi-document-details'\nimport { importDocumentToWorkspace } from '@/v2/features/command-palette/helpers/import-document-to-workspace'\nimport {\n loadDocumentFromSource,\n type ImportEventData,\n} from '@/v2/features/command-palette/helpers/load-document-from-source'\nimport { isUrl } from '@/v2/helpers/is-url'\n\nimport CommandActionForm from './CommandActionForm.vue'\nimport CommandActionInput from './CommandActionInput.vue'\nimport WatchModeToggle from './WatchModeToggle.vue'\n\nconst { workspaceStore, eventBus, fileLoader } = defineProps<{\n /** The workspace store for adding documents */\n workspaceStore: WorkspaceStore\n /** Event bus for emitting operation creation events */\n eventBus: WorkspaceEventBus\n /** Loader plugin for file import */\n fileLoader?: LoaderPlugin\n}>()\n\nconst emit = defineEmits<{\n /** Emitted when the import is complete or cancelled */\n (event: 'close'): void\n /** Emitted when user navigates back (e.g., backspace on empty input) */\n (event: 'back', keyboardEvent: KeyboardEvent): void\n}>()\n\ndefineSlots<{\n /** Slot for custom file upload component that can trigger import */\n fileUpload(props: {\n /** Function to trigger import with source content and type */\n import: (source: string, type: 'file' | 'raw') => Promise<void>\n }): void\n}>()\n\nconst { toast } = useToasts()\n\nconst router = useRouter()\nconst loader = useLoadingState()\n\nconst inputContent = ref('')\nconst watchMode = ref(false)\n\n/** Check if the input content is a URL */\nconst isUrlInput = computed<boolean>(() => isUrl(inputContent.value))\nconst isLocalUrlInput = computed<boolean>(\n () => isUrlInput.value && isLocalUrl(inputContent.value),\n)\n\nconst documentDetails = computed(() =>\n getOpenApiDocumentDetails(inputContent.value),\n)\n\n/** Get the document type for syntax highlighting */\nconst documentType = computed<string>(() =>\n documentDetails.value ? documentDetails.value.type : 'json',\n)\n\n/** Check if the form should be disabled (when input is empty) */\nconst isDisabled = computed<boolean>(() => {\n return !inputContent.value.trim()\n})\n\n/**\n * Toggle watchMode based on whether the input is a local URL.\n * Only enables watch mode for local URLs, not for files or pasted content.\n */\nwatch(isLocalUrlInput, (value: boolean) => {\n watchMode.value = value\n})\n\n/**\n * Handles errors during the import process.\n * Shows an error toast, invalidates the loader to show an error state,\n * and closes the command palette modal.\n *\n * @param errorMessage - The error message to display and log\n */\nconst handleImportError = async (errorMessage: string) => {\n // Log the error\n console.error(errorMessage)\n toast(errorMessage, 'error')\n\n // Invalidate the loader to show the error state\n await loader.invalidate()\n\n // Close the command palette\n emit('close')\n}\n\n/**\n * Directly imports a document into the workspace without showing the modal.\n * This is used when there is only one workspace and it is empty.\n */\nconst handleImport = async (\n newSource: string,\n type?: ImportEventData['type'],\n): Promise<void> => {\n loader.start()\n\n const TEMP_DOCUMENT_NAME = 'drafts'\n\n // First load the document into a draft store\n // This is to get the title of the document so we can generate a unique slug for store\n const draftStore = createWorkspaceStore({\n fileLoader,\n meta: {\n /** Ensure we use the active proxy to fetch documents */\n 'x-scalar-active-proxy':\n workspaceStore.workspace['x-scalar-active-proxy'],\n },\n })\n\n const eventType = (() => {\n if (type) {\n return type\n }\n\n if (isUrlInput.value) {\n return 'url'\n }\n\n return 'raw'\n })()\n\n const isSuccessfullyLoaded = await loadDocumentFromSource(\n draftStore,\n { source: newSource, type: eventType },\n TEMP_DOCUMENT_NAME,\n watchMode.value,\n )\n\n if (!isSuccessfullyLoaded) {\n return handleImportError('Failed to import document')\n }\n\n const importResult = await importDocumentToWorkspace({\n workspaceStore,\n workspaceState: draftStore.exportWorkspace(),\n name: TEMP_DOCUMENT_NAME,\n })\n\n if (!importResult.ok) {\n return handleImportError(importResult.error)\n }\n\n // Validate the loader to show the success state\n await loader.validate()\n\n // Navigate to the document overview page\n navigateToDocument(importResult.slug)\n\n // Close the command palette\n emit('close')\n}\n\n/** Navigate to the document overview page after successful import */\nconst navigateToDocument = (documentName: string): void => {\n router.push({\n name: 'document.overview',\n params: { documentSlug: documentName },\n })\n}\n\n/**\n * Handle file selection and import from file dialog.\n * Reads the file as text and imports it as OpenAPI or Postman collection.\n * Shows loading state during the import process.\n */\nconst { open: openSpecFileDialog } = useFileDialog({\n onChange: (files) => {\n const [file] = files ?? []\n\n if (!file) {\n return\n }\n\n loader.start()\n\n const onLoad = async (event: ProgressEvent<FileReader>): Promise<void> => {\n const text = event.target?.result as string\n if (isPostmanCollection(text)) {\n eventBus.emit('ui:open:command-palette', {\n action: 'import-postman-collection',\n payload: {\n inputValue: text,\n },\n })\n await loader.clear()\n return\n }\n await handleImport(text, 'raw')\n }\n\n const reader = new FileReader()\n reader.onload = onLoad\n reader.readAsText(file)\n },\n multiple: false,\n accept: '.json,.yaml,.yml',\n})\n\n/**\n * Handle input changes.\n * Detects cURL commands and redirects to the cURL import command.\n */\nconst handleInput = (value: string): void => {\n const trimmed = value.trim()\n\n if (trimmed.toLowerCase().startsWith('curl')) {\n return eventBus.emit('ui:open:command-palette', {\n action: 'import-curl-command',\n payload: {\n inputValue: value,\n },\n })\n }\n\n if (isPostmanCollection(trimmed)) {\n return eventBus.emit('ui:open:command-palette', {\n action: 'import-postman-collection',\n payload: {\n inputValue: value,\n },\n })\n }\n\n inputContent.value = value\n}\n\n/** Handle back navigation when user presses backspace on empty input */\nconst handleBack = (event: KeyboardEvent): void => {\n emit('back', event)\n}\n</script>\n<template>\n <CommandActionForm\n :disabled=\"isDisabled\"\n :loader\n @submit=\"handleImport(inputContent)\">\n <!-- URL or cURL input mode -->\n <template v-if=\"!documentDetails || isUrlInput\">\n <CommandActionInput\n :modelValue=\"inputContent\"\n placeholder=\"OpenAPI/Swagger/Postman URL or cURL\"\n @delete=\"handleBack\"\n @update:modelValue=\"handleInput\" />\n </template>\n\n <!-- Preview mode for pasted content -->\n <template v-else>\n <!-- Preview header with clear button -->\n <div class=\"flex justify-between\">\n <div class=\"text-c-2 min-h-8 w-full py-2 pl-12 text-center text-xs\">\n Preview\n </div>\n <ScalarButton\n class=\"hover:bg-b-2 relative ml-auto max-h-8 gap-1.5 p-2 text-xs\"\n variant=\"ghost\"\n @click=\"inputContent = ''\">\n Clear\n </ScalarButton>\n </div>\n\n <!-- Code preview with syntax highlighting -->\n <ScalarCodeBlock\n v-if=\"documentDetails && !isUrlInput\"\n class=\"bg-b-2 mt-1 max-h-[40dvh] rounded border px-2 py-1 text-sm\"\n :content=\"inputContent\"\n :copy=\"false\"\n :lang=\"documentType\" />\n </template>\n\n <!-- Actions: File upload and watch mode toggle -->\n <template #options>\n <div class=\"flex w-full flex-row items-center justify-between gap-3\">\n <!-- Custom file upload slot or default button -->\n <slot\n :import=\"handleImport\"\n name=\"fileUpload\">\n <!-- Default file upload button -->\n <ScalarButton\n class=\"hover:bg-b-2 relative max-h-8 gap-1.5 p-2 text-xs\"\n variant=\"outlined\"\n @click=\"openSpecFileDialog\">\n JSON, or YAML File\n <ScalarIcon\n class=\"text-c-3\"\n icon=\"Upload\"\n size=\"md\" />\n </ScalarButton>\n </slot>\n\n <!-- Watch mode toggle (only enabled for URL imports) -->\n <ScalarTooltip\n :content=\"\n isUrlInput\n ? 'Watch mode automatically updates the API client when the OpenAPI URL content changes, ensuring your client remains up-to-date.'\n : 'Watch mode is only available for URL imports. When enabled it automatically updates the API client when the OpenAPI URL content changes.'\n \"\n placement=\"bottom\">\n <WatchModeToggle\n v-model=\"watchMode\"\n :disabled=\"!isUrlInput\" />\n </ScalarTooltip>\n </div>\n </template>\n\n <!-- Dynamic submit button text based on import type -->\n <template #submit>\n Import\n <template v-if=\"isUrlInput\">from URL</template>\n <template v-else-if=\"documentDetails && documentType\">\n <template v-if=\"documentDetails.title\">\n \"{{ documentDetails.title }}\"\n </template>\n <template v-else>\n {{ documentDetails.version }}\n </template>\n </template>\n <template v-else>Collection</template>\n </template>\n </CommandActionForm>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;CAWE,MAAM;;;;;;;;EA8CR,MAAM,OAAO;EAeb,MAAM,EAAE,UAAU,WAAU;EAE5B,MAAM,SAAS,WAAU;EACzB,MAAM,SAAS,iBAAgB;EAE/B,MAAM,eAAe,IAAI,GAAE;EAC3B,MAAM,YAAY,IAAI,MAAK;;EAG3B,MAAM,aAAa,eAAwB,MAAM,aAAa,MAAM,CAAA;EACpE,MAAM,kBAAkB,eAChB,WAAW,SAAS,WAAW,aAAa,MAAM,CAC1D;EAEA,MAAM,kBAAkB,eACtB,0BAA0B,aAAa,MAAM,CAC/C;;EAGA,MAAM,eAAe,eACnB,gBAAgB,QAAQ,gBAAgB,MAAM,OAAO,OACvD;;EAGA,MAAM,aAAa,eAAwB;AACzC,UAAO,CAAC,aAAa,MAAM,MAAK;IACjC;;;;;AAMD,QAAM,kBAAkB,UAAmB;AACzC,aAAU,QAAQ;IACnB;;;;;;;;EASD,MAAM,oBAAoB,OAAO,iBAAyB;AAExD,WAAQ,MAAM,aAAY;AAC1B,SAAM,cAAc,QAAO;AAG3B,SAAM,OAAO,YAAW;AAGxB,QAAK,QAAO;;;;;;EAOd,MAAM,eAAe,OACnB,WACA,SACkB;AAClB,UAAO,OAAM;GAEb,MAAM,qBAAqB;GAI3B,MAAM,aAAa,qBAAqB;IACtC,YAAS,QAAA;IACT,MAAM,EAEJ,yBACE,QAAA,eAAe,UAAU,0BAC5B;IACF,CAAA;AAqBD,OAAI,CAPyB,MAAM,uBACjC,YACA;IAAE,QAAQ;IAAW,aAdE;AACvB,SAAI,KACF,QAAO;AAGT,SAAI,WAAW,MACb,QAAO;AAGT,YAAO;QACN;IAIqC,EACtC,oBACA,UAAU,MACZ,CAGE,QAAO,kBAAkB,4BAA2B;GAGtD,MAAM,eAAe,MAAM,0BAA0B;IACnD,gBAAa,QAAA;IACb,gBAAgB,WAAW,iBAAiB;IAC5C,MAAM;IACP,CAAA;AAED,OAAI,CAAC,aAAa,GAChB,QAAO,kBAAkB,aAAa,MAAK;AAI7C,SAAM,OAAO,UAAS;AAGtB,sBAAmB,aAAa,KAAI;AAGpC,QAAK,QAAO;;;EAId,MAAM,sBAAsB,iBAA+B;AACzD,UAAO,KAAK;IACV,MAAM;IACN,QAAQ,EAAE,cAAc,cAAc;IACvC,CAAA;;;;;;;EAQH,MAAM,EAAE,MAAM,uBAAuB,cAAc;GACjD,WAAW,UAAU;IACnB,MAAM,CAAC,QAAQ,SAAS,EAAC;AAEzB,QAAI,CAAC,KACH;AAGF,WAAO,OAAM;IAEb,MAAM,SAAS,OAAO,UAAoD;KACxE,MAAM,OAAO,MAAM,QAAQ;AAC3B,SAAI,oBAAoB,KAAK,EAAE;AAC7B,cAAA,SAAS,KAAK,2BAA2B;OACvC,QAAQ;OACR,SAAS,EACP,YAAY,MACb;OACF,CAAA;AACD,YAAM,OAAO,OAAM;AACnB;;AAEF,WAAM,aAAa,MAAM,MAAK;;IAGhC,MAAM,SAAS,IAAI,YAAW;AAC9B,WAAO,SAAS;AAChB,WAAO,WAAW,KAAI;;GAExB,UAAU;GACV,QAAQ;GACT,CAAA;;;;;EAMD,MAAM,eAAe,UAAwB;GAC3C,MAAM,UAAU,MAAM,MAAK;AAE3B,OAAI,QAAQ,aAAa,CAAC,WAAW,OAAO,CAC1C,QAAO,QAAA,SAAS,KAAK,2BAA2B;IAC9C,QAAQ;IACR,SAAS,EACP,YAAY,OACb;IACF,CAAA;AAGH,OAAI,oBAAoB,QAAQ,CAC9B,QAAO,QAAA,SAAS,KAAK,2BAA2B;IAC9C,QAAQ;IACR,SAAS,EACP,YAAY,OACb;IACF,CAAA;AAGH,gBAAa,QAAQ;;;EAIvB,MAAM,cAAc,UAA+B;AACjD,QAAK,QAAQ,MAAK;;;uBAIlB,YAsFoB,2BAAA;IArFjB,UAAU,WAAA;IACV,QAAA,MAAA,OAAM;IACN,UAAM,OAAA,OAAA,OAAA,MAAA,WAAE,aAAa,aAAA,MAAY;;IAmCvB,SAAO,cA+BV,CA9BN,mBA8BM,OA9BN,YA8BM,CA5BJ,WAcO,KAAA,QAAA,cAAA,EAbJ,QAAQ,cAAY,QAahB,CAVL,YASe,MAAA,aAAA,EAAA;KARb,OAAM;KACN,SAAQ;KACP,SAAO,MAAA,mBAAkB;;4BAE1B,CAAA,OAAA,OAAA,OAAA,KAAA,gBAF4B,wBAE5B,GAAA,GAAA,YAGc,MAAA,WAAA,EAAA;MAFZ,OAAM;MACN,MAAK;MACL,MAAK;;;0BAKX,YAUgB,MAAA,cAAA,EAAA;KATb,SAAsB,WAAA,QAAA,mIAAA;KAKvB,WAAU;;4BAGkB,CAF5B,YAE4B,yBAAA;kBADjB,UAAA;6EAAS,QAAA;MACjB,UAAQ,CAAG,WAAA;;;;IAMT,QAAM,cAEf,CAAA,OAAA,OAAA,OAAA,KAAA,gBAFgB,YAEhB,GAAA,GAAgB,WAAA,SAAA,WAAA,EAAhB,mBAA+C,UAAA,EAAA,KAAA,GAAA,EAAA,CAAA,gBAAnB,WAAQ,CAAA,EAAA,GAAA,IACf,gBAAA,SAAmB,aAAA,SAAA,WAAA,EAAxC,mBAOW,UAAA,EAAA,KAAA,GAAA,EAAA,CANO,gBAAA,MAAgB,SAAA,WAAA,EAAhC,mBAEW,UAAA,EAAA,KAAA,GAAA,EAAA,CAAA,gBAF4B,QACpC,gBAAG,gBAAA,MAAgB,MAAK,GAAG,OAC9B,EAAA,CAAA,EAAA,GAAA,KAAA,WAAA,EACA,mBAEW,UAAA,EAAA,KAAA,GAAA,EAAA,CAAA,gBAAA,gBADN,gBAAA,MAAgB,QAAO,EAAA,EAAA,CAAA,EAAA,GAAA,EAAA,EAAA,GAAA,KAAA,WAAA,EAG9B,mBAAsC,UAAA,EAAA,KAAA,GAAA,EAAA,CAAA,gBAArB,aAAU,CAAA,EAAA,GAAA,EAAA,CAAA;2BAzElB,CAAA,CANM,gBAAA,SAAmB,WAAA,SAAA,WAAA,EAClC,YAIqC,4BAAA;;KAHlC,YAAY,aAAA;KACb,aAAY;KACX,UAAQ;KACR,uBAAmB;iDAIxB,mBAqBW,UAAA,EAAA,KAAA,GAAA,EAAA,CAnBT,mBAUM,OAVN,YAUM,CAAA,OAAA,OAAA,OAAA,KATJ,mBAEM,OAAA,EAFD,OAAM,0DAAwD,EAAC,aAEpE,GAAA,GACA,YAKe,MAAA,aAAA,EAAA;KAJb,OAAM;KACN,SAAQ;KACP,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,aAAA,QAAY;;4BAEtB,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAA,gBAF6B,WAE7B,GAAA,CAAA,EAAA,CAAA;;UAKM,gBAAA,SAAe,CAAK,WAAA,SAAA,WAAA,EAD5B,YAKyB,MAAA,gBAAA,EAAA;;KAHvB,OAAM;KACL,SAAS,aAAA;KACT,MAAM;KACN,MAAM,aAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"CommandPaletteImportPostman.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteImportPostman.vue"],"names":[],"mappings":"AAoPA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAuBvE;;;;;GAKG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAKzC,QAAA,MAAM,YAAY;oBAEA,cAAc;IAC9B,2CAA2C;cACjC,iBAAiB;IAC3B,2EAA2E;gBAC/D,MAAM;;;;;oBAJF,cAAc;IAC9B,2CAA2C;cACjC,iBAAiB;IAC3B,2EAA2E;gBAC/D,MAAM;;;;kFAkUhB,CAAC"}
1
+ {"version":3,"file":"CommandPaletteImportPostman.vue.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteImportPostman.vue"],"names":[],"mappings":"AAyPA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAsBvE;;;;;GAKG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAKzC,QAAA,MAAM,YAAY;oBAEA,cAAc;IAC9B,2CAA2C;cACjC,iBAAiB;IAC3B,2EAA2E;gBAC/D,MAAM;;;;;oBAJF,cAAc;IAC9B,2CAA2C;cACjC,iBAAiB;IAC3B,2EAA2E;gBAC/D,MAAM;;;;kFAmUhB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"CommandPaletteImportPostman.vue.js","names":[],"sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteImportPostman.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Command Palette Import Postman Component\n *\n * Imports Postman collections from URL, file, or pasted JSON, including\n * request selection, merge-into-existing, and convert options.\n */\nexport default {\n name: 'CommandPaletteImportPostman',\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { useLoadingState } from '@scalar/components'\nimport type { ConvertOptions } from '@scalar/postman-to-openapi'\nimport { useToasts } from '@scalar/use-toasts'\nimport { type WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport type { OpenApiDocument } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport PostmanImportPreview from '@/v2/features/command-palette/components/PostmanImportPreview.vue'\nimport PostmanRequestTreeRow from '@/v2/features/command-palette/components/PostmanRequestTreeRow.vue'\nimport { generateUniqueSlug } from '@/v2/features/command-palette/helpers/generate-unique-slug'\nimport { getOpenApiFromPostman } from '@/v2/features/command-palette/helpers/get-openapi-from-postman'\nimport { getPostmanDocumentDetails } from '@/v2/features/command-palette/helpers/get-postman-document-details'\nimport { getCollidingPostmanRequestPathKeys } from '@/v2/features/command-palette/helpers/postman-request-collisions'\nimport {\n applyPostmanFolderSelectionChange,\n applyPostmanRequestSelectionChange,\n buildPostmanRequestTree,\n countPostmanRequestLeaves,\n pathKey,\n pathKeysToRequestIndexPaths,\n type PostmanTreeNode,\n} from '@/v2/features/command-palette/helpers/postman-request-tree'\n\nimport CommandActionForm from './CommandActionForm.vue'\n\nconst {\n workspaceStore,\n eventBus,\n inputValue = '',\n} = defineProps<{\n workspaceStore: WorkspaceStore\n /** Event bus for emitting import events */\n eventBus: WorkspaceEventBus\n /** Pre-filled collection JSON (e.g. from file pick or redirected paste) */\n inputValue: string\n}>()\n\nconst emit = defineEmits<{\n (event: 'close'): void\n (event: 'back', keyboardEvent: KeyboardEvent): void\n}>()\n\nconst { toast } = useToasts()\n\nconst loader = useLoadingState()\n\n/** Document name to merge imported operations into. */\nconst importTargetDocumentName = ref<{ slug: string; label: string } | null>(\n null,\n)\nconst baseDocument = ref<OpenApiDocument | null>(null)\n\nwatch(importTargetDocumentName, async (value) => {\n if (!value) {\n baseDocument.value = null\n return\n }\n baseDocument.value = await workspaceStore.getEditableDocument(value.slug)\n})\n\nconst mergeSamePathAndMethod = ref(false)\n\nconst postmanDocumentDetails = computed(() =>\n getPostmanDocumentDetails(inputValue),\n)\nconst postmanRequestTree = computed(() =>\n buildPostmanRequestTree(postmanDocumentDetails.value?.collection ?? []),\n)\n\n/** Path keys to import from the Postman collection. */\nconst importPathKeys = ref<string[]>([])\n\nconst onPostmanRequestSelectionChange = (\n key: string,\n selected: boolean,\n): void => {\n importPathKeys.value = applyPostmanRequestSelectionChange(\n importPathKeys.value,\n key,\n selected,\n )\n}\n\nconst onPostmanFolderSelectionChange = (\n node: PostmanTreeNode,\n selected: boolean,\n): void => {\n importPathKeys.value = applyPostmanFolderSelectionChange(\n importPathKeys.value,\n node,\n selected,\n )\n}\n\nconst collisionsPathKeys = computed(() => {\n return getCollidingPostmanRequestPathKeys(\n postmanDocumentDetails.value?.collection ?? [],\n importPathKeys.value,\n baseDocument.value ?? undefined,\n )\n})\n\n/** Navigate to a document in the workspace. */\nconst navigateToDocument = (documentName: string): void => {\n eventBus.emit('ui:navigate', {\n page: 'document',\n path: 'overview',\n documentSlug: documentName,\n })\n}\n\n/** Handle import error. */\nconst handleImportError = async (errorMessage: string): Promise<void> => {\n console.error(errorMessage)\n toast(errorMessage, 'error')\n await loader.invalidate()\n emit('close')\n}\n\n/** Handle import. */\nconst handleImport = async (): Promise<void> => {\n loader.start()\n\n const mergeTarget = importTargetDocumentName.value?.slug ?? ''\n const mergeIntoExisting =\n mergeTarget.length > 0 &&\n workspaceStore.workspace.documents[mergeTarget] !== undefined\n\n const targetDocument = mergeIntoExisting\n ? await workspaceStore.getEditableDocument(mergeTarget)\n : null\n\n const options: ConvertOptions = {\n document: (targetDocument as unknown) ?? undefined,\n mergeOperation: mergeSamePathAndMethod.value,\n requestIndexPaths: pathKeysToRequestIndexPaths(importPathKeys.value),\n }\n\n const document = getOpenApiFromPostman(inputValue ?? '', options)\n\n if (document === null) {\n return handleImportError(\n 'Failed to convert Postman collection to OpenAPI document. Please contact support.',\n )\n }\n\n if (mergeIntoExisting) {\n await workspaceStore.replaceDocument(mergeTarget, document)\n await loader.validate()\n navigateToDocument(mergeTarget)\n emit('close')\n return\n }\n\n // Otherwise create a new document\n const slug = await generateUniqueSlug(\n document.info?.title ?? 'default',\n new Set(Object.keys(workspaceStore.workspace.documents)),\n )\n\n if (!slug) {\n return handleImportError(\n 'Failed to generate a unique slug for the imported document. Please contact support.',\n )\n }\n\n await workspaceStore.addDocument({\n name: slug,\n document,\n })\n\n await loader.validate()\n navigateToDocument(slug)\n emit('close')\n}\n</script>\n<template>\n <CommandActionForm\n :loader\n @submit=\"handleImport\">\n <div class=\"flex min-h-0 min-w-0 flex-1 flex-col gap-1.5 overflow-hidden\">\n <div class=\"flex shrink-0 justify-between\">\n <div class=\"text-c-2 min-h-7 w-full py-1.5 pl-12 text-center text-xs\">\n Postman collection\n </div>\n </div>\n\n <!-- Postman collection preview and tree picker -->\n <PostmanImportPreview\n v-if=\"postmanDocumentDetails\"\n v-model:mergeSamePathAndMethod=\"mergeSamePathAndMethod\"\n v-model:selectedTargetDocument=\"importTargetDocumentName\"\n :availableTargetDocuments=\"\n Object.entries(workspaceStore.workspace.documents).map(\n ([slug, document]) => ({\n slug,\n label: document.info?.title ?? slug,\n }),\n )\n \"\n :hasCollisionPathKeys=\"collisionsPathKeys.length > 0\"\n :schema=\"postmanDocumentDetails?.schemaLabel ?? undefined\"\n :title=\"postmanDocumentDetails?.title ?? ''\"\n :totalRequests=\"\n countPostmanRequestLeaves(postmanDocumentDetails?.collection ?? [])\n \"\n :version=\"postmanDocumentDetails?.version ?? ''\">\n <!-- Tree picker slot -->\n <template #treePicker>\n <PostmanRequestTreeRow\n v-for=\"node in postmanRequestTree\"\n :key=\"pathKey(node.path)\"\n :collisionPathKeys=\"collisionsPathKeys\"\n :mergeSamePathAndMethod=\"mergeSamePathAndMethod\"\n :node=\"node\"\n :selectedKeys=\"importPathKeys\"\n @folderSelectionChange=\"onPostmanFolderSelectionChange\"\n @requestSelectionChange=\"onPostmanRequestSelectionChange\" />\n </template>\n </PostmanImportPreview>\n </div>\n <template #submit> Import Postman Collection </template>\n </CommandActionForm>\n</template>\n"],"mappings":""}
1
+ {"version":3,"file":"CommandPaletteImportPostman.vue.js","names":[],"sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteImportPostman.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Command Palette Import Postman Component\n *\n * Imports Postman collections from URL, file, or pasted JSON, including\n * request selection, merge-into-existing, and convert options.\n */\nexport default {\n name: 'CommandPaletteImportPostman',\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { useLoadingState } from '@scalar/components'\nimport type { ConvertOptions } from '@scalar/postman-to-openapi'\nimport { useToasts } from '@scalar/use-toasts'\nimport { type WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport type { OpenApiDocument } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport PostmanImportPreview from '@/v2/features/command-palette/components/PostmanImportPreview.vue'\nimport PostmanRequestTreeRow from '@/v2/features/command-palette/components/PostmanRequestTreeRow.vue'\nimport { generateUniqueSlug } from '@/v2/features/command-palette/helpers/generate-unique-slug'\nimport { getOpenApiFromPostman } from '@/v2/features/command-palette/helpers/get-openapi-from-postman'\nimport { getPostmanConvertOptions } from '@/v2/features/command-palette/helpers/get-postman-convert-options'\nimport { getPostmanDocumentDetails } from '@/v2/features/command-palette/helpers/get-postman-document-details'\nimport { getCollidingPostmanRequestPathKeys } from '@/v2/features/command-palette/helpers/postman-request-collisions'\nimport {\n applyPostmanFolderSelectionChange,\n applyPostmanRequestSelectionChange,\n buildPostmanRequestTree,\n countPostmanRequestLeaves,\n type PostmanTreeNode,\n} from '@/v2/features/command-palette/helpers/postman-request-tree'\n\nimport CommandActionForm from './CommandActionForm.vue'\n\nconst {\n workspaceStore,\n eventBus,\n inputValue = '',\n} = defineProps<{\n workspaceStore: WorkspaceStore\n /** Event bus for emitting import events */\n eventBus: WorkspaceEventBus\n /** Pre-filled collection JSON (e.g. from file pick or redirected paste) */\n inputValue: string\n}>()\n\nconst emit = defineEmits<{\n (event: 'close'): void\n (event: 'back', keyboardEvent: KeyboardEvent): void\n}>()\n\nconst { toast } = useToasts()\n\nconst loader = useLoadingState()\n\n/** Document name to merge imported operations into. */\nconst importTargetDocumentName = ref<{ slug: string; label: string } | null>(\n null,\n)\nconst baseDocument = ref<OpenApiDocument | null>(null)\n\nwatch(importTargetDocumentName, async (value) => {\n if (!value) {\n baseDocument.value = null\n return\n }\n baseDocument.value = await workspaceStore.getEditableDocument(value.slug)\n})\n\nconst mergeSamePathAndMethod = ref(false)\n\nconst postmanDocumentDetails = computed(() =>\n getPostmanDocumentDetails(inputValue),\n)\nconst postmanRequestTree = computed(() =>\n buildPostmanRequestTree(postmanDocumentDetails.value?.collection ?? []),\n)\n\n/** Path keys to import from the Postman collection. */\nconst importPathKeys = ref<string[]>([])\n\nconst onPostmanRequestSelectionChange = (\n key: string,\n selected: boolean,\n): void => {\n importPathKeys.value = applyPostmanRequestSelectionChange(\n importPathKeys.value,\n key,\n selected,\n )\n}\n\nconst onPostmanFolderSelectionChange = (\n node: PostmanTreeNode,\n selected: boolean,\n): void => {\n importPathKeys.value = applyPostmanFolderSelectionChange(\n importPathKeys.value,\n node,\n selected,\n )\n}\n\n/** Wraps all top-level nodes in a single root folder so the tree row handles select-all. */\nconst rootTreeNode = computed<PostmanTreeNode>(() => ({\n path: [],\n name: postmanDocumentDetails.value?.title ?? 'Collection',\n isFolder: true,\n children: postmanRequestTree.value,\n}))\n\nconst collisionsPathKeys = computed(() => {\n return getCollidingPostmanRequestPathKeys(\n postmanDocumentDetails.value?.collection ?? [],\n importPathKeys.value,\n baseDocument.value ?? undefined,\n )\n})\n\n/** Navigate to a document in the workspace. */\nconst navigateToDocument = (documentName: string): void => {\n eventBus.emit('ui:navigate', {\n page: 'document',\n path: 'overview',\n documentSlug: documentName,\n })\n}\n\n/** Handle import error. */\nconst handleImportError = async (errorMessage: string): Promise<void> => {\n console.error(errorMessage)\n toast(errorMessage, 'error')\n await loader.invalidate()\n emit('close')\n}\n\n/** Handle import. */\nconst handleImport = async (): Promise<void> => {\n loader.start()\n\n const mergeTarget = importTargetDocumentName.value?.slug ?? ''\n const mergeIntoExisting =\n mergeTarget.length > 0 &&\n workspaceStore.workspace.documents[mergeTarget] !== undefined\n\n const targetDocument = mergeIntoExisting\n ? await workspaceStore.getEditableDocument(mergeTarget)\n : null\n\n const options: ConvertOptions = getPostmanConvertOptions({\n document: (targetDocument as unknown) ?? undefined,\n mergeOperation: mergeSamePathAndMethod.value,\n importPathKeys: importPathKeys.value,\n })\n\n const document = getOpenApiFromPostman(inputValue ?? '', options)\n\n if (document === null) {\n return handleImportError(\n 'Failed to convert Postman collection to OpenAPI document. Please contact support.',\n )\n }\n\n if (mergeIntoExisting) {\n await workspaceStore.replaceDocument(mergeTarget, document)\n await loader.validate()\n navigateToDocument(mergeTarget)\n emit('close')\n return\n }\n\n // Otherwise create a new document\n const slug = await generateUniqueSlug(\n document.info?.title ?? 'default',\n new Set(Object.keys(workspaceStore.workspace.documents)),\n )\n\n if (!slug) {\n return handleImportError(\n 'Failed to generate a unique slug for the imported document. Please contact support.',\n )\n }\n\n await workspaceStore.addDocument({\n name: slug,\n document,\n })\n\n await loader.validate()\n navigateToDocument(slug)\n emit('close')\n}\n</script>\n<template>\n <CommandActionForm\n :loader\n @submit=\"handleImport\">\n <div class=\"flex min-h-0 min-w-0 flex-1 flex-col gap-1.5 overflow-hidden\">\n <div class=\"flex shrink-0 justify-between\">\n <div class=\"text-c-2 min-h-7 w-full py-1.5 pl-12 text-center text-xs\">\n Postman collection\n </div>\n </div>\n\n <!-- Postman collection preview and tree picker -->\n <PostmanImportPreview\n v-if=\"postmanDocumentDetails\"\n v-model:mergeSamePathAndMethod=\"mergeSamePathAndMethod\"\n v-model:selectedTargetDocument=\"importTargetDocumentName\"\n :availableTargetDocuments=\"\n Object.entries(workspaceStore.workspace.documents).map(\n ([slug, document]) => ({\n slug,\n label: document.info?.title ?? slug,\n }),\n )\n \"\n :hasCollisionPathKeys=\"collisionsPathKeys.length > 0\"\n :schema=\"postmanDocumentDetails?.schemaLabel ?? undefined\"\n :title=\"postmanDocumentDetails?.title ?? ''\"\n :totalRequests=\"\n countPostmanRequestLeaves(postmanDocumentDetails?.collection ?? [])\n \"\n :version=\"postmanDocumentDetails?.version ?? ''\">\n <!-- Tree picker slot -->\n <template #treePicker>\n <PostmanRequestTreeRow\n :collisionPathKeys=\"collisionsPathKeys\"\n :mergeSamePathAndMethod=\"mergeSamePathAndMethod\"\n :node=\"rootTreeNode\"\n :selectedKeys=\"importPathKeys\"\n @folderSelectionChange=\"onPostmanFolderSelectionChange\"\n @requestSelectionChange=\"onPostmanRequestSelectionChange\" />\n </template>\n </PostmanImportPreview>\n </div>\n <template #submit> Import Postman Collection </template>\n </CommandActionForm>\n</template>\n"],"mappings":""}
@@ -2,11 +2,12 @@ import CommandActionForm_default from "./CommandActionForm.vue.js";
2
2
  import { generateUniqueSlug } from "../helpers/generate-unique-slug.js";
3
3
  import { getOpenApiFromPostman } from "../helpers/get-openapi-from-postman.js";
4
4
  import PostmanImportPreview_default from "./PostmanImportPreview.vue.js";
5
- import { applyPostmanFolderSelectionChange, applyPostmanRequestSelectionChange, buildPostmanRequestTree, countPostmanRequestLeaves, pathKey, pathKeysToRequestIndexPaths } from "../helpers/postman-request-tree.js";
5
+ import { applyPostmanFolderSelectionChange, applyPostmanRequestSelectionChange, buildPostmanRequestTree, countPostmanRequestLeaves } from "../helpers/postman-request-tree.js";
6
6
  import PostmanRequestTreeRow_default from "./PostmanRequestTreeRow.vue.js";
7
+ import { getPostmanConvertOptions } from "../helpers/get-postman-convert-options.js";
7
8
  import { getPostmanDocumentDetails } from "../helpers/get-postman-document-details.js";
8
9
  import { getCollidingPostmanRequestPathKeys } from "../helpers/postman-request-collisions.js";
9
- import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, defineComponent, openBlock, ref, renderList, unref, watch, withCtx } from "vue";
10
+ import { computed, createBlock, createCommentVNode, createElementVNode, createTextVNode, createVNode, defineComponent, openBlock, ref, unref, watch, withCtx } from "vue";
10
11
  import { useLoadingState } from "@scalar/components";
11
12
  import { useToasts } from "@scalar/use-toasts";
12
13
  //#region src/v2/features/command-palette/components/CommandPaletteImportPostman.vue?vue&type=script&setup=true&lang.ts
@@ -44,6 +45,13 @@ var CommandPaletteImportPostman_vue_vue_type_script_setup_true_lang_default = /*
44
45
  const onPostmanFolderSelectionChange = (node, selected) => {
45
46
  importPathKeys.value = applyPostmanFolderSelectionChange(importPathKeys.value, node, selected);
46
47
  };
48
+ /** Wraps all top-level nodes in a single root folder so the tree row handles select-all. */
49
+ const rootTreeNode = computed(() => ({
50
+ path: [],
51
+ name: postmanDocumentDetails.value?.title ?? "Collection",
52
+ isFolder: true,
53
+ children: postmanRequestTree.value
54
+ }));
47
55
  const collisionsPathKeys = computed(() => {
48
56
  return getCollidingPostmanRequestPathKeys(postmanDocumentDetails.value?.collection ?? [], importPathKeys.value, baseDocument.value ?? void 0);
49
57
  });
@@ -67,11 +75,11 @@ var CommandPaletteImportPostman_vue_vue_type_script_setup_true_lang_default = /*
67
75
  loader.start();
68
76
  const mergeTarget = importTargetDocumentName.value?.slug ?? "";
69
77
  const mergeIntoExisting = mergeTarget.length > 0 && __props.workspaceStore.workspace.documents[mergeTarget] !== void 0;
70
- const options = {
78
+ const options = getPostmanConvertOptions({
71
79
  document: (mergeIntoExisting ? await __props.workspaceStore.getEditableDocument(mergeTarget) : null) ?? void 0,
72
80
  mergeOperation: mergeSamePathAndMethod.value,
73
- requestIndexPaths: pathKeysToRequestIndexPaths(importPathKeys.value)
74
- };
81
+ importPathKeys: importPathKeys.value
82
+ });
75
83
  const document = getOpenApiFromPostman(__props.inputValue ?? "", options);
76
84
  if (document === null) return handleImportError("Failed to convert Postman collection to OpenAPI document. Please contact support.");
77
85
  if (mergeIntoExisting) {
@@ -113,22 +121,19 @@ var CommandPaletteImportPostman_vue_vue_type_script_setup_true_lang_default = /*
113
121
  totalRequests: unref(countPostmanRequestLeaves)(postmanDocumentDetails.value?.collection ?? []),
114
122
  version: postmanDocumentDetails.value?.version ?? ""
115
123
  }, {
116
- treePicker: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(postmanRequestTree.value, (node) => {
117
- return openBlock(), createBlock(PostmanRequestTreeRow_default, {
118
- key: unref(pathKey)(node.path),
119
- collisionPathKeys: collisionsPathKeys.value,
120
- mergeSamePathAndMethod: mergeSamePathAndMethod.value,
121
- node,
122
- selectedKeys: importPathKeys.value,
123
- onFolderSelectionChange: onPostmanFolderSelectionChange,
124
- onRequestSelectionChange: onPostmanRequestSelectionChange
125
- }, null, 8, [
126
- "collisionPathKeys",
127
- "mergeSamePathAndMethod",
128
- "node",
129
- "selectedKeys"
130
- ]);
131
- }), 128))]),
124
+ treePicker: withCtx(() => [createVNode(PostmanRequestTreeRow_default, {
125
+ collisionPathKeys: collisionsPathKeys.value,
126
+ mergeSamePathAndMethod: mergeSamePathAndMethod.value,
127
+ node: rootTreeNode.value,
128
+ selectedKeys: importPathKeys.value,
129
+ onFolderSelectionChange: onPostmanFolderSelectionChange,
130
+ onRequestSelectionChange: onPostmanRequestSelectionChange
131
+ }, null, 8, [
132
+ "collisionPathKeys",
133
+ "mergeSamePathAndMethod",
134
+ "node",
135
+ "selectedKeys"
136
+ ])]),
132
137
  _: 1
133
138
  }, 8, [
134
139
  "mergeSamePathAndMethod",
@@ -1 +1 @@
1
- {"version":3,"file":"CommandPaletteImportPostman.vue.script.js","names":[],"sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteImportPostman.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Command Palette Import Postman Component\n *\n * Imports Postman collections from URL, file, or pasted JSON, including\n * request selection, merge-into-existing, and convert options.\n */\nexport default {\n name: 'CommandPaletteImportPostman',\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { useLoadingState } from '@scalar/components'\nimport type { ConvertOptions } from '@scalar/postman-to-openapi'\nimport { useToasts } from '@scalar/use-toasts'\nimport { type WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport type { OpenApiDocument } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport PostmanImportPreview from '@/v2/features/command-palette/components/PostmanImportPreview.vue'\nimport PostmanRequestTreeRow from '@/v2/features/command-palette/components/PostmanRequestTreeRow.vue'\nimport { generateUniqueSlug } from '@/v2/features/command-palette/helpers/generate-unique-slug'\nimport { getOpenApiFromPostman } from '@/v2/features/command-palette/helpers/get-openapi-from-postman'\nimport { getPostmanDocumentDetails } from '@/v2/features/command-palette/helpers/get-postman-document-details'\nimport { getCollidingPostmanRequestPathKeys } from '@/v2/features/command-palette/helpers/postman-request-collisions'\nimport {\n applyPostmanFolderSelectionChange,\n applyPostmanRequestSelectionChange,\n buildPostmanRequestTree,\n countPostmanRequestLeaves,\n pathKey,\n pathKeysToRequestIndexPaths,\n type PostmanTreeNode,\n} from '@/v2/features/command-palette/helpers/postman-request-tree'\n\nimport CommandActionForm from './CommandActionForm.vue'\n\nconst {\n workspaceStore,\n eventBus,\n inputValue = '',\n} = defineProps<{\n workspaceStore: WorkspaceStore\n /** Event bus for emitting import events */\n eventBus: WorkspaceEventBus\n /** Pre-filled collection JSON (e.g. from file pick or redirected paste) */\n inputValue: string\n}>()\n\nconst emit = defineEmits<{\n (event: 'close'): void\n (event: 'back', keyboardEvent: KeyboardEvent): void\n}>()\n\nconst { toast } = useToasts()\n\nconst loader = useLoadingState()\n\n/** Document name to merge imported operations into. */\nconst importTargetDocumentName = ref<{ slug: string; label: string } | null>(\n null,\n)\nconst baseDocument = ref<OpenApiDocument | null>(null)\n\nwatch(importTargetDocumentName, async (value) => {\n if (!value) {\n baseDocument.value = null\n return\n }\n baseDocument.value = await workspaceStore.getEditableDocument(value.slug)\n})\n\nconst mergeSamePathAndMethod = ref(false)\n\nconst postmanDocumentDetails = computed(() =>\n getPostmanDocumentDetails(inputValue),\n)\nconst postmanRequestTree = computed(() =>\n buildPostmanRequestTree(postmanDocumentDetails.value?.collection ?? []),\n)\n\n/** Path keys to import from the Postman collection. */\nconst importPathKeys = ref<string[]>([])\n\nconst onPostmanRequestSelectionChange = (\n key: string,\n selected: boolean,\n): void => {\n importPathKeys.value = applyPostmanRequestSelectionChange(\n importPathKeys.value,\n key,\n selected,\n )\n}\n\nconst onPostmanFolderSelectionChange = (\n node: PostmanTreeNode,\n selected: boolean,\n): void => {\n importPathKeys.value = applyPostmanFolderSelectionChange(\n importPathKeys.value,\n node,\n selected,\n )\n}\n\nconst collisionsPathKeys = computed(() => {\n return getCollidingPostmanRequestPathKeys(\n postmanDocumentDetails.value?.collection ?? [],\n importPathKeys.value,\n baseDocument.value ?? undefined,\n )\n})\n\n/** Navigate to a document in the workspace. */\nconst navigateToDocument = (documentName: string): void => {\n eventBus.emit('ui:navigate', {\n page: 'document',\n path: 'overview',\n documentSlug: documentName,\n })\n}\n\n/** Handle import error. */\nconst handleImportError = async (errorMessage: string): Promise<void> => {\n console.error(errorMessage)\n toast(errorMessage, 'error')\n await loader.invalidate()\n emit('close')\n}\n\n/** Handle import. */\nconst handleImport = async (): Promise<void> => {\n loader.start()\n\n const mergeTarget = importTargetDocumentName.value?.slug ?? ''\n const mergeIntoExisting =\n mergeTarget.length > 0 &&\n workspaceStore.workspace.documents[mergeTarget] !== undefined\n\n const targetDocument = mergeIntoExisting\n ? await workspaceStore.getEditableDocument(mergeTarget)\n : null\n\n const options: ConvertOptions = {\n document: (targetDocument as unknown) ?? undefined,\n mergeOperation: mergeSamePathAndMethod.value,\n requestIndexPaths: pathKeysToRequestIndexPaths(importPathKeys.value),\n }\n\n const document = getOpenApiFromPostman(inputValue ?? '', options)\n\n if (document === null) {\n return handleImportError(\n 'Failed to convert Postman collection to OpenAPI document. Please contact support.',\n )\n }\n\n if (mergeIntoExisting) {\n await workspaceStore.replaceDocument(mergeTarget, document)\n await loader.validate()\n navigateToDocument(mergeTarget)\n emit('close')\n return\n }\n\n // Otherwise create a new document\n const slug = await generateUniqueSlug(\n document.info?.title ?? 'default',\n new Set(Object.keys(workspaceStore.workspace.documents)),\n )\n\n if (!slug) {\n return handleImportError(\n 'Failed to generate a unique slug for the imported document. Please contact support.',\n )\n }\n\n await workspaceStore.addDocument({\n name: slug,\n document,\n })\n\n await loader.validate()\n navigateToDocument(slug)\n emit('close')\n}\n</script>\n<template>\n <CommandActionForm\n :loader\n @submit=\"handleImport\">\n <div class=\"flex min-h-0 min-w-0 flex-1 flex-col gap-1.5 overflow-hidden\">\n <div class=\"flex shrink-0 justify-between\">\n <div class=\"text-c-2 min-h-7 w-full py-1.5 pl-12 text-center text-xs\">\n Postman collection\n </div>\n </div>\n\n <!-- Postman collection preview and tree picker -->\n <PostmanImportPreview\n v-if=\"postmanDocumentDetails\"\n v-model:mergeSamePathAndMethod=\"mergeSamePathAndMethod\"\n v-model:selectedTargetDocument=\"importTargetDocumentName\"\n :availableTargetDocuments=\"\n Object.entries(workspaceStore.workspace.documents).map(\n ([slug, document]) => ({\n slug,\n label: document.info?.title ?? slug,\n }),\n )\n \"\n :hasCollisionPathKeys=\"collisionsPathKeys.length > 0\"\n :schema=\"postmanDocumentDetails?.schemaLabel ?? undefined\"\n :title=\"postmanDocumentDetails?.title ?? ''\"\n :totalRequests=\"\n countPostmanRequestLeaves(postmanDocumentDetails?.collection ?? [])\n \"\n :version=\"postmanDocumentDetails?.version ?? ''\">\n <!-- Tree picker slot -->\n <template #treePicker>\n <PostmanRequestTreeRow\n v-for=\"node in postmanRequestTree\"\n :key=\"pathKey(node.path)\"\n :collisionPathKeys=\"collisionsPathKeys\"\n :mergeSamePathAndMethod=\"mergeSamePathAndMethod\"\n :node=\"node\"\n :selectedKeys=\"importPathKeys\"\n @folderSelectionChange=\"onPostmanFolderSelectionChange\"\n @requestSelectionChange=\"onPostmanRequestSelectionChange\" />\n </template>\n </PostmanImportPreview>\n </div>\n <template #submit> Import Postman Collection </template>\n </CommandActionForm>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"CommandPaletteImportPostman.vue.script.js","names":[],"sources":["../../../../../src/v2/features/command-palette/components/CommandPaletteImportPostman.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Command Palette Import Postman Component\n *\n * Imports Postman collections from URL, file, or pasted JSON, including\n * request selection, merge-into-existing, and convert options.\n */\nexport default {\n name: 'CommandPaletteImportPostman',\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { useLoadingState } from '@scalar/components'\nimport type { ConvertOptions } from '@scalar/postman-to-openapi'\nimport { useToasts } from '@scalar/use-toasts'\nimport { type WorkspaceStore } from '@scalar/workspace-store/client'\nimport type { WorkspaceEventBus } from '@scalar/workspace-store/events'\nimport type { OpenApiDocument } from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport { computed, ref, watch } from 'vue'\n\nimport PostmanImportPreview from '@/v2/features/command-palette/components/PostmanImportPreview.vue'\nimport PostmanRequestTreeRow from '@/v2/features/command-palette/components/PostmanRequestTreeRow.vue'\nimport { generateUniqueSlug } from '@/v2/features/command-palette/helpers/generate-unique-slug'\nimport { getOpenApiFromPostman } from '@/v2/features/command-palette/helpers/get-openapi-from-postman'\nimport { getPostmanConvertOptions } from '@/v2/features/command-palette/helpers/get-postman-convert-options'\nimport { getPostmanDocumentDetails } from '@/v2/features/command-palette/helpers/get-postman-document-details'\nimport { getCollidingPostmanRequestPathKeys } from '@/v2/features/command-palette/helpers/postman-request-collisions'\nimport {\n applyPostmanFolderSelectionChange,\n applyPostmanRequestSelectionChange,\n buildPostmanRequestTree,\n countPostmanRequestLeaves,\n type PostmanTreeNode,\n} from '@/v2/features/command-palette/helpers/postman-request-tree'\n\nimport CommandActionForm from './CommandActionForm.vue'\n\nconst {\n workspaceStore,\n eventBus,\n inputValue = '',\n} = defineProps<{\n workspaceStore: WorkspaceStore\n /** Event bus for emitting import events */\n eventBus: WorkspaceEventBus\n /** Pre-filled collection JSON (e.g. from file pick or redirected paste) */\n inputValue: string\n}>()\n\nconst emit = defineEmits<{\n (event: 'close'): void\n (event: 'back', keyboardEvent: KeyboardEvent): void\n}>()\n\nconst { toast } = useToasts()\n\nconst loader = useLoadingState()\n\n/** Document name to merge imported operations into. */\nconst importTargetDocumentName = ref<{ slug: string; label: string } | null>(\n null,\n)\nconst baseDocument = ref<OpenApiDocument | null>(null)\n\nwatch(importTargetDocumentName, async (value) => {\n if (!value) {\n baseDocument.value = null\n return\n }\n baseDocument.value = await workspaceStore.getEditableDocument(value.slug)\n})\n\nconst mergeSamePathAndMethod = ref(false)\n\nconst postmanDocumentDetails = computed(() =>\n getPostmanDocumentDetails(inputValue),\n)\nconst postmanRequestTree = computed(() =>\n buildPostmanRequestTree(postmanDocumentDetails.value?.collection ?? []),\n)\n\n/** Path keys to import from the Postman collection. */\nconst importPathKeys = ref<string[]>([])\n\nconst onPostmanRequestSelectionChange = (\n key: string,\n selected: boolean,\n): void => {\n importPathKeys.value = applyPostmanRequestSelectionChange(\n importPathKeys.value,\n key,\n selected,\n )\n}\n\nconst onPostmanFolderSelectionChange = (\n node: PostmanTreeNode,\n selected: boolean,\n): void => {\n importPathKeys.value = applyPostmanFolderSelectionChange(\n importPathKeys.value,\n node,\n selected,\n )\n}\n\n/** Wraps all top-level nodes in a single root folder so the tree row handles select-all. */\nconst rootTreeNode = computed<PostmanTreeNode>(() => ({\n path: [],\n name: postmanDocumentDetails.value?.title ?? 'Collection',\n isFolder: true,\n children: postmanRequestTree.value,\n}))\n\nconst collisionsPathKeys = computed(() => {\n return getCollidingPostmanRequestPathKeys(\n postmanDocumentDetails.value?.collection ?? [],\n importPathKeys.value,\n baseDocument.value ?? undefined,\n )\n})\n\n/** Navigate to a document in the workspace. */\nconst navigateToDocument = (documentName: string): void => {\n eventBus.emit('ui:navigate', {\n page: 'document',\n path: 'overview',\n documentSlug: documentName,\n })\n}\n\n/** Handle import error. */\nconst handleImportError = async (errorMessage: string): Promise<void> => {\n console.error(errorMessage)\n toast(errorMessage, 'error')\n await loader.invalidate()\n emit('close')\n}\n\n/** Handle import. */\nconst handleImport = async (): Promise<void> => {\n loader.start()\n\n const mergeTarget = importTargetDocumentName.value?.slug ?? ''\n const mergeIntoExisting =\n mergeTarget.length > 0 &&\n workspaceStore.workspace.documents[mergeTarget] !== undefined\n\n const targetDocument = mergeIntoExisting\n ? await workspaceStore.getEditableDocument(mergeTarget)\n : null\n\n const options: ConvertOptions = getPostmanConvertOptions({\n document: (targetDocument as unknown) ?? undefined,\n mergeOperation: mergeSamePathAndMethod.value,\n importPathKeys: importPathKeys.value,\n })\n\n const document = getOpenApiFromPostman(inputValue ?? '', options)\n\n if (document === null) {\n return handleImportError(\n 'Failed to convert Postman collection to OpenAPI document. Please contact support.',\n )\n }\n\n if (mergeIntoExisting) {\n await workspaceStore.replaceDocument(mergeTarget, document)\n await loader.validate()\n navigateToDocument(mergeTarget)\n emit('close')\n return\n }\n\n // Otherwise create a new document\n const slug = await generateUniqueSlug(\n document.info?.title ?? 'default',\n new Set(Object.keys(workspaceStore.workspace.documents)),\n )\n\n if (!slug) {\n return handleImportError(\n 'Failed to generate a unique slug for the imported document. Please contact support.',\n )\n }\n\n await workspaceStore.addDocument({\n name: slug,\n document,\n })\n\n await loader.validate()\n navigateToDocument(slug)\n emit('close')\n}\n</script>\n<template>\n <CommandActionForm\n :loader\n @submit=\"handleImport\">\n <div class=\"flex min-h-0 min-w-0 flex-1 flex-col gap-1.5 overflow-hidden\">\n <div class=\"flex shrink-0 justify-between\">\n <div class=\"text-c-2 min-h-7 w-full py-1.5 pl-12 text-center text-xs\">\n Postman collection\n </div>\n </div>\n\n <!-- Postman collection preview and tree picker -->\n <PostmanImportPreview\n v-if=\"postmanDocumentDetails\"\n v-model:mergeSamePathAndMethod=\"mergeSamePathAndMethod\"\n v-model:selectedTargetDocument=\"importTargetDocumentName\"\n :availableTargetDocuments=\"\n Object.entries(workspaceStore.workspace.documents).map(\n ([slug, document]) => ({\n slug,\n label: document.info?.title ?? slug,\n }),\n )\n \"\n :hasCollisionPathKeys=\"collisionsPathKeys.length > 0\"\n :schema=\"postmanDocumentDetails?.schemaLabel ?? undefined\"\n :title=\"postmanDocumentDetails?.title ?? ''\"\n :totalRequests=\"\n countPostmanRequestLeaves(postmanDocumentDetails?.collection ?? [])\n \"\n :version=\"postmanDocumentDetails?.version ?? ''\">\n <!-- Tree picker slot -->\n <template #treePicker>\n <PostmanRequestTreeRow\n :collisionPathKeys=\"collisionsPathKeys\"\n :mergeSamePathAndMethod=\"mergeSamePathAndMethod\"\n :node=\"rootTreeNode\"\n :selectedKeys=\"importPathKeys\"\n @folderSelectionChange=\"onPostmanFolderSelectionChange\"\n @requestSelectionChange=\"onPostmanRequestSelectionChange\" />\n </template>\n </PostmanImportPreview>\n </div>\n <template #submit> Import Postman Collection </template>\n </CommandActionForm>\n</template>\n"],"mappings":"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"}
@@ -2,7 +2,7 @@ import _plugin_vue_export_helper_default from "../../../../_virtual/_plugin-vue_
2
2
  import PostmanImportPreview_vue_vue_type_script_setup_true_lang_default from "./PostmanImportPreview.vue.script.js";
3
3
  /* empty css */
4
4
  //#region src/v2/features/command-palette/components/PostmanImportPreview.vue
5
- var PostmanImportPreview_default = /* @__PURE__ */ _plugin_vue_export_helper_default(PostmanImportPreview_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-9f13a627"]]);
5
+ var PostmanImportPreview_default = /* @__PURE__ */ _plugin_vue_export_helper_default(PostmanImportPreview_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-cc4f666d"]]);
6
6
  //#endregion
7
7
  export { PostmanImportPreview_default as default };
8
8
 
@@ -1 +1 @@
1
- {"version":3,"file":"PostmanImportPreview.vue.js","names":[],"sources":["../../../../../src/v2/features/command-palette/components/PostmanImportPreview.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Full Postman collection import preview: metadata, request picker, merge target, and convert options.\n */\nexport default {\n name: 'PostmanImportPreview',\n}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarCheckboxInput,\n ScalarIcon,\n ScalarListbox,\n ScalarTooltip,\n type ScalarListboxOption,\n} from '@scalar/components'\nimport { computed } from 'vue'\n\nconst props = defineProps<{\n title: string\n version: string\n schema?: string\n totalRequests: number\n availableTargetDocuments: { slug: string; label: string }[]\n hasCollisionPathKeys: boolean\n}>()\n\nconst slots = defineSlots<{\n treePicker: () => unknown\n}>()\n\nconst selectedTargetDocument = defineModel<{\n slug: string\n label: string\n} | null>('selectedTargetDocument')\nconst mergeSamePathAndMethod = defineModel<boolean>('mergeSamePathAndMethod')\n\n/** Listbox id for \"create a new document\" — parent model stays `null`. */\nconst NEW_DOCUMENT_LISTBOX_ID = '__postman_import_new__'\n\nconst importDestinationOptions = computed<ScalarListboxOption[]>(() => [\n { id: NEW_DOCUMENT_LISTBOX_ID, label: 'New document' },\n ...props.availableTargetDocuments.map((d) => ({\n id: d.slug,\n label: d.label,\n })),\n])\n\nconst resolvedImportDestinationOption = computed((): ScalarListboxOption => {\n const options = importDestinationOptions.value\n const fallback = options[0]!\n const sel = selectedTargetDocument.value\n if (!sel) {\n return fallback\n }\n return options.find((o) => o.id === sel.slug) ?? fallback\n})\n\nconst onImportDestinationChange = (option: ScalarListboxOption): void => {\n if (option.id === NEW_DOCUMENT_LISTBOX_ID) {\n selectedTargetDocument.value = null\n return\n }\n selectedTargetDocument.value = {\n slug: option.id,\n label: option.label,\n }\n}\n</script>\n\n<template>\n <div class=\"flex flex-1 flex-col gap-1.5 overflow-hidden\">\n <div class=\"flex flex-1 flex-col gap-1.5 overflow-hidden\">\n <div\n class=\"border-border bg-b-2 text-c-2 shrink-0 rounded border px-2.5 py-1.5 text-xs leading-tight\">\n <div class=\"text-c-1 truncate font-medium\">\n {{ title }}\n </div>\n <div\n class=\"text-c-3 mt-0.5 flex flex-wrap items-center gap-x-1.5 gap-y-0.5\">\n <template v-if=\"schema\">\n <span class=\"whitespace-nowrap\">\n {{ schema }}\n </span>\n <span\n aria-hidden=\"true\"\n class=\"text-c-3 opacity-50\">\n ·\n </span>\n </template>\n <span class=\"whitespace-nowrap\"> v{{ version }} </span>\n <span\n aria-hidden=\"true\"\n class=\"text-c-3 opacity-50\">\n ·\n </span>\n <span class=\"whitespace-nowrap\">\n {{ totalRequests }}\n {{ totalRequests === 1 ? 'request' : 'requests' }}\n </span>\n </div>\n </div>\n <div\n v-if=\"hasCollisionPathKeys\"\n class=\"postman-import-path-conflict-callout w-full max-w-full rounded-md border px-2.5 py-1.5 text-xs leading-snug\">\n <div class=\"[overflow-wrap:anywhere] [word-break:break-word]\">\n <span class=\"font-semibold text-[var(--scalar-color-red)]\">\n Conflict\n </span>\n <template v-if=\"selectedTargetDocument\">\n — Same OpenAPI path + method as existing operations in\n <span class=\"font-medium\">\n {{ selectedTargetDocument.label }}\n </span>\n .\n <template v-if=\"!mergeSamePathAndMethod\">\n These will overwrite existing operations unless\n <span class=\"font-medium\">Merge same path &amp; method</span>\n is enabled.\n </template>\n <template v-else>\n These will be merged with existing operations.\n </template>\n </template>\n <template v-else>\n — Same OpenAPI path + method for multiple selected requests. Turn on\n <span class=\"font-medium\">Merge same path &amp; method</span>\n to combine them; otherwise the last one wins.\n </template>\n </div>\n </div>\n </div>\n <div class=\"max-h-[300px] overflow-y-auto\">\n <slots.treePicker />\n </div>\n\n <section\n class=\"border-border bg-b-2 flex shrink-0 flex-col gap-3 rounded-md border px-2.5 py-2.5\">\n <div\n v-if=\"availableTargetDocuments.length > 0\"\n class=\"border-border flex flex-col gap-2 border-b border-dashed pb-3\">\n <div>\n <p class=\"text-c-1 text-xs font-semibold tracking-tight\">\n Import destination\n </p>\n <p class=\"text-c-3 mt-1 text-xs leading-snug\">\n Put operations into an existing API description, or create a new\n document in this workspace.\n </p>\n </div>\n <ScalarListbox\n id=\"postman-import-target\"\n label=\"Import destination\"\n :modelValue=\"resolvedImportDestinationOption\"\n :options=\"importDestinationOptions\"\n placement=\"bottom-start\"\n resize\n @update:modelValue=\"onImportDestinationChange\">\n <ScalarButton\n class=\"hover:bg-b-2 h-9 w-full justify-between gap-2 px-2.5 py-2 text-left text-xs\"\n variant=\"outlined\">\n <span class=\"text-c-1 truncate font-medium\">\n {{ resolvedImportDestinationOption.label }}\n </span>\n <ScalarIcon\n class=\"text-c-3 shrink-0\"\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n </div>\n <ScalarTooltip\n content=\"When several Postman requests map to the same OpenAPI path and HTTP method, merge them into one operation instead of keeping duplicate operations.\"\n placement=\"top\">\n <div\n class=\"[&>label]:bg-transparent [&>label]:p-0 [&>label]:shadow-none [&>label]:hover:bg-transparent\">\n <ScalarCheckboxInput v-model=\"mergeSamePathAndMethod\">\n <span class=\"text-c-1 text-xs leading-snug font-medium\">\n Merge same path &amp; method\n </span>\n </ScalarCheckboxInput>\n </div>\n </ScalarTooltip>\n </section>\n </div>\n</template>\n\n<style scoped>\n.postman-import-path-conflict-callout {\n border-color: var(--scalar-color-red);\n background-color: var(--scalar-background-danger);\n color: var(--scalar-color-1);\n}\n</style>\n"],"mappings":""}
1
+ {"version":3,"file":"PostmanImportPreview.vue.js","names":[],"sources":["../../../../../src/v2/features/command-palette/components/PostmanImportPreview.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Full Postman collection import preview: metadata, request picker, merge target, and convert options.\n */\nexport default {\n name: 'PostmanImportPreview',\n}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarCheckboxInput,\n ScalarIcon,\n ScalarListbox,\n ScalarTooltip,\n type ScalarListboxOption,\n} from '@scalar/components'\nimport { computed } from 'vue'\n\nconst props = defineProps<{\n title: string\n version: string\n schema?: string\n totalRequests: number\n availableTargetDocuments: { slug: string; label: string }[]\n hasCollisionPathKeys: boolean\n}>()\n\nconst slots = defineSlots<{\n treePicker: () => unknown\n}>()\n\nconst selectedTargetDocument = defineModel<{\n slug: string\n label: string\n} | null>('selectedTargetDocument')\nconst mergeSamePathAndMethod = defineModel<boolean>('mergeSamePathAndMethod')\n\n/** Listbox id for \"create a new document\" — parent model stays `null`. */\nconst NEW_DOCUMENT_LISTBOX_ID = '__postman_import_new__'\n\nconst importDestinationOptions = computed<ScalarListboxOption[]>(() => [\n { id: NEW_DOCUMENT_LISTBOX_ID, label: 'New document' },\n ...props.availableTargetDocuments.map((d) => ({\n id: d.slug,\n label: d.label,\n })),\n])\n\nconst resolvedImportDestinationOption = computed((): ScalarListboxOption => {\n const options = importDestinationOptions.value\n const fallback = options[0]!\n const sel = selectedTargetDocument.value\n if (!sel) {\n return fallback\n }\n return options.find((o) => o.id === sel.slug) ?? fallback\n})\n\nconst onImportDestinationChange = (option: ScalarListboxOption): void => {\n if (option.id === NEW_DOCUMENT_LISTBOX_ID) {\n selectedTargetDocument.value = null\n return\n }\n selectedTargetDocument.value = {\n slug: option.id,\n label: option.label,\n }\n}\n</script>\n\n<template>\n <div class=\"flex flex-1 flex-col gap-1.5 overflow-hidden\">\n <div class=\"flex flex-1 flex-col gap-1.5 overflow-hidden\">\n <div\n class=\"border-border bg-b-2 text-c-2 shrink-0 rounded border px-2.5 py-1.5 text-xs leading-tight\">\n <div class=\"text-c-1 truncate font-medium\">\n {{ title }}\n </div>\n <div\n class=\"text-c-3 mt-0.5 flex flex-wrap items-center gap-x-1.5 gap-y-0.5\">\n <template v-if=\"schema\">\n <span class=\"whitespace-nowrap\">\n {{ schema }}\n </span>\n <span\n aria-hidden=\"true\"\n class=\"text-c-3 opacity-50\">\n ·\n </span>\n </template>\n <span class=\"whitespace-nowrap\"> v{{ version }} </span>\n <span\n aria-hidden=\"true\"\n class=\"text-c-3 opacity-50\">\n ·\n </span>\n <span class=\"whitespace-nowrap\">\n {{ totalRequests }}\n {{ totalRequests === 1 ? 'request' : 'requests' }}\n </span>\n </div>\n </div>\n <div\n v-if=\"hasCollisionPathKeys\"\n class=\"postman-import-path-conflict-callout w-full max-w-full rounded-md border px-2.5 py-1.5 text-xs leading-snug\">\n <div class=\"[overflow-wrap:anywhere] [word-break:break-word]\">\n <span class=\"font-semibold text-[var(--scalar-color-red)]\">\n Conflict\n </span>\n <template v-if=\"selectedTargetDocument\">\n — Same OpenAPI path + method as existing operations in\n <span class=\"font-medium\">\n {{ selectedTargetDocument.label }}\n </span>\n .\n <template v-if=\"!mergeSamePathAndMethod\">\n These will overwrite existing operations unless\n <span class=\"font-medium\">Merge same path &amp; method</span>\n is enabled.\n </template>\n <template v-else>\n These will be merged with existing operations.\n </template>\n </template>\n <template v-else>\n — Same OpenAPI path + method for multiple selected requests. Turn on\n <span class=\"font-medium\">Merge same path &amp; method</span>\n to combine them; otherwise the last one wins.\n </template>\n </div>\n </div>\n </div>\n <div class=\"h-[300px] overflow-y-auto\">\n <slots.treePicker />\n </div>\n\n <section\n class=\"border-border bg-b-2 flex shrink-0 flex-col gap-3 rounded-md border px-2.5 py-2.5\">\n <div\n v-if=\"availableTargetDocuments.length > 0\"\n class=\"border-border flex flex-col gap-2 border-b border-dashed pb-3\">\n <div>\n <p class=\"text-c-1 text-xs font-semibold tracking-tight\">\n Import destination\n </p>\n <p class=\"text-c-3 mt-1 text-xs leading-snug\">\n Put operations into an existing API description, or create a new\n document in this workspace.\n </p>\n </div>\n <ScalarListbox\n id=\"postman-import-target\"\n label=\"Import destination\"\n :modelValue=\"resolvedImportDestinationOption\"\n :options=\"importDestinationOptions\"\n placement=\"bottom-start\"\n resize\n @update:modelValue=\"onImportDestinationChange\">\n <ScalarButton\n class=\"hover:bg-b-2 h-9 w-full justify-between gap-2 px-2.5 py-2 text-left text-xs\"\n variant=\"outlined\">\n <span class=\"text-c-1 truncate font-medium\">\n {{ resolvedImportDestinationOption.label }}\n </span>\n <ScalarIcon\n class=\"text-c-3 shrink-0\"\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n </div>\n <ScalarTooltip\n content=\"When several Postman requests map to the same OpenAPI path and HTTP method, merge them into one operation instead of keeping duplicate operations.\"\n placement=\"top\">\n <div\n class=\"[&>label]:bg-transparent [&>label]:p-0 [&>label]:shadow-none [&>label]:hover:bg-transparent\">\n <ScalarCheckboxInput v-model=\"mergeSamePathAndMethod\">\n <span class=\"text-c-1 text-xs leading-snug font-medium\">\n Merge same path &amp; method\n </span>\n </ScalarCheckboxInput>\n </div>\n </ScalarTooltip>\n </section>\n </div>\n</template>\n\n<style scoped>\n.postman-import-path-conflict-callout {\n border-color: var(--scalar-color-red);\n background-color: var(--scalar-background-danger);\n color: var(--scalar-color-1);\n}\n</style>\n"],"mappings":""}
@@ -15,7 +15,7 @@ var _hoisted_9 = {
15
15
  };
16
16
  var _hoisted_10 = { class: "[overflow-wrap:anywhere] [word-break:break-word]" };
17
17
  var _hoisted_11 = { class: "font-medium" };
18
- var _hoisted_12 = { class: "max-h-[300px] overflow-y-auto" };
18
+ var _hoisted_12 = { class: "h-[300px] overflow-y-auto" };
19
19
  var _hoisted_13 = { class: "border-border bg-b-2 flex shrink-0 flex-col gap-3 rounded-md border px-2.5 py-2.5" };
20
20
  var _hoisted_14 = {
21
21
  key: 0,
@@ -1 +1 @@
1
- {"version":3,"file":"PostmanImportPreview.vue.script.js","names":[],"sources":["../../../../../src/v2/features/command-palette/components/PostmanImportPreview.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Full Postman collection import preview: metadata, request picker, merge target, and convert options.\n */\nexport default {\n name: 'PostmanImportPreview',\n}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarCheckboxInput,\n ScalarIcon,\n ScalarListbox,\n ScalarTooltip,\n type ScalarListboxOption,\n} from '@scalar/components'\nimport { computed } from 'vue'\n\nconst props = defineProps<{\n title: string\n version: string\n schema?: string\n totalRequests: number\n availableTargetDocuments: { slug: string; label: string }[]\n hasCollisionPathKeys: boolean\n}>()\n\nconst slots = defineSlots<{\n treePicker: () => unknown\n}>()\n\nconst selectedTargetDocument = defineModel<{\n slug: string\n label: string\n} | null>('selectedTargetDocument')\nconst mergeSamePathAndMethod = defineModel<boolean>('mergeSamePathAndMethod')\n\n/** Listbox id for \"create a new document\" — parent model stays `null`. */\nconst NEW_DOCUMENT_LISTBOX_ID = '__postman_import_new__'\n\nconst importDestinationOptions = computed<ScalarListboxOption[]>(() => [\n { id: NEW_DOCUMENT_LISTBOX_ID, label: 'New document' },\n ...props.availableTargetDocuments.map((d) => ({\n id: d.slug,\n label: d.label,\n })),\n])\n\nconst resolvedImportDestinationOption = computed((): ScalarListboxOption => {\n const options = importDestinationOptions.value\n const fallback = options[0]!\n const sel = selectedTargetDocument.value\n if (!sel) {\n return fallback\n }\n return options.find((o) => o.id === sel.slug) ?? fallback\n})\n\nconst onImportDestinationChange = (option: ScalarListboxOption): void => {\n if (option.id === NEW_DOCUMENT_LISTBOX_ID) {\n selectedTargetDocument.value = null\n return\n }\n selectedTargetDocument.value = {\n slug: option.id,\n label: option.label,\n }\n}\n</script>\n\n<template>\n <div class=\"flex flex-1 flex-col gap-1.5 overflow-hidden\">\n <div class=\"flex flex-1 flex-col gap-1.5 overflow-hidden\">\n <div\n class=\"border-border bg-b-2 text-c-2 shrink-0 rounded border px-2.5 py-1.5 text-xs leading-tight\">\n <div class=\"text-c-1 truncate font-medium\">\n {{ title }}\n </div>\n <div\n class=\"text-c-3 mt-0.5 flex flex-wrap items-center gap-x-1.5 gap-y-0.5\">\n <template v-if=\"schema\">\n <span class=\"whitespace-nowrap\">\n {{ schema }}\n </span>\n <span\n aria-hidden=\"true\"\n class=\"text-c-3 opacity-50\">\n ·\n </span>\n </template>\n <span class=\"whitespace-nowrap\"> v{{ version }} </span>\n <span\n aria-hidden=\"true\"\n class=\"text-c-3 opacity-50\">\n ·\n </span>\n <span class=\"whitespace-nowrap\">\n {{ totalRequests }}\n {{ totalRequests === 1 ? 'request' : 'requests' }}\n </span>\n </div>\n </div>\n <div\n v-if=\"hasCollisionPathKeys\"\n class=\"postman-import-path-conflict-callout w-full max-w-full rounded-md border px-2.5 py-1.5 text-xs leading-snug\">\n <div class=\"[overflow-wrap:anywhere] [word-break:break-word]\">\n <span class=\"font-semibold text-[var(--scalar-color-red)]\">\n Conflict\n </span>\n <template v-if=\"selectedTargetDocument\">\n — Same OpenAPI path + method as existing operations in\n <span class=\"font-medium\">\n {{ selectedTargetDocument.label }}\n </span>\n .\n <template v-if=\"!mergeSamePathAndMethod\">\n These will overwrite existing operations unless\n <span class=\"font-medium\">Merge same path &amp; method</span>\n is enabled.\n </template>\n <template v-else>\n These will be merged with existing operations.\n </template>\n </template>\n <template v-else>\n — Same OpenAPI path + method for multiple selected requests. Turn on\n <span class=\"font-medium\">Merge same path &amp; method</span>\n to combine them; otherwise the last one wins.\n </template>\n </div>\n </div>\n </div>\n <div class=\"max-h-[300px] overflow-y-auto\">\n <slots.treePicker />\n </div>\n\n <section\n class=\"border-border bg-b-2 flex shrink-0 flex-col gap-3 rounded-md border px-2.5 py-2.5\">\n <div\n v-if=\"availableTargetDocuments.length > 0\"\n class=\"border-border flex flex-col gap-2 border-b border-dashed pb-3\">\n <div>\n <p class=\"text-c-1 text-xs font-semibold tracking-tight\">\n Import destination\n </p>\n <p class=\"text-c-3 mt-1 text-xs leading-snug\">\n Put operations into an existing API description, or create a new\n document in this workspace.\n </p>\n </div>\n <ScalarListbox\n id=\"postman-import-target\"\n label=\"Import destination\"\n :modelValue=\"resolvedImportDestinationOption\"\n :options=\"importDestinationOptions\"\n placement=\"bottom-start\"\n resize\n @update:modelValue=\"onImportDestinationChange\">\n <ScalarButton\n class=\"hover:bg-b-2 h-9 w-full justify-between gap-2 px-2.5 py-2 text-left text-xs\"\n variant=\"outlined\">\n <span class=\"text-c-1 truncate font-medium\">\n {{ resolvedImportDestinationOption.label }}\n </span>\n <ScalarIcon\n class=\"text-c-3 shrink-0\"\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n </div>\n <ScalarTooltip\n content=\"When several Postman requests map to the same OpenAPI path and HTTP method, merge them into one operation instead of keeping duplicate operations.\"\n placement=\"top\">\n <div\n class=\"[&>label]:bg-transparent [&>label]:p-0 [&>label]:shadow-none [&>label]:hover:bg-transparent\">\n <ScalarCheckboxInput v-model=\"mergeSamePathAndMethod\">\n <span class=\"text-c-1 text-xs leading-snug font-medium\">\n Merge same path &amp; method\n </span>\n </ScalarCheckboxInput>\n </div>\n </ScalarTooltip>\n </section>\n </div>\n</template>\n\n<style scoped>\n.postman-import-path-conflict-callout {\n border-color: var(--scalar-color-red);\n background-color: var(--scalar-background-danger);\n color: var(--scalar-color-1);\n}\n</style>\n"],"mappings":"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"}
1
+ {"version":3,"file":"PostmanImportPreview.vue.script.js","names":[],"sources":["../../../../../src/v2/features/command-palette/components/PostmanImportPreview.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * Full Postman collection import preview: metadata, request picker, merge target, and convert options.\n */\nexport default {\n name: 'PostmanImportPreview',\n}\n</script>\n\n<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarCheckboxInput,\n ScalarIcon,\n ScalarListbox,\n ScalarTooltip,\n type ScalarListboxOption,\n} from '@scalar/components'\nimport { computed } from 'vue'\n\nconst props = defineProps<{\n title: string\n version: string\n schema?: string\n totalRequests: number\n availableTargetDocuments: { slug: string; label: string }[]\n hasCollisionPathKeys: boolean\n}>()\n\nconst slots = defineSlots<{\n treePicker: () => unknown\n}>()\n\nconst selectedTargetDocument = defineModel<{\n slug: string\n label: string\n} | null>('selectedTargetDocument')\nconst mergeSamePathAndMethod = defineModel<boolean>('mergeSamePathAndMethod')\n\n/** Listbox id for \"create a new document\" — parent model stays `null`. */\nconst NEW_DOCUMENT_LISTBOX_ID = '__postman_import_new__'\n\nconst importDestinationOptions = computed<ScalarListboxOption[]>(() => [\n { id: NEW_DOCUMENT_LISTBOX_ID, label: 'New document' },\n ...props.availableTargetDocuments.map((d) => ({\n id: d.slug,\n label: d.label,\n })),\n])\n\nconst resolvedImportDestinationOption = computed((): ScalarListboxOption => {\n const options = importDestinationOptions.value\n const fallback = options[0]!\n const sel = selectedTargetDocument.value\n if (!sel) {\n return fallback\n }\n return options.find((o) => o.id === sel.slug) ?? fallback\n})\n\nconst onImportDestinationChange = (option: ScalarListboxOption): void => {\n if (option.id === NEW_DOCUMENT_LISTBOX_ID) {\n selectedTargetDocument.value = null\n return\n }\n selectedTargetDocument.value = {\n slug: option.id,\n label: option.label,\n }\n}\n</script>\n\n<template>\n <div class=\"flex flex-1 flex-col gap-1.5 overflow-hidden\">\n <div class=\"flex flex-1 flex-col gap-1.5 overflow-hidden\">\n <div\n class=\"border-border bg-b-2 text-c-2 shrink-0 rounded border px-2.5 py-1.5 text-xs leading-tight\">\n <div class=\"text-c-1 truncate font-medium\">\n {{ title }}\n </div>\n <div\n class=\"text-c-3 mt-0.5 flex flex-wrap items-center gap-x-1.5 gap-y-0.5\">\n <template v-if=\"schema\">\n <span class=\"whitespace-nowrap\">\n {{ schema }}\n </span>\n <span\n aria-hidden=\"true\"\n class=\"text-c-3 opacity-50\">\n ·\n </span>\n </template>\n <span class=\"whitespace-nowrap\"> v{{ version }} </span>\n <span\n aria-hidden=\"true\"\n class=\"text-c-3 opacity-50\">\n ·\n </span>\n <span class=\"whitespace-nowrap\">\n {{ totalRequests }}\n {{ totalRequests === 1 ? 'request' : 'requests' }}\n </span>\n </div>\n </div>\n <div\n v-if=\"hasCollisionPathKeys\"\n class=\"postman-import-path-conflict-callout w-full max-w-full rounded-md border px-2.5 py-1.5 text-xs leading-snug\">\n <div class=\"[overflow-wrap:anywhere] [word-break:break-word]\">\n <span class=\"font-semibold text-[var(--scalar-color-red)]\">\n Conflict\n </span>\n <template v-if=\"selectedTargetDocument\">\n — Same OpenAPI path + method as existing operations in\n <span class=\"font-medium\">\n {{ selectedTargetDocument.label }}\n </span>\n .\n <template v-if=\"!mergeSamePathAndMethod\">\n These will overwrite existing operations unless\n <span class=\"font-medium\">Merge same path &amp; method</span>\n is enabled.\n </template>\n <template v-else>\n These will be merged with existing operations.\n </template>\n </template>\n <template v-else>\n — Same OpenAPI path + method for multiple selected requests. Turn on\n <span class=\"font-medium\">Merge same path &amp; method</span>\n to combine them; otherwise the last one wins.\n </template>\n </div>\n </div>\n </div>\n <div class=\"h-[300px] overflow-y-auto\">\n <slots.treePicker />\n </div>\n\n <section\n class=\"border-border bg-b-2 flex shrink-0 flex-col gap-3 rounded-md border px-2.5 py-2.5\">\n <div\n v-if=\"availableTargetDocuments.length > 0\"\n class=\"border-border flex flex-col gap-2 border-b border-dashed pb-3\">\n <div>\n <p class=\"text-c-1 text-xs font-semibold tracking-tight\">\n Import destination\n </p>\n <p class=\"text-c-3 mt-1 text-xs leading-snug\">\n Put operations into an existing API description, or create a new\n document in this workspace.\n </p>\n </div>\n <ScalarListbox\n id=\"postman-import-target\"\n label=\"Import destination\"\n :modelValue=\"resolvedImportDestinationOption\"\n :options=\"importDestinationOptions\"\n placement=\"bottom-start\"\n resize\n @update:modelValue=\"onImportDestinationChange\">\n <ScalarButton\n class=\"hover:bg-b-2 h-9 w-full justify-between gap-2 px-2.5 py-2 text-left text-xs\"\n variant=\"outlined\">\n <span class=\"text-c-1 truncate font-medium\">\n {{ resolvedImportDestinationOption.label }}\n </span>\n <ScalarIcon\n class=\"text-c-3 shrink-0\"\n icon=\"ChevronDown\"\n size=\"md\" />\n </ScalarButton>\n </ScalarListbox>\n </div>\n <ScalarTooltip\n content=\"When several Postman requests map to the same OpenAPI path and HTTP method, merge them into one operation instead of keeping duplicate operations.\"\n placement=\"top\">\n <div\n class=\"[&>label]:bg-transparent [&>label]:p-0 [&>label]:shadow-none [&>label]:hover:bg-transparent\">\n <ScalarCheckboxInput v-model=\"mergeSamePathAndMethod\">\n <span class=\"text-c-1 text-xs leading-snug font-medium\">\n Merge same path &amp; method\n </span>\n </ScalarCheckboxInput>\n </div>\n </ScalarTooltip>\n </section>\n </div>\n</template>\n\n<style scoped>\n.postman-import-path-conflict-callout {\n border-color: var(--scalar-color-red);\n background-color: var(--scalar-background-danger);\n color: var(--scalar-color-1);\n}\n</style>\n"],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { ConvertOptions } from '@scalar/postman-to-openapi';
2
+ type GetPostmanConvertOptionsInput = {
3
+ document?: ConvertOptions['document'] | null;
4
+ mergeOperation: boolean;
5
+ importPathKeys: readonly string[];
6
+ };
7
+ /**
8
+ * Builds Postman conversion options from command palette state.
9
+ *
10
+ * An empty selection means "import all requests", so we omit requestIndexPaths.
11
+ */
12
+ export declare const getPostmanConvertOptions: ({ document, mergeOperation, importPathKeys, }: GetPostmanConvertOptionsInput) => ConvertOptions;
13
+ export {};
14
+ //# sourceMappingURL=get-postman-convert-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-postman-convert-options.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/command-palette/helpers/get-postman-convert-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAIhE,KAAK,6BAA6B,GAAG;IACnC,QAAQ,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,IAAI,CAAA;IAC5C,cAAc,EAAE,OAAO,CAAA;IACvB,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;CAClC,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GAAI,+CAItC,6BAA6B,KAAG,cAQlC,CAAA"}
@@ -0,0 +1,19 @@
1
+ import { pathKeysToRequestIndexPaths } from "./postman-request-tree.js";
2
+ //#region src/v2/features/command-palette/helpers/get-postman-convert-options.ts
3
+ /**
4
+ * Builds Postman conversion options from command palette state.
5
+ *
6
+ * An empty selection means "import all requests", so we omit requestIndexPaths.
7
+ */
8
+ var getPostmanConvertOptions = ({ document, mergeOperation, importPathKeys }) => {
9
+ const requestIndexPaths = importPathKeys.length > 0 ? pathKeysToRequestIndexPaths(importPathKeys) : void 0;
10
+ return {
11
+ document: document ?? void 0,
12
+ mergeOperation,
13
+ requestIndexPaths
14
+ };
15
+ };
16
+ //#endregion
17
+ export { getPostmanConvertOptions };
18
+
19
+ //# sourceMappingURL=get-postman-convert-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-postman-convert-options.js","names":[],"sources":["../../../../../src/v2/features/command-palette/helpers/get-postman-convert-options.ts"],"sourcesContent":["import type { ConvertOptions } from '@scalar/postman-to-openapi'\n\nimport { pathKeysToRequestIndexPaths } from '@/v2/features/command-palette/helpers/postman-request-tree'\n\ntype GetPostmanConvertOptionsInput = {\n document?: ConvertOptions['document'] | null\n mergeOperation: boolean\n importPathKeys: readonly string[]\n}\n\n/**\n * Builds Postman conversion options from command palette state.\n *\n * An empty selection means \"import all requests\", so we omit requestIndexPaths.\n */\nexport const getPostmanConvertOptions = ({\n document,\n mergeOperation,\n importPathKeys,\n}: GetPostmanConvertOptionsInput): ConvertOptions => {\n const requestIndexPaths = importPathKeys.length > 0 ? pathKeysToRequestIndexPaths(importPathKeys) : undefined\n\n return {\n document: document ?? undefined,\n mergeOperation,\n requestIndexPaths,\n }\n}\n"],"mappings":";;;;;;;AAeA,IAAa,4BAA4B,EACvC,UACA,gBACA,qBACmD;CACnD,MAAM,oBAAoB,eAAe,SAAS,IAAI,4BAA4B,eAAe,GAAG,KAAA;AAEpG,QAAO;EACL,UAAU,YAAY,KAAA;EACtB;EACA;EACD"}
@@ -1,4 +1,4 @@
1
- import { isPostmanCollection } from "./is-postman-collection.js";
1
+ import { isPostmanCollection } from "@scalar/postman-to-openapi";
2
2
  //#region src/v2/features/command-palette/helpers/get-postman-document-details.ts
3
3
  var extractSchemaLabel = (schema) => {
4
4
  if (typeof schema !== "string") return;
@@ -1 +1 @@
1
- {"version":3,"file":"get-postman-document-details.js","names":[],"sources":["../../../../../src/v2/features/command-palette/helpers/get-postman-document-details.ts"],"sourcesContent":["import { isPostmanCollection } from '@/v2/features/command-palette/helpers/is-postman-collection'\n\n/**\n * Represents the extracted details from a Postman collection.\n * Used to display collection metadata in the command palette import UI.\n */\ntype PostmanDocumentDetails = {\n /** The document format type. */\n type: string\n /** The name of the Postman collection. */\n title: string\n /** The version of the Postman collection. */\n version: string\n /** Postman collection schema segment from `info.schema` (e.g. `v2.1.0`), when present. */\n schemaLabel?: string\n /** The collection items. */\n collection: unknown[]\n}\n\nconst extractSchemaLabel = (schema: unknown): string | undefined => {\n if (typeof schema !== 'string') {\n return undefined\n }\n const match = schema.match(/\\/collection\\/(v[\\d.]+)\\//i)\n return match?.[1]\n}\n\n/**\n * Extracts document details from a Postman collection JSON string.\n *\n * We parse and validate in a single pass to avoid the performance cost\n * of parsing the JSON twice.\n *\n * @param content - The JSON string representing the Postman collection\n * @returns The collection details if valid, null otherwise\n */\nexport const getPostmanDocumentDetails = (content: string): PostmanDocumentDetails | null => {\n if (!isPostmanCollection(content)) {\n return null\n }\n\n try {\n const parsed = JSON.parse(content)\n\n const schemaLabel = extractSchemaLabel(parsed.info?.schema)\n\n const collectionItems = Array.isArray(parsed.item) ? parsed.item : []\n\n return {\n type: 'json',\n title: parsed.info?.name || 'Postman Collection',\n version: parsed.info?.version || '1.0',\n schemaLabel: schemaLabel ?? undefined,\n collection: collectionItems,\n }\n } catch {\n return null\n }\n}\n"],"mappings":";;AAmBA,IAAM,sBAAsB,WAAwC;AAClE,KAAI,OAAO,WAAW,SACpB;AAGF,QADc,OAAO,MAAM,6BAA6B,GACzC;;;;;;;;;;;AAYjB,IAAa,6BAA6B,YAAmD;AAC3F,KAAI,CAAC,oBAAoB,QAAQ,CAC/B,QAAO;AAGT,KAAI;EACF,MAAM,SAAS,KAAK,MAAM,QAAQ;EAElC,MAAM,cAAc,mBAAmB,OAAO,MAAM,OAAO;EAE3D,MAAM,kBAAkB,MAAM,QAAQ,OAAO,KAAK,GAAG,OAAO,OAAO,EAAE;AAErE,SAAO;GACL,MAAM;GACN,OAAO,OAAO,MAAM,QAAQ;GAC5B,SAAS,OAAO,MAAM,WAAW;GACjC,aAAa,eAAe,KAAA;GAC5B,YAAY;GACb;SACK;AACN,SAAO"}
1
+ {"version":3,"file":"get-postman-document-details.js","names":[],"sources":["../../../../../src/v2/features/command-palette/helpers/get-postman-document-details.ts"],"sourcesContent":["import { isPostmanCollection } from '@scalar/postman-to-openapi'\n\n/**\n * Represents the extracted details from a Postman collection.\n * Used to display collection metadata in the command palette import UI.\n */\ntype PostmanDocumentDetails = {\n /** The document format type. */\n type: string\n /** The name of the Postman collection. */\n title: string\n /** The version of the Postman collection. */\n version: string\n /** Postman collection schema segment from `info.schema` (e.g. `v2.1.0`), when present. */\n schemaLabel?: string\n /** The collection items. */\n collection: unknown[]\n}\n\nconst extractSchemaLabel = (schema: unknown): string | undefined => {\n if (typeof schema !== 'string') {\n return undefined\n }\n const match = schema.match(/\\/collection\\/(v[\\d.]+)\\//i)\n return match?.[1]\n}\n\n/**\n * Extracts document details from a Postman collection JSON string.\n *\n * We parse and validate in a single pass to avoid the performance cost\n * of parsing the JSON twice.\n *\n * @param content - The JSON string representing the Postman collection\n * @returns The collection details if valid, null otherwise\n */\nexport const getPostmanDocumentDetails = (content: string): PostmanDocumentDetails | null => {\n if (!isPostmanCollection(content)) {\n return null\n }\n\n try {\n const parsed = JSON.parse(content)\n\n const schemaLabel = extractSchemaLabel(parsed.info?.schema)\n\n const collectionItems = Array.isArray(parsed.item) ? parsed.item : []\n\n return {\n type: 'json',\n title: parsed.info?.name || 'Postman Collection',\n version: parsed.info?.version || '1.0',\n schemaLabel: schemaLabel ?? undefined,\n collection: collectionItems,\n }\n } catch {\n return null\n }\n}\n"],"mappings":";;AAmBA,IAAM,sBAAsB,WAAwC;AAClE,KAAI,OAAO,WAAW,SACpB;AAGF,QADc,OAAO,MAAM,6BAA6B,GACzC;;;;;;;;;;;AAYjB,IAAa,6BAA6B,YAAmD;AAC3F,KAAI,CAAC,oBAAoB,QAAQ,CAC/B,QAAO;AAGT,KAAI;EACF,MAAM,SAAS,KAAK,MAAM,QAAQ;EAElC,MAAM,cAAc,mBAAmB,OAAO,MAAM,OAAO;EAE3D,MAAM,kBAAkB,MAAM,QAAQ,OAAO,KAAK,GAAG,OAAO,OAAO,EAAE;AAErE,SAAO;GACL,MAAM;GACN,OAAO,OAAO,MAAM,QAAQ;GAC5B,SAAS,OAAO,MAAM,WAAW;GACjC,aAAa,eAAe,KAAA;GAC5B,YAAY;GACb;SACK;AACN,SAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"load-document-from-source.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/command-palette/helpers/load-document-from-source.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAKpE,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,CAAA;CAC7B,CAAA;AAiCD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,sBAAsB,GACjC,gBAAgB,cAAc,EAC9B,iBAAiB,eAAe,EAChC,MAAM,MAAM,EACZ,WAAW,OAAO,KACjB,OAAO,CAAC,OAAO,CAsDjB,CAAA"}
1
+ {"version":3,"file":"load-document-from-source.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/command-palette/helpers/load-document-from-source.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAIpE,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,CAAA;CAC7B,CAAA;AAiCD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,sBAAsB,GACjC,gBAAgB,cAAc,EAC9B,iBAAiB,eAAe,EAChC,MAAM,MAAM,EACZ,WAAW,OAAO,KACjB,OAAO,CAAC,OAAO,CAsDjB,CAAA"}
@@ -1,6 +1,6 @@
1
- import { isPostmanCollection } from "./is-postman-collection.js";
2
1
  import { getOpenApiFromPostman } from "./get-openapi-from-postman.js";
3
2
  import { isObject } from "@scalar/helpers/object/is-object";
3
+ import { isPostmanCollection } from "@scalar/postman-to-openapi";
4
4
  import { parseJson, parseYaml } from "@scalar/json-magic/bundle/plugins/browser";
5
5
  //#region src/v2/features/command-palette/helpers/load-document-from-source.ts
6
6
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"load-document-from-source.js","names":[],"sources":["../../../../../src/v2/features/command-palette/helpers/load-document-from-source.ts"],"sourcesContent":["import { isObject } from '@scalar/helpers/object/is-object'\nimport type { LoaderPlugin } from '@scalar/json-magic/bundle'\nimport { parseJson, parseYaml } from '@scalar/json-magic/bundle/plugins/browser'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\n\nimport { getOpenApiFromPostman } from '@/v2/features/command-palette/helpers/get-openapi-from-postman'\nimport { isPostmanCollection } from '@/v2/features/command-palette/helpers/is-postman-collection'\n\nexport type ImportEventData = {\n source: string\n type: 'url' | 'file' | 'raw'\n}\n\n/**\n * Loader plugin to detect and convert Postman collections into OpenAPI documents\n */\nconst readPostmanCollection = (): LoaderPlugin => {\n return {\n type: 'loader',\n validate: isPostmanCollection,\n exec: (source: string) => {\n try {\n const document = getOpenApiFromPostman(source)\n\n if (document) {\n return Promise.resolve({\n ok: true,\n data: document,\n raw: source,\n })\n }\n\n return Promise.resolve({\n ok: false,\n })\n } catch {\n return Promise.resolve({\n ok: false,\n })\n }\n },\n }\n}\n\n/**\n * Attempts to add a document to the workspace from a given source, which may be a URL or raw content.\n *\n * - If the source is a URL, adds the document by its URL and includes a watch mode flag as metadata.\n * - If the source is a Postman collection, transforms it to OpenAPI and adds it as a document.\n * - For other raw sources (such as pasted JSON or YAML), attempts to normalize and add them as a document.\n *\n * @param workspaceStore The workspace store where the document will be added.\n * @param source The document source (URL, Postman Collection, JSON, or YAML string).\n * @param name The display name for the new document.\n * @param watchMode Whether to enable watch mode (applies only to URL sources).\n * @returns Promise resolving to true if the document was successfully added, or false if the operation failed.\n */\nexport const loadDocumentFromSource = async (\n workspaceStore: WorkspaceStore,\n importEventData: ImportEventData,\n name: string,\n watchMode: boolean,\n): Promise<boolean> => {\n const { source, type } = importEventData\n if (!source) {\n // No source provided, do nothing.\n return false\n }\n\n // If the source is a URL, add it directly with watch mode metadata.\n if (type === 'url') {\n return await workspaceStore.addDocument({\n name,\n url: source,\n meta: {\n 'x-scalar-watch-mode': watchMode,\n },\n })\n }\n\n if (type === 'file') {\n return await workspaceStore.addDocument({\n name,\n path: source,\n })\n }\n\n const loaders = [readPostmanCollection(), parseJson(), parseYaml()]\n const loader = loaders.find((l) => l.validate(source))\n\n // If no loader is found, return false\n if (!loader) {\n return false\n }\n\n // Execute the loader\n const result = await loader.exec(source)\n // If the loader failed, return false\n if (!result.ok) {\n return false\n }\n\n if (!isObject(result.data)) {\n return false\n }\n\n const addDocumentResult = await workspaceStore.addDocument({\n name,\n document: result.data,\n })\n\n if (!addDocumentResult) {\n return false\n }\n\n return true\n}\n"],"mappings":";;;;;;;;AAgBA,IAAM,8BAA4C;AAChD,QAAO;EACL,MAAM;EACN,UAAU;EACV,OAAO,WAAmB;AACxB,OAAI;IACF,MAAM,WAAW,sBAAsB,OAAO;AAE9C,QAAI,SACF,QAAO,QAAQ,QAAQ;KACrB,IAAI;KACJ,MAAM;KACN,KAAK;KACN,CAAC;AAGJ,WAAO,QAAQ,QAAQ,EACrB,IAAI,OACL,CAAC;WACI;AACN,WAAO,QAAQ,QAAQ,EACrB,IAAI,OACL,CAAC;;;EAGP;;;;;;;;;;;;;;;AAgBH,IAAa,yBAAyB,OACpC,gBACA,iBACA,MACA,cACqB;CACrB,MAAM,EAAE,QAAQ,SAAS;AACzB,KAAI,CAAC,OAEH,QAAO;AAIT,KAAI,SAAS,MACX,QAAO,MAAM,eAAe,YAAY;EACtC;EACA,KAAK;EACL,MAAM,EACJ,uBAAuB,WACxB;EACF,CAAC;AAGJ,KAAI,SAAS,OACX,QAAO,MAAM,eAAe,YAAY;EACtC;EACA,MAAM;EACP,CAAC;CAIJ,MAAM,SADU;EAAC,uBAAuB;EAAE,WAAW;EAAE,WAAW;EAAC,CAC5C,MAAM,MAAM,EAAE,SAAS,OAAO,CAAC;AAGtD,KAAI,CAAC,OACH,QAAO;CAIT,MAAM,SAAS,MAAM,OAAO,KAAK,OAAO;AAExC,KAAI,CAAC,OAAO,GACV,QAAO;AAGT,KAAI,CAAC,SAAS,OAAO,KAAK,CACxB,QAAO;AAQT,KAAI,CALsB,MAAM,eAAe,YAAY;EACzD;EACA,UAAU,OAAO;EAClB,CAAC,CAGA,QAAO;AAGT,QAAO"}
1
+ {"version":3,"file":"load-document-from-source.js","names":[],"sources":["../../../../../src/v2/features/command-palette/helpers/load-document-from-source.ts"],"sourcesContent":["import { isObject } from '@scalar/helpers/object/is-object'\nimport type { LoaderPlugin } from '@scalar/json-magic/bundle'\nimport { parseJson, parseYaml } from '@scalar/json-magic/bundle/plugins/browser'\nimport { isPostmanCollection } from '@scalar/postman-to-openapi'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\n\nimport { getOpenApiFromPostman } from '@/v2/features/command-palette/helpers/get-openapi-from-postman'\n\nexport type ImportEventData = {\n source: string\n type: 'url' | 'file' | 'raw'\n}\n\n/**\n * Loader plugin to detect and convert Postman collections into OpenAPI documents\n */\nconst readPostmanCollection = (): LoaderPlugin => {\n return {\n type: 'loader',\n validate: isPostmanCollection,\n exec: (source: string) => {\n try {\n const document = getOpenApiFromPostman(source)\n\n if (document) {\n return Promise.resolve({\n ok: true,\n data: document,\n raw: source,\n })\n }\n\n return Promise.resolve({\n ok: false,\n })\n } catch {\n return Promise.resolve({\n ok: false,\n })\n }\n },\n }\n}\n\n/**\n * Attempts to add a document to the workspace from a given source, which may be a URL or raw content.\n *\n * - If the source is a URL, adds the document by its URL and includes a watch mode flag as metadata.\n * - If the source is a Postman collection, transforms it to OpenAPI and adds it as a document.\n * - For other raw sources (such as pasted JSON or YAML), attempts to normalize and add them as a document.\n *\n * @param workspaceStore The workspace store where the document will be added.\n * @param source The document source (URL, Postman Collection, JSON, or YAML string).\n * @param name The display name for the new document.\n * @param watchMode Whether to enable watch mode (applies only to URL sources).\n * @returns Promise resolving to true if the document was successfully added, or false if the operation failed.\n */\nexport const loadDocumentFromSource = async (\n workspaceStore: WorkspaceStore,\n importEventData: ImportEventData,\n name: string,\n watchMode: boolean,\n): Promise<boolean> => {\n const { source, type } = importEventData\n if (!source) {\n // No source provided, do nothing.\n return false\n }\n\n // If the source is a URL, add it directly with watch mode metadata.\n if (type === 'url') {\n return await workspaceStore.addDocument({\n name,\n url: source,\n meta: {\n 'x-scalar-watch-mode': watchMode,\n },\n })\n }\n\n if (type === 'file') {\n return await workspaceStore.addDocument({\n name,\n path: source,\n })\n }\n\n const loaders = [readPostmanCollection(), parseJson(), parseYaml()]\n const loader = loaders.find((l) => l.validate(source))\n\n // If no loader is found, return false\n if (!loader) {\n return false\n }\n\n // Execute the loader\n const result = await loader.exec(source)\n // If the loader failed, return false\n if (!result.ok) {\n return false\n }\n\n if (!isObject(result.data)) {\n return false\n }\n\n const addDocumentResult = await workspaceStore.addDocument({\n name,\n document: result.data,\n })\n\n if (!addDocumentResult) {\n return false\n }\n\n return true\n}\n"],"mappings":";;;;;;;;AAgBA,IAAM,8BAA4C;AAChD,QAAO;EACL,MAAM;EACN,UAAU;EACV,OAAO,WAAmB;AACxB,OAAI;IACF,MAAM,WAAW,sBAAsB,OAAO;AAE9C,QAAI,SACF,QAAO,QAAQ,QAAQ;KACrB,IAAI;KACJ,MAAM;KACN,KAAK;KACN,CAAC;AAGJ,WAAO,QAAQ,QAAQ,EACrB,IAAI,OACL,CAAC;WACI;AACN,WAAO,QAAQ,QAAQ,EACrB,IAAI,OACL,CAAC;;;EAGP;;;;;;;;;;;;;;;AAgBH,IAAa,yBAAyB,OACpC,gBACA,iBACA,MACA,cACqB;CACrB,MAAM,EAAE,QAAQ,SAAS;AACzB,KAAI,CAAC,OAEH,QAAO;AAIT,KAAI,SAAS,MACX,QAAO,MAAM,eAAe,YAAY;EACtC;EACA,KAAK;EACL,MAAM,EACJ,uBAAuB,WACxB;EACF,CAAC;AAGJ,KAAI,SAAS,OACX,QAAO,MAAM,eAAe,YAAY;EACtC;EACA,MAAM;EACP,CAAC;CAIJ,MAAM,SADU;EAAC,uBAAuB;EAAE,WAAW;EAAE,WAAW;EAAC,CAC5C,MAAM,MAAM,EAAE,SAAS,OAAO,CAAC;AAGtD,KAAI,CAAC,OACH,QAAO;CAIT,MAAM,SAAS,MAAM,OAAO,KAAK,OAAO;AAExC,KAAI,CAAC,OAAO,GACV,QAAO;AAGT,KAAI,CAAC,SAAS,OAAO,KAAK,CACxB,QAAO;AAQT,KAAI,CALsB,MAAM,eAAe,YAAY;EACzD;EACA,UAAU,OAAO;EAClB,CAAC,CAGA,QAAO;AAGT,QAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"create-api-client-modal.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/modal/helpers/create-api-client-modal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAY,MAAM,oBAAoB,CAAA;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,EAAE,KAAK,iBAAiB,EAA2B,MAAM,gCAAgC,CAAA;AAChG,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,gBAAgB,EAA6D,MAAM,KAAK,CAAA;AAEhH,OAAO,EAEL,KAAK,YAAY,EAElB,MAAM,sDAAsD,CAAA;AAC7D,OAAO,KAAK,EAAE,qBAAqB,EAA4B,MAAM,mCAAmC,CAAA;AAIxG,KAAK,2BAA2B,GAAG;IACjC,4CAA4C;IAC5C,EAAE,EAAE,WAAW,GAAG,IAAI,CAAA;IACtB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,kFAAkF;IAClF,QAAQ,CAAC,EAAE,iBAAiB,CAAA;IAC5B,6DAA6D;IAC7D,cAAc,EAAE,cAAc,CAAA;IAC9B,iDAAiD;IACjD,OAAO,CAAC,EAAE,YAAY,EAAE,CAAA;IACxB,wGAAwG;IACxG,OAAO,CAAC,EAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAA;CAClD,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,GAAG,EAAE,GAAG,CAAA;IACR,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,YAAY,KAAK,IAAI,CAAA;IACtC,KAAK,EAAE,CAAC,UAAU,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAA;IAC/C,KAAK,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAA;IACtC,aAAa,EAAE,CAAC,WAAW,EAAE,qBAAqB,EAAE,SAAS,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IAChF,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAAI,wEASlC,2BAA2B,KAAG,cA2HhC,CAAA"}
1
+ {"version":3,"file":"create-api-client-modal.d.ts","sourceRoot":"","sources":["../../../../../src/v2/features/modal/helpers/create-api-client-modal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAY,MAAM,oBAAoB,CAAA;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,EAAE,KAAK,iBAAiB,EAA2B,MAAM,gCAAgC,CAAA;AAChG,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,gBAAgB,EAA6D,MAAM,KAAK,CAAA;AAEhH,OAAO,EAEL,KAAK,YAAY,EAElB,MAAM,sDAAsD,CAAA;AAC7D,OAAO,KAAK,EAAE,qBAAqB,EAA4B,MAAM,mCAAmC,CAAA;AAIxG,KAAK,2BAA2B,GAAG;IACjC,4CAA4C;IAC5C,EAAE,EAAE,WAAW,GAAG,IAAI,CAAA;IACtB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,kFAAkF;IAClF,QAAQ,CAAC,EAAE,iBAAiB,CAAA;IAC5B,6DAA6D;IAC7D,cAAc,EAAE,cAAc,CAAA;IAC9B,iDAAiD;IACjD,OAAO,CAAC,EAAE,YAAY,EAAE,CAAA;IACxB,wGAAwG;IACxG,OAAO,CAAC,EAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAA;CAClD,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,GAAG,EAAE,GAAG,CAAA;IACR,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,YAAY,KAAK,IAAI,CAAA;IACtC,KAAK,EAAE,CAAC,UAAU,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAA;IAC/C,KAAK,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAA;IACtC,aAAa,EAAE,CAAC,WAAW,EAAE,qBAAqB,EAAE,SAAS,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IAChF,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAAI,wEASlC,2BAA2B,KAAG,cAiJhC,CAAA"}
@@ -61,6 +61,17 @@ var createApiClientModal = ({ el, eventBus = createWorkspaceEventBus({ debug: fa
61
61
  const handleModalClose = () => {
62
62
  requestBodyCompositionSelection.value = {};
63
63
  };
64
+ /** Initialize plugins and subscribe to event bus events */
65
+ const pluginUnsubscribes = [];
66
+ for (const plugin of plugins) {
67
+ plugin.lifecycle?.onInit?.();
68
+ if (plugin.on) for (const [event, handler] of Object.entries(plugin.on)) pluginUnsubscribes.push(eventBus.on(event, handler));
69
+ }
70
+ /** Clean up plugin lifecycle and event bus subscriptions when the app is unmounted */
71
+ app.onUnmount(() => {
72
+ for (const unsub of pluginUnsubscribes) unsub();
73
+ for (const plugin of plugins) plugin.lifecycle?.onDestroy?.();
74
+ });
64
75
  watch(() => modalState.open, (open) => open ? null : handleModalClose());
65
76
  watch(() => toValue(optionsRef).proxyUrl, (newProxyUrl) => workspaceStore.update("x-scalar-active-proxy", newProxyUrl), { immediate: true });
66
77
  app.config.idPrefix = "scalar-client";
@@ -1 +1 @@
1
- {"version":3,"file":"create-api-client-modal.js","names":[],"sources":["../../../../../src/v2/features/modal/helpers/create-api-client-modal.ts"],"sourcesContent":["import { type ModalState, useModal } from '@scalar/components'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport { type WorkspaceEventBus, createWorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { type App, type MaybeRefOrGetter, computed, createApp, isRef, reactive, ref, toValue, watch } from 'vue'\n\nimport {\n type DefaultEntities,\n type RoutePayload,\n resolveRouteParameters,\n} from '@/v2/features/modal/helpers/resolve-route-parameters'\nimport type { ApiClientModalOptions, ApiClientModalOptionsRef } from '@/v2/features/modal/helpers/types'\nimport { useModalSidebar } from '@/v2/features/modal/hooks/use-modal-sidebar'\nimport Modal, { type ModalProps } from '@/v2/features/modal/Modal.vue'\n\ntype CreateApiClientModalOptions = {\n /** Element to mount the client modal to. */\n el: HTMLElement | null\n /**\n * Will attempt to mount the references immediately.\n * For SSR this may need to be disabled and handled manually on the client side.\n */\n mountOnInitialize?: boolean\n /** You can pass in an event bus if you have one already, or we will create one */\n eventBus?: WorkspaceEventBus\n /** The workspace store must be initialized and passed in. */\n workspaceStore: WorkspaceStore\n /** Api client plugins to include in the modal */\n plugins?: ClientPlugin[]\n /** Subset of the configuration options for the modal, if you want it to be reactive ensure its a ref */\n options?: MaybeRefOrGetter<ApiClientModalOptions>\n}\n\nexport type ApiClientModal = {\n app: App\n open: (payload?: RoutePayload) => void\n mount: (mountingEl: HTMLElement | null) => void\n route: (payload: RoutePayload) => void\n updateOptions: (nextOptions: ApiClientModalOptions, overwrite?: boolean) => void\n modalState: ModalState\n}\n\n/**\n * Creates the API Client Modal.\n *\n * The modal does not require a router. Instead, navigation is handled by setting\n * active entities directly through the returned `route` function.\n */\nexport const createApiClientModal = ({\n el,\n eventBus = createWorkspaceEventBus({\n debug: import.meta.env.DEV,\n }),\n mountOnInitialize = true,\n plugins = [],\n workspaceStore,\n options = {},\n}: CreateApiClientModalOptions): ApiClientModal => {\n const requestBodyCompositionSelection = ref<Record<string, number>>({})\n\n /** This is to ensure that the options are a ref if they are not already, useful for react */\n const optionsRef = (isRef(options) ? options : ref(toValue(options))) as ApiClientModalOptionsRef\n\n const defaultEntities: DefaultEntities = {\n path: 'default',\n method: 'default',\n example: 'default',\n documentSlug: workspaceStore.workspace['x-scalar-active-document'] || 'default',\n }\n\n const parameters = reactive<DefaultEntities>({ ...defaultEntities })\n\n /** Navigate to the specified path, method, and example. */\n const route = (payload: RoutePayload): void => {\n Object.assign(parameters, defaultEntities, payload)\n }\n\n /** Resolved parameters from the workspace store. */\n const resolvedParameters = computed(() => resolveRouteParameters(workspaceStore, parameters))\n const documentSlug = computed(() => resolvedParameters.value.documentSlug)\n const path = computed(() => resolvedParameters.value.path)\n const method = computed(() => resolvedParameters.value.method)\n const exampleName = computed(() => resolvedParameters.value.example)\n /** The document from the workspace store. */\n const document = computed(() => workspaceStore.workspace.documents[documentSlug.value ?? ''] ?? null)\n\n /** Sidebar state and selection handling. */\n const sidebarState = useModalSidebar({\n workspaceStore,\n documentSlug: documentSlug,\n path: path,\n method: method,\n exampleName: exampleName,\n route,\n })\n\n const modalState = useModal()\n\n const app = createApp(Modal, {\n document,\n eventBus,\n exampleName,\n method,\n modalState,\n path,\n plugins,\n requestBodyCompositionSelection,\n sidebarState,\n workspaceStore,\n options: optionsRef,\n } satisfies ModalProps)\n\n /** Restore the workspace store when the modal is closed. */\n const handleModalClose = () => {\n requestBodyCompositionSelection.value = {}\n }\n\n watch(\n () => modalState.open,\n (open) => (open ? null : handleModalClose()),\n )\n\n // Update the active proxy when the proxyUrl changes\n watch(\n () => toValue(optionsRef).proxyUrl,\n (newProxyUrl) => workspaceStore.update('x-scalar-active-proxy', newProxyUrl),\n { immediate: true },\n )\n\n // Use a unique id prefix to prevent collisions with other Vue apps on the page\n app.config.idPrefix = 'scalar-client'\n\n /** Mount the modal to a given element. */\n const mount = (mountingEl: HTMLElement | null = el): void => {\n if (!mountingEl) {\n console.error(\n '[@scalar/api-client] Could not create the API client Modal.',\n 'Invalid HTML element provided.',\n 'Read more: https://github.com/scalar/scalar/tree/main/packages/api-client',\n )\n return\n }\n app.mount(mountingEl)\n }\n\n if (mountOnInitialize) {\n mount()\n }\n\n return {\n /** The Vue app instance for the modal. Use with caution. */\n app,\n /** Open the modal and optionally navigate to a specific route. */\n open: (payload?: RoutePayload): void => {\n modalState.open = true\n if (payload) {\n route(payload)\n }\n },\n /** Mount the modal to a given element. */\n mount,\n /** Navigate to the specified path, method, and example. */\n route,\n /** Controls the visibility of the modal. */\n modalState,\n /**\n * Merge new options into the current modal options.\n *\n * @param newOptions - The new options to merge into the current modal options.\n * @param overwrite - Whether to overwrite the current modal options with the new options. If false, the new options will be merged with the current options.\n */\n updateOptions: (newOptions: ApiClientModalOptions, overwrite = false): void => {\n optionsRef.value = overwrite\n ? newOptions\n : {\n ...optionsRef.value,\n ...newOptions,\n }\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAgDA,IAAa,wBAAwB,EACnC,IACA,WAAW,wBAAwB,EACjC,OAAA,OACD,CAAC,EACF,oBAAoB,MACpB,UAAU,EAAE,EACZ,gBACA,UAAU,EAAE,OACqC;CACjD,MAAM,kCAAkC,IAA4B,EAAE,CAAC;;CAGvE,MAAM,aAAc,MAAM,QAAQ,GAAG,UAAU,IAAI,QAAQ,QAAQ,CAAC;CAEpE,MAAM,kBAAmC;EACvC,MAAM;EACN,QAAQ;EACR,SAAS;EACT,cAAc,eAAe,UAAU,+BAA+B;EACvE;CAED,MAAM,aAAa,SAA0B,EAAE,GAAG,iBAAiB,CAAC;;CAGpE,MAAM,SAAS,YAAgC;AAC7C,SAAO,OAAO,YAAY,iBAAiB,QAAQ;;;CAIrD,MAAM,qBAAqB,eAAe,uBAAuB,gBAAgB,WAAW,CAAC;CAC7F,MAAM,eAAe,eAAe,mBAAmB,MAAM,aAAa;CAC1E,MAAM,OAAO,eAAe,mBAAmB,MAAM,KAAK;CAC1D,MAAM,SAAS,eAAe,mBAAmB,MAAM,OAAO;CAC9D,MAAM,cAAc,eAAe,mBAAmB,MAAM,QAAQ;;CAEpE,MAAM,WAAW,eAAe,eAAe,UAAU,UAAU,aAAa,SAAS,OAAO,KAAK;;CAGrG,MAAM,eAAe,gBAAgB;EACnC;EACc;EACR;EACE;EACK;EACb;EACD,CAAC;CAEF,MAAM,aAAa,UAAU;CAE7B,MAAM,MAAM,UAAU,eAAO;EAC3B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,SAAS;EACV,CAAsB;;CAGvB,MAAM,yBAAyB;AAC7B,kCAAgC,QAAQ,EAAE;;AAG5C,aACQ,WAAW,OAChB,SAAU,OAAO,OAAO,kBAAkB,CAC5C;AAGD,aACQ,QAAQ,WAAW,CAAC,WACzB,gBAAgB,eAAe,OAAO,yBAAyB,YAAY,EAC5E,EAAE,WAAW,MAAM,CACpB;AAGD,KAAI,OAAO,WAAW;;CAGtB,MAAM,SAAS,aAAiC,OAAa;AAC3D,MAAI,CAAC,YAAY;AACf,WAAQ,MACN,+DACA,kCACA,4EACD;AACD;;AAEF,MAAI,MAAM,WAAW;;AAGvB,KAAI,kBACF,QAAO;AAGT,QAAO;EAEL;EAEA,OAAO,YAAiC;AACtC,cAAW,OAAO;AAClB,OAAI,QACF,OAAM,QAAQ;;EAIlB;EAEA;EAEA;EAOA,gBAAgB,YAAmC,YAAY,UAAgB;AAC7E,cAAW,QAAQ,YACf,aACA;IACE,GAAG,WAAW;IACd,GAAG;IACJ;;EAER"}
1
+ {"version":3,"file":"create-api-client-modal.js","names":[],"sources":["../../../../../src/v2/features/modal/helpers/create-api-client-modal.ts"],"sourcesContent":["import { type ModalState, useModal } from '@scalar/components'\nimport type { ClientPlugin } from '@scalar/oas-utils/helpers'\nimport type { WorkspaceStore } from '@scalar/workspace-store/client'\nimport { type WorkspaceEventBus, createWorkspaceEventBus } from '@scalar/workspace-store/events'\nimport { type App, type MaybeRefOrGetter, computed, createApp, isRef, reactive, ref, toValue, watch } from 'vue'\n\nimport {\n type DefaultEntities,\n type RoutePayload,\n resolveRouteParameters,\n} from '@/v2/features/modal/helpers/resolve-route-parameters'\nimport type { ApiClientModalOptions, ApiClientModalOptionsRef } from '@/v2/features/modal/helpers/types'\nimport { useModalSidebar } from '@/v2/features/modal/hooks/use-modal-sidebar'\nimport Modal, { type ModalProps } from '@/v2/features/modal/Modal.vue'\n\ntype CreateApiClientModalOptions = {\n /** Element to mount the client modal to. */\n el: HTMLElement | null\n /**\n * Will attempt to mount the references immediately.\n * For SSR this may need to be disabled and handled manually on the client side.\n */\n mountOnInitialize?: boolean\n /** You can pass in an event bus if you have one already, or we will create one */\n eventBus?: WorkspaceEventBus\n /** The workspace store must be initialized and passed in. */\n workspaceStore: WorkspaceStore\n /** Api client plugins to include in the modal */\n plugins?: ClientPlugin[]\n /** Subset of the configuration options for the modal, if you want it to be reactive ensure its a ref */\n options?: MaybeRefOrGetter<ApiClientModalOptions>\n}\n\nexport type ApiClientModal = {\n app: App\n open: (payload?: RoutePayload) => void\n mount: (mountingEl: HTMLElement | null) => void\n route: (payload: RoutePayload) => void\n updateOptions: (nextOptions: ApiClientModalOptions, overwrite?: boolean) => void\n modalState: ModalState\n}\n\n/**\n * Creates the API Client Modal.\n *\n * The modal does not require a router. Instead, navigation is handled by setting\n * active entities directly through the returned `route` function.\n */\nexport const createApiClientModal = ({\n el,\n eventBus = createWorkspaceEventBus({\n debug: import.meta.env.DEV,\n }),\n mountOnInitialize = true,\n plugins = [],\n workspaceStore,\n options = {},\n}: CreateApiClientModalOptions): ApiClientModal => {\n const requestBodyCompositionSelection = ref<Record<string, number>>({})\n\n /** This is to ensure that the options are a ref if they are not already, useful for react */\n const optionsRef = (isRef(options) ? options : ref(toValue(options))) as ApiClientModalOptionsRef\n\n const defaultEntities: DefaultEntities = {\n path: 'default',\n method: 'default',\n example: 'default',\n documentSlug: workspaceStore.workspace['x-scalar-active-document'] || 'default',\n }\n\n const parameters = reactive<DefaultEntities>({ ...defaultEntities })\n\n /** Navigate to the specified path, method, and example. */\n const route = (payload: RoutePayload): void => {\n Object.assign(parameters, defaultEntities, payload)\n }\n\n /** Resolved parameters from the workspace store. */\n const resolvedParameters = computed(() => resolveRouteParameters(workspaceStore, parameters))\n const documentSlug = computed(() => resolvedParameters.value.documentSlug)\n const path = computed(() => resolvedParameters.value.path)\n const method = computed(() => resolvedParameters.value.method)\n const exampleName = computed(() => resolvedParameters.value.example)\n /** The document from the workspace store. */\n const document = computed(() => workspaceStore.workspace.documents[documentSlug.value ?? ''] ?? null)\n\n /** Sidebar state and selection handling. */\n const sidebarState = useModalSidebar({\n workspaceStore,\n documentSlug: documentSlug,\n path: path,\n method: method,\n exampleName: exampleName,\n route,\n })\n\n const modalState = useModal()\n\n const app = createApp(Modal, {\n document,\n eventBus,\n exampleName,\n method,\n modalState,\n path,\n plugins,\n requestBodyCompositionSelection,\n sidebarState,\n workspaceStore,\n options: optionsRef,\n } satisfies ModalProps)\n\n /** Restore the workspace store when the modal is closed. */\n const handleModalClose = () => {\n requestBodyCompositionSelection.value = {}\n }\n\n /** Initialize plugins and subscribe to event bus events */\n const pluginUnsubscribes: (() => void)[] = []\n for (const plugin of plugins) {\n plugin.lifecycle?.onInit?.()\n\n if (plugin.on) {\n for (const [event, handler] of Object.entries(plugin.on)) {\n pluginUnsubscribes.push(eventBus.on(event as any, handler as any))\n }\n }\n }\n\n /** Clean up plugin lifecycle and event bus subscriptions when the app is unmounted */\n app.onUnmount(() => {\n for (const unsub of pluginUnsubscribes) {\n unsub()\n }\n for (const plugin of plugins) {\n plugin.lifecycle?.onDestroy?.()\n }\n })\n\n watch(\n () => modalState.open,\n (open) => (open ? null : handleModalClose()),\n )\n\n // Update the active proxy when the proxyUrl changes\n watch(\n () => toValue(optionsRef).proxyUrl,\n (newProxyUrl) => workspaceStore.update('x-scalar-active-proxy', newProxyUrl),\n { immediate: true },\n )\n\n // Use a unique id prefix to prevent collisions with other Vue apps on the page\n app.config.idPrefix = 'scalar-client'\n\n /** Mount the modal to a given element. */\n const mount = (mountingEl: HTMLElement | null = el): void => {\n if (!mountingEl) {\n console.error(\n '[@scalar/api-client] Could not create the API client Modal.',\n 'Invalid HTML element provided.',\n 'Read more: https://github.com/scalar/scalar/tree/main/packages/api-client',\n )\n return\n }\n app.mount(mountingEl)\n }\n\n if (mountOnInitialize) {\n mount()\n }\n\n return {\n /** The Vue app instance for the modal. Use with caution. */\n app,\n /** Open the modal and optionally navigate to a specific route. */\n open: (payload?: RoutePayload): void => {\n modalState.open = true\n if (payload) {\n route(payload)\n }\n },\n /** Mount the modal to a given element. */\n mount,\n /** Navigate to the specified path, method, and example. */\n route,\n /** Controls the visibility of the modal. */\n modalState,\n /**\n * Merge new options into the current modal options.\n *\n * @param newOptions - The new options to merge into the current modal options.\n * @param overwrite - Whether to overwrite the current modal options with the new options. If false, the new options will be merged with the current options.\n */\n updateOptions: (newOptions: ApiClientModalOptions, overwrite = false): void => {\n optionsRef.value = overwrite\n ? newOptions\n : {\n ...optionsRef.value,\n ...newOptions,\n }\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAgDA,IAAa,wBAAwB,EACnC,IACA,WAAW,wBAAwB,EACjC,OAAA,OACD,CAAC,EACF,oBAAoB,MACpB,UAAU,EAAE,EACZ,gBACA,UAAU,EAAE,OACqC;CACjD,MAAM,kCAAkC,IAA4B,EAAE,CAAC;;CAGvE,MAAM,aAAc,MAAM,QAAQ,GAAG,UAAU,IAAI,QAAQ,QAAQ,CAAC;CAEpE,MAAM,kBAAmC;EACvC,MAAM;EACN,QAAQ;EACR,SAAS;EACT,cAAc,eAAe,UAAU,+BAA+B;EACvE;CAED,MAAM,aAAa,SAA0B,EAAE,GAAG,iBAAiB,CAAC;;CAGpE,MAAM,SAAS,YAAgC;AAC7C,SAAO,OAAO,YAAY,iBAAiB,QAAQ;;;CAIrD,MAAM,qBAAqB,eAAe,uBAAuB,gBAAgB,WAAW,CAAC;CAC7F,MAAM,eAAe,eAAe,mBAAmB,MAAM,aAAa;CAC1E,MAAM,OAAO,eAAe,mBAAmB,MAAM,KAAK;CAC1D,MAAM,SAAS,eAAe,mBAAmB,MAAM,OAAO;CAC9D,MAAM,cAAc,eAAe,mBAAmB,MAAM,QAAQ;;CAEpE,MAAM,WAAW,eAAe,eAAe,UAAU,UAAU,aAAa,SAAS,OAAO,KAAK;;CAGrG,MAAM,eAAe,gBAAgB;EACnC;EACc;EACR;EACE;EACK;EACb;EACD,CAAC;CAEF,MAAM,aAAa,UAAU;CAE7B,MAAM,MAAM,UAAU,eAAO;EAC3B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,SAAS;EACV,CAAsB;;CAGvB,MAAM,yBAAyB;AAC7B,kCAAgC,QAAQ,EAAE;;;CAI5C,MAAM,qBAAqC,EAAE;AAC7C,MAAK,MAAM,UAAU,SAAS;AAC5B,SAAO,WAAW,UAAU;AAE5B,MAAI,OAAO,GACT,MAAK,MAAM,CAAC,OAAO,YAAY,OAAO,QAAQ,OAAO,GAAG,CACtD,oBAAmB,KAAK,SAAS,GAAG,OAAc,QAAe,CAAC;;;AAMxE,KAAI,gBAAgB;AAClB,OAAK,MAAM,SAAS,mBAClB,QAAO;AAET,OAAK,MAAM,UAAU,QACnB,QAAO,WAAW,aAAa;GAEjC;AAEF,aACQ,WAAW,OAChB,SAAU,OAAO,OAAO,kBAAkB,CAC5C;AAGD,aACQ,QAAQ,WAAW,CAAC,WACzB,gBAAgB,eAAe,OAAO,yBAAyB,YAAY,EAC5E,EAAE,WAAW,MAAM,CACpB;AAGD,KAAI,OAAO,WAAW;;CAGtB,MAAM,SAAS,aAAiC,OAAa;AAC3D,MAAI,CAAC,YAAY;AACf,WAAQ,MACN,+DACA,kCACA,4EACD;AACD;;AAEF,MAAI,MAAM,WAAW;;AAGvB,KAAI,kBACF,QAAO;AAGT,QAAO;EAEL;EAEA,OAAO,YAAiC;AACtC,cAAW,OAAO;AAClB,OAAI,QACF,OAAM,QAAQ;;EAIlB;EAEA;EAEA;EAOA,gBAAgB,YAAmC,YAAY,UAAgB;AAC7E,cAAW,QAAQ,YACf,aACA;IACE,GAAG,WAAW;IACd,GAAG;IACJ;;EAER"}