Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
309 changes: 154 additions & 155 deletions openapi_v2.yaml

Large diffs are not rendered by default.

64 changes: 64 additions & 0 deletions src/api/v2Client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import axios, { type AxiosRequestConfig, type AxiosResponse } from 'axios';
import { getApiConfig } from '@/config/api';

/**
* Builds the absolute URL for a V2 API request.
*
* @param {string} path - The endpoint path without the leading base URL.
* @returns {string} The absolute URL for the request.
*/
function buildUrl(path: string): string {
const config = getApiConfig();
const basePath = (config.basePath ?? '').replace(/\/+$/, '');
const trimmedPath = path.replace(/^\/+/, '');
return `${basePath}/${trimmedPath}`;
}

/**
* Builds the Axios configuration shared by all V2 requests.
*
* @param {AxiosRequestConfig} [override] - Optional overrides for the request.
* @returns {AxiosRequestConfig} The Axios configuration with headers and overrides merged.
*/
function buildRequestConfig(override?: AxiosRequestConfig): AxiosRequestConfig {
const config = getApiConfig();
const baseHeaders = (config.baseOptions?.headers ?? {}) as Record<string, string>;
const headers = {
'Content-Type': 'application/json',
...baseHeaders,
...override?.headers,
};
return {
...override,
headers,
};
}

/**
* Sends a POST request to a V2 API endpoint.
*
* @param {string} path - The endpoint path relative to the API base URL.
* @param {unknown} payload - The request payload.
* @param {AxiosRequestConfig} [config] - Optional Axios configuration overrides.
* @returns {Promise<AxiosResponse<T>>} The Axios response promise.
*/
export function postV2<T>(
path: string,
payload: unknown,
config?: AxiosRequestConfig,
): Promise<AxiosResponse<T>> {
const url = buildUrl(path);
return axios.post<T>(url, payload, buildRequestConfig(config));
}

/**
* Sends a GET request to a V2 API endpoint.
*
* @param {string} path - The endpoint path relative to the API base URL.
* @param {AxiosRequestConfig} [config] - Optional Axios configuration overrides.
* @returns {Promise<AxiosResponse<T>>} The Axios response promise.
*/
export function getV2<T>(path: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
const url = buildUrl(path);
return axios.get<T>(url, buildRequestConfig(config));
}
61 changes: 47 additions & 14 deletions src/components/ApiKeyInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@
<a href="https://app.firecrawl.dev" target="_blank">the Firecrawl dashboard</a>
</small>
</div>
<div class="form-group">
<label for="apiVersion">Firecrawl API version:</label>
<select id="apiVersion" v-model="selectedVersion">
<option value="v1">v1</option>
<option value="v2">v2</option>
</select>
<small>Select the API version that matches your backend deployment.</small>
</div>
<div class="form-group">
<label for="baseUrl">Firecrawl API base URL (optional):</label>
<input
id="baseUrl"
v-model="baseUrl"
type="text"
placeholder="https://api.firecrawl.dev/v1"
/>
<input id="baseUrl" v-model="baseUrl" type="text" :placeholder="placeholder" />
<small> Leave blank to use the default URL. </small>
</div>
<button type="submit" class="primary-button">Save</button>
Expand All @@ -36,8 +39,10 @@
</template>

<script lang="ts">
import { defineComponent, ref, onMounted } from 'vue';
import { defineComponent, ref, onMounted, watch, computed } from 'vue';
import { refreshApiClients } from '@/plugins/api';
import { getBaseUrlForVersion, getDefaultBaseUrl } from '@/config/api';
import { useApiVersion, type ApiVersion } from '@/config/apiVersion';

/**
* Component allowing users to configure and store the Firecrawl API key and base URL.
Expand All @@ -49,34 +54,44 @@ import { refreshApiClients } from '@/plugins/api';
export default defineComponent({
name: 'ApiKeyInput',
setup() {
const apiKey = ref(localStorage.getItem('firecrawl_api_key') || '');
const baseUrl = ref(localStorage.getItem('firecrawl_base_url') || '');
const { apiVersion, setApiVersion } = useApiVersion();
const apiKey = ref(readStoredApiKey());
const selectedVersion = ref<ApiVersion>(apiVersion.value);
const baseUrl = ref(getBaseUrlForVersion(selectedVersion.value));
const error = ref('');
const success = ref(false);

const placeholder = computed(() => getDefaultBaseUrl(selectedVersion.value));

// Automatically display if no key is configured
onMounted(() => {
if (!apiKey.value) {
error.value = 'Please configure your API key to continue';
}
});

watch(
selectedVersion,
(newVersion) => {
baseUrl.value = getBaseUrlForVersion(newVersion);
},
{ immediate: true },
);

const saveApiConfig = () => {
try {
if (!apiKey.value) {
throw new Error('Please enter a valid API key');
}
// Save the API key
localStorage.setItem('firecrawl_api_key', apiKey.value);
// Save the base URL (even if empty to override any previous value if needed)
localStorage.setItem('firecrawl_base_url', baseUrl.value);

setApiVersion(selectedVersion.value);

success.value = true;
error.value = '';
setTimeout(() => (success.value = false), 3000);

// Update API clients dynamically without reloading the page
refreshApiClients(baseUrl.value, apiKey.value);
refreshApiClients(baseUrl.value, apiKey.value, selectedVersion.value);
} catch (err) {
error.value = err instanceof Error ? err.message : 'Unknown error';
success.value = false;
Expand All @@ -86,12 +101,30 @@ export default defineComponent({
return {
apiKey,
baseUrl,
placeholder,
error,
success,
selectedVersion,
saveApiConfig,
};
},
});

/**
* Reads the API key from local storage or environment variables.
*
* @returns {string} The stored API key or an empty string when unavailable.
*/
function readStoredApiKey(): string {
if (typeof window !== 'undefined' && window.localStorage) {
const storedKey = window.localStorage.getItem('firecrawl_api_key');
if (storedKey !== null) {
return storedKey;
}
}
const env = import.meta.env as Record<string, string | undefined>;
return env.VITE_FIRECRAWL_API_KEY || '';
}
</script>

<style scoped>
Expand Down
Loading