diff --git a/README.md b/README.md
index 642fcd31a..22ac9347f 100644
--- a/README.md
+++ b/README.md
@@ -155,25 +155,25 @@ The `docusaurus-plugin-openapi-docs` plugin can be configured with the following
`config` can be configured with the following options:
-| Name | Type | Default | Description |
-| -------------------- | --------- | ------- | --------------------------------------------------------------------------------------------------------------------------- |
-| `specPath` | `string` | `null` | Designated URL or path to the source of an OpenAPI specification file or directory of multiple OpenAPI specification files. |
-| `outputDir` | `string` | `null` | Desired output path for generated MDX and sidebar files. |
-| `proxy` | `string` | `null` | _Optional:_ Proxy URL to prepend to base URL when performing API requests from browser. |
-| `template` | `string` | `null` | _Optional:_ Customize MDX content with a desired template. |
-| `infoTemplate` | `string` | `null` | _Optional:_ Customize MDX content for **info** pages only. |
-| `tagTemplate` | `string` | `null` | _Optional:_ Customize MDX content for **tag** pages only. |
-| `schemaTemplate` | `string` | `null` | _Optional:_ Customize MDX content for **schema** pages only. |
-| `downloadUrl` | `string` | `null` | _Optional:_ Designated URL for downloading OpenAPI specification. (requires `info` section/doc) |
-| `hideSendButton` | `boolean` | `null` | _Optional:_ If set to `true`, hides the “Send API Request” button in the API demo panel. |
-| `showExtensions` | `boolean` | `null` | _Optional:_ If set to `true`, renders operation‑level vendor‑extensions in descriptions. |
-| `sidebarOptions` | `object` | `null` | _Optional:_ Set of options for sidebar configuration. See below for a list of supported options. |
-| `version` | `string` | `null` | _Optional:_ Version assigned to a single or micro‑spec API specified in `specPath`. |
-| `label` | `string` | `null` | _Optional:_ Version label used when generating the version‑selector dropdown menu. |
-| `baseUrl` | `string` | `null` | _Optional:_ Base URL for versioned docs in the version‑selector dropdown. |
-| `versions` | `object` | `null` | _Optional:_ Options for versioning configuration. See below for a list of supported options. |
-| `markdownGenerators` | `object` | `null` | _Optional:_ Customize MDX content via generator functions. See below for a list of supported options. |
-| `showSchemas` | `boolean` | `null` | _Optional:_ If set to `true`, generates standalone schema pages and adds them to the sidebar. |
+| Name | Type | Default | Description |
+| -------------------- | --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
+| `specPath` | `string` | `null` | Designated URL or path to the source of an OpenAPI specification file or directory of multiple OpenAPI specification files. |
+| `outputDir` | `string` | `null` | Desired output path for generated MDX and sidebar files. |
+| `proxy` | `string` | `null` | _Optional:_ Proxy URL to prepend to base URL when performing API requests from browser. Overrides site-wide `themeConfig.api.proxy` if set. |
+| `template` | `string` | `null` | _Optional:_ Customize MDX content with a desired template. |
+| `infoTemplate` | `string` | `null` | _Optional:_ Customize MDX content for **info** pages only. |
+| `tagTemplate` | `string` | `null` | _Optional:_ Customize MDX content for **tag** pages only. |
+| `schemaTemplate` | `string` | `null` | _Optional:_ Customize MDX content for **schema** pages only. |
+| `downloadUrl` | `string` | `null` | _Optional:_ Designated URL for downloading OpenAPI specification. (requires `info` section/doc) |
+| `hideSendButton` | `boolean` | `null` | _Optional:_ If set to `true`, hides the “Send API Request” button in the API demo panel. |
+| `showExtensions` | `boolean` | `null` | _Optional:_ If set to `true`, renders operation‑level vendor‑extensions in descriptions. |
+| `sidebarOptions` | `object` | `null` | _Optional:_ Set of options for sidebar configuration. See below for a list of supported options. |
+| `version` | `string` | `null` | _Optional:_ Version assigned to a single or micro‑spec API specified in `specPath`. |
+| `label` | `string` | `null` | _Optional:_ Version label used when generating the version‑selector dropdown menu. |
+| `baseUrl` | `string` | `null` | _Optional:_ Base URL for versioned docs in the version‑selector dropdown. |
+| `versions` | `object` | `null` | _Optional:_ Options for versioning configuration. See below for a list of supported options. |
+| `markdownGenerators` | `object` | `null` | _Optional:_ Customize MDX content via generator functions. See below for a list of supported options. |
+| `showSchemas` | `boolean` | `null` | _Optional:_ If set to `true`, generates standalone schema pages and adds them to the sidebar. |
### sidebarOptions
@@ -221,6 +221,31 @@ The `docusaurus-plugin-openapi-docs` plugin can be configured with the following
| --------------- | ---------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `createDocItem` | `function` | `null` | Optional: Returns a `SidebarItemDoc` object containing metadata for a sidebar item.
**Function type:** `(item: ApiPageMetadata \| SchemaPageMetadata, context: { sidebarOptions: SidebarOptions; basePath: string }) => SidebarItemDoc` |
+## Theme Configuration Options
+
+The `docusaurus-theme-openapi-docs` theme can be configured with the following options in `themeConfig.api`:
+
+| Name | Type | Default | Description |
+| ----------------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------- |
+| `proxy` | `string` | `null` | _Optional:_ Site-wide proxy URL to prepend to base URL when performing API requests. Can be overridden per-spec via plugin config. |
+| `authPersistance` | `string` | `null` | _Optional:_ Determines how auth credentials are persisted. Options: `"localStorage"`, `"sessionStorage"`, or `false` to disable. |
+| `requestTimeout` | `number` | `30000` | _Optional:_ Request timeout in milliseconds for API requests made from the browser. Defaults to 30 seconds. |
+
+Example:
+
+```typescript
+// docusaurus.config.ts
+{
+ themeConfig: {
+ api: {
+ proxy: "https://cors.pan.dev", // Site-wide proxy (can be overridden per-spec in plugin config)
+ authPersistance: "localStorage",
+ requestTimeout: 60000, // 60 seconds
+ },
+ },
+}
+```
+
## CLI Usage
```bash
diff --git a/demo/docs/intro.mdx b/demo/docs/intro.mdx
index d4779c3f7..71585306e 100644
--- a/demo/docs/intro.mdx
+++ b/demo/docs/intro.mdx
@@ -206,7 +206,7 @@ The `docusaurus-plugin-openapi-docs` plugin can be configured with the following
| -------------------- | --------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `specPath` | `string` | `null` | Designated URL or path to the source of an OpenAPI specification file or directory of multiple OpenAPI specification files. |
| `outputDir` | `string` | `null` | Desired output path for generated MDX and sidebar files. |
-| `proxy` | `string` | `null` | _Optional:_ Proxy URL to prepend to base URL when performing API requests from browser. |
+| `proxy` | `string` | `null` | _Optional:_ Proxy URL to prepend to base URL when performing API requests from browser. Overrides site-wide `themeConfig.api.proxy` if set. |
| `template` | `string` | `null` | _Optional:_ Customize MDX content with a desired template. |
| `infoTemplate` | `string` | `null` | _Optional:_ Customize MDX content for **info** pages only. |
| `tagTemplate` | `string` | `null` | _Optional:_ Customize MDX content for **tag** pages only. |
@@ -285,6 +285,31 @@ petstore31: {
| --------------- | ---------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `createDocItem` | `function` | `null` | Optional: Returns a `SidebarItemDoc` object containing metadata for a sidebar item.
**Function type:** `(item: ApiPageMetadata \| SchemaPageMetadata, context: { sidebarOptions: SidebarOptions; basePath: string }) => SidebarItemDoc` |
+## Theme Configuration Options
+
+The `docusaurus-theme-openapi-docs` theme can be configured with the following options in `themeConfig.api`:
+
+| Name | Type | Default | Description |
+| ---------------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `proxy` | `string` | `null` | _Optional:_ Site-wide proxy URL to prepend to base URL when performing API requests. Can be overridden per-spec via plugin config. |
+| `authPersistance`| `string` | `null` | _Optional:_ Determines how auth credentials are persisted. Options: `"localStorage"`, `"sessionStorage"`, or `false` to disable. |
+| `requestTimeout` | `number` | `30000` | _Optional:_ Request timeout in milliseconds for API requests made from the browser. Defaults to 30 seconds. |
+
+Example:
+
+```typescript
+// docusaurus.config.ts
+{
+ themeConfig: {
+ api: {
+ proxy: "https://cors.pan.dev", // Site-wide proxy (can be overridden per-spec in plugin config)
+ authPersistance: "localStorage",
+ requestTimeout: 60000, // 60 seconds
+ },
+ },
+}
+```
+
## CLI Usage
After you've installed and configured the plugin and theme, the CLI can be used to `generate` and `clean` API docs.
diff --git a/packages/docusaurus-plugin-openapi-docs/README.md b/packages/docusaurus-plugin-openapi-docs/README.md
index c09d4eb19..cde77d0f2 100644
--- a/packages/docusaurus-plugin-openapi-docs/README.md
+++ b/packages/docusaurus-plugin-openapi-docs/README.md
@@ -156,26 +156,26 @@ The `docusaurus-plugin-openapi-docs` plugin can be configured with the following
`config` can be configured with the following options:
-| Name | Type | Default | Description |
-| -------------------- | --------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------- |
-| `specPath` | `string` | `null` | Designated URL or path to the source of an OpenAPI specification file or directory of multiple OpenAPI specification files. |
-| `outputDir` | `string` | `null` | Desired output path for generated MDX and sidebar files. |
-| `proxy` | `string` | `null` | _Optional:_ Proxy URL to prepend to base URL when performing API requests from browser. |
-| `template` | `string` | `null` | _Optional:_ Customize MDX content with a desired template. |
-| `infoTemplate` | `string` | `null` | _Optional:_ Customize MDX content for **info** pages only. |
-| `tagTemplate` | `string` | `null` | _Optional:_ Customize MDX content for **tag** pages only. |
-| `schemaTemplate` | `string` | `null` | _Optional:_ Customize MDX content for **schema** pages only. |
-| `downloadUrl` | `string` | `null` | _Optional:_ Designated URL for downloading OpenAPI specification. (requires `info` section/doc) |
-| `hideSendButton` | `boolean` | `null` | _Optional:_ If set to `true`, hides the “Send API Request” button in the API demo panel. |
-| `showExtensions` | `boolean` | `null` | _Optional:_ If set to `true`, renders operation‑level vendor‑extensions in descriptions. |
-| `maskCredentials` | `boolean` | `true` | _Optional:_ If set to `false`, disables credential masking in generated code snippets. By default, credentials are masked for security. |
-| `sidebarOptions` | `object` | `null` | _Optional:_ Set of options for sidebar configuration. See below for a list of supported options. |
-| `version` | `string` | `null` | _Optional:_ Version assigned to a single or micro‑spec API specified in `specPath`. |
-| `label` | `string` | `null` | _Optional:_ Version label used when generating the version‑selector dropdown menu. |
-| `baseUrl` | `string` | `null` | _Optional:_ Base URL for versioned docs in the version‑selector dropdown. |
-| `versions` | `object` | `null` | _Optional:_ Options for versioning configuration. See below for a list of supported options. |
-| `markdownGenerators` | `object` | `null` | _Optional:_ Customize MDX content via generator functions. See below for a list of supported options. |
-| `showSchemas` | `boolean` | `null` | _Optional:_ If set to `true`, generates standalone schema pages and adds them to the sidebar. |
+| Name | Type | Default | Description |
+| -------------------- | --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
+| `specPath` | `string` | `null` | Designated URL or path to the source of an OpenAPI specification file or directory of multiple OpenAPI specification files. |
+| `outputDir` | `string` | `null` | Desired output path for generated MDX and sidebar files. |
+| `proxy` | `string` | `null` | _Optional:_ Proxy URL to prepend to base URL when performing API requests from browser. Overrides site-wide `themeConfig.api.proxy` if set. |
+| `template` | `string` | `null` | _Optional:_ Customize MDX content with a desired template. |
+| `infoTemplate` | `string` | `null` | _Optional:_ Customize MDX content for **info** pages only. |
+| `tagTemplate` | `string` | `null` | _Optional:_ Customize MDX content for **tag** pages only. |
+| `schemaTemplate` | `string` | `null` | _Optional:_ Customize MDX content for **schema** pages only. |
+| `downloadUrl` | `string` | `null` | _Optional:_ Designated URL for downloading OpenAPI specification. (requires `info` section/doc) |
+| `hideSendButton` | `boolean` | `null` | _Optional:_ If set to `true`, hides the “Send API Request” button in the API demo panel. |
+| `showExtensions` | `boolean` | `null` | _Optional:_ If set to `true`, renders operation‑level vendor‑extensions in descriptions. |
+| `maskCredentials` | `boolean` | `true` | _Optional:_ If set to `false`, disables credential masking in generated code snippets. By default, credentials are masked for security. |
+| `sidebarOptions` | `object` | `null` | _Optional:_ Set of options for sidebar configuration. See below for a list of supported options. |
+| `version` | `string` | `null` | _Optional:_ Version assigned to a single or micro‑spec API specified in `specPath`. |
+| `label` | `string` | `null` | _Optional:_ Version label used when generating the version‑selector dropdown menu. |
+| `baseUrl` | `string` | `null` | _Optional:_ Base URL for versioned docs in the version‑selector dropdown. |
+| `versions` | `object` | `null` | _Optional:_ Options for versioning configuration. See below for a list of supported options. |
+| `markdownGenerators` | `object` | `null` | _Optional:_ Customize MDX content via generator functions. See below for a list of supported options. |
+| `showSchemas` | `boolean` | `null` | _Optional:_ If set to `true`, generates standalone schema pages and adds them to the sidebar. |
### sidebarOptions
@@ -224,6 +224,31 @@ The `docusaurus-plugin-openapi-docs` plugin can be configured with the following
| --------------- | ---------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `createDocItem` | `function` | `null` | Optional: Returns a `SidebarItemDoc` object containing metadata for a sidebar item.
**Function type:** `(item: ApiPageMetadata \| SchemaPageMetadata, context: { sidebarOptions: SidebarOptions; basePath: string }) => SidebarItemDoc` |
+## Theme Configuration Options
+
+The `docusaurus-theme-openapi-docs` theme can be configured with the following options in `themeConfig.api`:
+
+| Name | Type | Default | Description |
+| ----------------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------- |
+| `proxy` | `string` | `null` | _Optional:_ Site-wide proxy URL to prepend to base URL when performing API requests. Can be overridden per-spec via plugin config. |
+| `authPersistance` | `string` | `null` | _Optional:_ Determines how auth credentials are persisted. Options: `"localStorage"`, `"sessionStorage"`, or `false` to disable. |
+| `requestTimeout` | `number` | `30000` | _Optional:_ Request timeout in milliseconds for API requests made from the browser. Defaults to 30 seconds. |
+
+Example:
+
+```typescript
+// docusaurus.config.ts
+{
+ themeConfig: {
+ api: {
+ proxy: "https://cors.pan.dev", // Site-wide proxy (can be overridden per-spec in plugin config)
+ authPersistance: "localStorage",
+ requestTimeout: 60000, // 60 seconds
+ },
+ },
+}
+```
+
## Supported Vendor Extensions
The plugin extracts a number of vendor extensions from the OpenAPI spec to enrich the generated docs. The theme renders some of these values as part of the UI.
diff --git a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/Request/index.tsx b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/Request/index.tsx
index a1b3bcf93..e3cf6d617 100644
--- a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/Request/index.tsx
+++ b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/Request/index.tsx
@@ -10,6 +10,8 @@ import React, { useState } from "react";
import { useDoc } from "@docusaurus/plugin-content-docs/client";
import { translate } from "@docusaurus/Translate";
+import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
+import type { ThemeConfig } from "docusaurus-theme-openapi-docs/src/types";
import Accept from "@theme/ApiExplorer/Accept";
import Authorization from "@theme/ApiExplorer/Authorization";
import Body from "@theme/ApiExplorer/Body";
@@ -31,12 +33,18 @@ import { ApiItem } from "docusaurus-plugin-openapi-docs/src/types";
import * as sdk from "postman-collection";
import { FormProvider, useForm } from "react-hook-form";
-import makeRequest from "./makeRequest";
+import makeRequest, { RequestError, RequestErrorType } from "./makeRequest";
function Request({ item }: { item: ApiItem }) {
const postman = new sdk.Request(item.postman);
const metadata = useDoc();
- const { proxy, hide_send_button: hideSendButton } = metadata.frontMatter;
+ const { proxy: frontMatterProxy, hide_send_button: hideSendButton } =
+ metadata.frontMatter;
+ const { siteConfig } = useDocusaurusContext();
+ const themeConfig = siteConfig.themeConfig as ThemeConfig;
+ const requestTimeout = themeConfig.api?.requestTimeout;
+ // Frontmatter proxy (per-spec) takes precedence over theme config proxy (site-wide)
+ const proxy = frontMatterProxy ?? themeConfig.api?.proxy;
const pathParams = useTypedSelector((state: any) => state.params.path);
const queryParams = useTypedSelector((state: any) => state.params.query);
@@ -118,6 +126,36 @@ function Request({ item }: { item: ApiItem }) {
res.headers && dispatch(setHeaders(Object.fromEntries(res.headers)));
};
+ const getErrorMessage = (errorType: RequestErrorType): string => {
+ switch (errorType) {
+ case "timeout":
+ return translate({
+ id: OPENAPI_REQUEST.ERROR_TIMEOUT,
+ message:
+ "The request timed out waiting for the server to respond. Please try again. If the issue persists, try using a different client (e.g., curl) with a longer timeout.",
+ });
+ case "network":
+ return translate({
+ id: OPENAPI_REQUEST.ERROR_NETWORK,
+ message:
+ "Unable to reach the server. Please check your network connection and verify the server URL is correct. If the server is running, this may be a CORS issue.",
+ });
+ case "cors":
+ return translate({
+ id: OPENAPI_REQUEST.ERROR_CORS,
+ message:
+ "The request was blocked, possibly due to CORS restrictions. Ensure the server allows requests from this origin, or try using a proxy.",
+ });
+ case "unknown":
+ default:
+ return translate({
+ id: OPENAPI_REQUEST.ERROR_UNKNOWN,
+ message:
+ "An unexpected error occurred while making the request. Please try again.",
+ });
+ }
+ };
+
const onSubmit = async (data) => {
dispatch(
setResponse(
@@ -129,7 +167,12 @@ function Request({ item }: { item: ApiItem }) {
);
try {
await delay(1200);
- const res = await makeRequest(postmanRequest, proxy, body);
+ const res = await makeRequest(
+ postmanRequest,
+ proxy,
+ body,
+ requestTimeout
+ );
if (res.headers.get("content-type")?.includes("text/event-stream")) {
await handleEventStream(res);
} else {
@@ -137,14 +180,18 @@ function Request({ item }: { item: ApiItem }) {
}
} catch (e) {
console.log(e);
- dispatch(
- setResponse(
- translate({
- id: OPENAPI_REQUEST.CONNECTION_FAILED,
- message: "Connection failed",
- })
- )
- );
+
+ let errorMessage: string;
+ if (e instanceof RequestError) {
+ errorMessage = getErrorMessage(e.type);
+ } else {
+ errorMessage = translate({
+ id: OPENAPI_REQUEST.CONNECTION_FAILED,
+ message: "Connection failed",
+ });
+ }
+
+ dispatch(setResponse(errorMessage));
dispatch(clearCode());
dispatch(clearHeaders());
}
diff --git a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/Request/makeRequest.ts b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/Request/makeRequest.ts
index 6c335709b..914311703 100644
--- a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/Request/makeRequest.ts
+++ b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/Request/makeRequest.ts
@@ -8,17 +8,83 @@
import { Body } from "@theme/ApiExplorer/Body/slice";
import * as sdk from "postman-collection";
+// Custom error types for better error handling
+export type RequestErrorType =
+ | "timeout"
+ | "network"
+ | "cors"
+ | "abort"
+ | "unknown";
+
+export class RequestError extends Error {
+ type: RequestErrorType;
+ originalError?: Error;
+
+ constructor(type: RequestErrorType, message: string, originalError?: Error) {
+ super(message);
+ this.name = "RequestError";
+ this.type = type;
+ this.originalError = originalError;
+ }
+}
+
+const DEFAULT_REQUEST_TIMEOUT = 30000; // 30 seconds
+
function fetchWithtimeout(
url: string,
options: RequestInit,
- timeout = 5000
-): any {
- return Promise.race([
- fetch(url, options),
- new Promise((_, reject) =>
- setTimeout(() => reject(new Error("Request timed out")), timeout)
- ),
- ]);
+ timeout = DEFAULT_REQUEST_TIMEOUT
+): Promise {
+ const controller = new AbortController();
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
+
+ return fetch(url, {
+ ...options,
+ signal: controller.signal,
+ })
+ .then((response) => {
+ clearTimeout(timeoutId);
+ return response;
+ })
+ .catch((error) => {
+ clearTimeout(timeoutId);
+
+ // Check if it was an abort due to timeout
+ if (error.name === "AbortError") {
+ throw new RequestError(
+ "timeout",
+ "The request timed out waiting for the server to respond. Please try again. If the issue persists, try using a different client (e.g., curl) with a longer timeout.",
+ error
+ );
+ }
+
+ // Check for network errors (offline, DNS failure, etc.)
+ if (error instanceof TypeError && error.message === "Failed to fetch") {
+ // This could be CORS, network failure, or the server being unreachable
+ throw new RequestError(
+ "network",
+ "Unable to reach the server. Please check your network connection and verify the server URL is correct. If the server is running, this may be a CORS issue.",
+ error
+ );
+ }
+
+ // Handle other TypeErrors that might indicate CORS issues
+ if (error instanceof TypeError) {
+ throw new RequestError(
+ "cors",
+ "The request was blocked, possibly due to CORS restrictions. Ensure the server allows requests from this origin, or try using a proxy.",
+ error
+ );
+ }
+
+ // Generic error fallback
+ throw new RequestError(
+ "unknown",
+ error.message ||
+ "An unexpected error occurred while making the request.",
+ error
+ );
+ });
}
async function loadImage(content: Blob): Promise {
@@ -47,7 +113,8 @@ async function loadImage(content: Blob): Promise {
async function makeRequest(
request: sdk.Request,
proxy: string | undefined,
- _body: Body
+ _body: Body,
+ timeout: number = DEFAULT_REQUEST_TIMEOUT
) {
const headers = request.toJSON().header;
@@ -194,7 +261,8 @@ async function makeRequest(
finalUrl = normalizedProxy + request.url.toString();
}
- return fetchWithtimeout(finalUrl, requestOptions).then((response: any) => {
+ try {
+ const response = await fetchWithtimeout(finalUrl, requestOptions, timeout);
const contentType = response.headers.get("content-type");
let fileExtension = "";
@@ -224,32 +292,45 @@ async function makeRequest(
}
if (fileExtension) {
- return response.blob().then((blob: any) => {
- const url = window.URL.createObjectURL(blob);
+ const blob = await response.blob();
+ const url = window.URL.createObjectURL(blob);
- const link = document.createElement("a");
- link.href = url;
- // Now the file name includes the extension
- link.setAttribute("download", `file${fileExtension}`);
+ const link = document.createElement("a");
+ link.href = url;
+ // Now the file name includes the extension
+ link.setAttribute("download", `file${fileExtension}`);
- // These two lines are necessary to make the link click in Firefox
- link.style.display = "none";
- document.body.appendChild(link);
+ // These two lines are necessary to make the link click in Firefox
+ link.style.display = "none";
+ document.body.appendChild(link);
- link.click();
+ link.click();
- // After link is clicked, it's safe to remove it.
- setTimeout(() => document.body.removeChild(link), 0);
+ // After link is clicked, it's safe to remove it.
+ setTimeout(() => document.body.removeChild(link), 0);
- return response;
- });
+ return response;
} else {
return response;
}
}
return response;
- });
+ } catch (error) {
+ // Re-throw RequestError instances as-is
+ if (error instanceof RequestError) {
+ throw error;
+ }
+
+ // Wrap unexpected errors
+ throw new RequestError(
+ "unknown",
+ error instanceof Error
+ ? error.message
+ : "An unexpected error occurred while processing the response.",
+ error instanceof Error ? error : undefined
+ );
+ }
}
export default makeRequest;
diff --git a/packages/docusaurus-theme-openapi-docs/src/theme/translationIds.ts b/packages/docusaurus-theme-openapi-docs/src/theme/translationIds.ts
index 46e47bab4..7616cd560 100644
--- a/packages/docusaurus-theme-openapi-docs/src/theme/translationIds.ts
+++ b/packages/docusaurus-theme-openapi-docs/src/theme/translationIds.ts
@@ -29,6 +29,10 @@ export const OPENAPI_REQUEST = {
PARAMETERS_TITLE: "theme.openapi.request.parameters.title",
FETCHING_MESSAGE: "theme.openapi.request.fetchingMessage",
CONNECTION_FAILED: "theme.openapi.request.connectionFailed",
+ ERROR_TIMEOUT: "theme.openapi.request.error.timeout",
+ ERROR_NETWORK: "theme.openapi.request.error.network",
+ ERROR_CORS: "theme.openapi.request.error.cors",
+ ERROR_UNKNOWN: "theme.openapi.request.error.unknown",
};
export const OPENAPI_SERVER = {
diff --git a/packages/docusaurus-theme-openapi-docs/src/types.ts b/packages/docusaurus-theme-openapi-docs/src/types.ts
index e65019ea5..af1780daa 100644
--- a/packages/docusaurus-theme-openapi-docs/src/types.ts
+++ b/packages/docusaurus-theme-openapi-docs/src/types.ts
@@ -12,6 +12,8 @@ export interface ThemeConfig {
api?: {
proxy?: string;
authPersistance?: false | "localStorage" | "sessionStorage";
+ /** Request timeout in milliseconds. Defaults to 30000 (30 seconds). */
+ requestTimeout?: number;
};
}