mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-16 07:33:46 -06:00
c7e7ac2728
* docs(secrets): remove retired web credential paths * refactor(web): remove retired provider compatibility paths * refactor(providers): delete retired compatibility routes * refactor(secrets): remove retired credential aliases * refactor(plugin-sdk): delete retired compatibility surfaces * docs(plugin-sdk): remove retired migration guidance * chore(plugin-sdk): refresh rebased surface budgets * chore(plugin-sdk): refresh API removal baseline * refactor(compat): migrate retired internal callers * chore(plugin-sdk): refresh current-main baselines * test(config): migrate plugin-owned secret assertions * test(gateway): narrow plugin secret refs * fix(plugin-sdk): preserve private boundary type identity * chore(compat): remove stale sweep references * chore(lint): lower max-lines budget * refactor(secrets): remove unused web helper * build(plugin-sdk): drop removed compat entries * chore(plugin-sdk): refresh rebased API baseline * chore(plugin-sdk): use Linux API baseline hash * fix(plugin-sdk): preserve private bundled build entries * fix(plugin-sdk): package private runtime facades * fix(plugins): preserve external credential contracts
187 lines
5.9 KiB
TypeScript
187 lines
5.9 KiB
TypeScript
// Firecrawl helper module supports config behavior.
|
|
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
|
|
import { canResolveEnvSecretRefInReadOnlyPath } from "openclaw/plugin-sdk/extension-shared";
|
|
import { resolvePositiveTimeoutSeconds } from "openclaw/plugin-sdk/provider-web-fetch";
|
|
import { resolveSecretInputString, normalizeSecretInput } from "openclaw/plugin-sdk/secret-input";
|
|
|
|
export const DEFAULT_FIRECRAWL_BASE_URL = "https://api.firecrawl.dev";
|
|
const DEFAULT_FIRECRAWL_SEARCH_TIMEOUT_SECONDS = 30;
|
|
const DEFAULT_FIRECRAWL_SCRAPE_TIMEOUT_SECONDS = 60;
|
|
const DEFAULT_FIRECRAWL_MAX_AGE_MS = 172_800_000;
|
|
const FIRECRAWL_API_KEY_ENV_VAR = "FIRECRAWL_API_KEY";
|
|
|
|
type FirecrawlSearchConfig =
|
|
| {
|
|
apiKey?: unknown;
|
|
baseUrl?: string;
|
|
}
|
|
| undefined;
|
|
|
|
type PluginEntryConfig =
|
|
| {
|
|
webSearch?: {
|
|
apiKey?: unknown;
|
|
baseUrl?: string;
|
|
};
|
|
webFetch?: {
|
|
apiKey?: unknown;
|
|
baseUrl?: string;
|
|
onlyMainContent?: boolean;
|
|
maxAgeMs?: number;
|
|
timeoutSeconds?: number;
|
|
};
|
|
}
|
|
| undefined;
|
|
|
|
type FirecrawlFetchConfig =
|
|
| {
|
|
apiKey?: unknown;
|
|
baseUrl?: string;
|
|
onlyMainContent?: boolean;
|
|
maxAgeMs?: number;
|
|
timeoutSeconds?: number;
|
|
}
|
|
| undefined;
|
|
|
|
function resolveFirecrawlSearchConfig(cfg?: OpenClawConfig): FirecrawlSearchConfig {
|
|
const pluginConfig = cfg?.plugins?.entries?.firecrawl?.config as PluginEntryConfig;
|
|
const pluginWebSearch = pluginConfig?.webSearch;
|
|
if (pluginWebSearch && typeof pluginWebSearch === "object" && !Array.isArray(pluginWebSearch)) {
|
|
return pluginWebSearch;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
function resolveFirecrawlFetchConfig(cfg?: OpenClawConfig): FirecrawlFetchConfig {
|
|
const pluginConfig = cfg?.plugins?.entries?.firecrawl?.config as PluginEntryConfig;
|
|
const pluginWebFetch = pluginConfig?.webFetch;
|
|
if (pluginWebFetch && typeof pluginWebFetch === "object" && !Array.isArray(pluginWebFetch)) {
|
|
return pluginWebFetch;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
type ConfiguredSecretResolution =
|
|
| { status: "available"; value: string }
|
|
| { status: "missing" }
|
|
| { status: "blocked" };
|
|
|
|
function resolveConfiguredSecret(
|
|
value: unknown,
|
|
path: string,
|
|
cfg?: OpenClawConfig,
|
|
): ConfiguredSecretResolution {
|
|
const resolved = resolveSecretInputString({
|
|
value,
|
|
path,
|
|
defaults: cfg?.secrets?.defaults,
|
|
mode: "inspect",
|
|
});
|
|
if (resolved.status === "available") {
|
|
const normalized = normalizeSecretInput(resolved.value);
|
|
return normalized ? { status: "available", value: normalized } : { status: "missing" };
|
|
}
|
|
if (resolved.status === "missing") {
|
|
return { status: "missing" };
|
|
}
|
|
if (resolved.ref.source !== "env") {
|
|
return { status: "blocked" };
|
|
}
|
|
const envVarName = resolved.ref.id.trim();
|
|
if (envVarName !== FIRECRAWL_API_KEY_ENV_VAR) {
|
|
return { status: "blocked" };
|
|
}
|
|
if (
|
|
!canResolveEnvSecretRefInReadOnlyPath({
|
|
cfg,
|
|
provider: resolved.ref.provider,
|
|
id: envVarName,
|
|
})
|
|
) {
|
|
return { status: "blocked" };
|
|
}
|
|
const envValue = normalizeSecretInput(process.env[envVarName]);
|
|
return envValue ? { status: "available", value: envValue } : { status: "missing" };
|
|
}
|
|
|
|
export function resolveFirecrawlApiKey(cfg?: OpenClawConfig): string | undefined {
|
|
const pluginConfig = cfg?.plugins?.entries?.firecrawl?.config as PluginEntryConfig;
|
|
const search = resolveFirecrawlSearchConfig(cfg);
|
|
const configuredCandidates: Array<{ value: unknown; path: string }> = [
|
|
{
|
|
value: pluginConfig?.webFetch?.apiKey,
|
|
path: "plugins.entries.firecrawl.config.webFetch.apiKey",
|
|
},
|
|
{
|
|
value: search?.apiKey,
|
|
path: "plugins.entries.firecrawl.config.webSearch.apiKey",
|
|
},
|
|
];
|
|
let blockedConfiguredSecret = false;
|
|
for (const candidate of configuredCandidates) {
|
|
const resolved = resolveConfiguredSecret(candidate.value, candidate.path, cfg);
|
|
if (resolved.status === "available") {
|
|
return resolved.value;
|
|
}
|
|
if (resolved.status === "blocked") {
|
|
blockedConfiguredSecret = true;
|
|
}
|
|
}
|
|
if (blockedConfiguredSecret) {
|
|
return undefined;
|
|
}
|
|
return normalizeSecretInput(process.env[FIRECRAWL_API_KEY_ENV_VAR]) || undefined;
|
|
}
|
|
|
|
export function resolveFirecrawlBaseUrl(cfg?: OpenClawConfig): string {
|
|
const search = resolveFirecrawlSearchConfig(cfg);
|
|
const fetch = resolveFirecrawlFetchConfig(cfg);
|
|
const configured =
|
|
(typeof search?.baseUrl === "string" ? search.baseUrl.trim() : "") ||
|
|
(typeof fetch?.baseUrl === "string" ? fetch.baseUrl.trim() : "") ||
|
|
normalizeSecretInput(process.env.FIRECRAWL_BASE_URL) ||
|
|
"";
|
|
return configured || DEFAULT_FIRECRAWL_BASE_URL;
|
|
}
|
|
|
|
export function resolveFirecrawlOnlyMainContent(cfg?: OpenClawConfig, override?: boolean): boolean {
|
|
if (typeof override === "boolean") {
|
|
return override;
|
|
}
|
|
const fetch = resolveFirecrawlFetchConfig(cfg);
|
|
if (typeof fetch?.onlyMainContent === "boolean") {
|
|
return fetch.onlyMainContent;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
export function resolveFirecrawlMaxAgeMs(cfg?: OpenClawConfig, override?: number): number {
|
|
if (typeof override === "number" && Number.isFinite(override) && override >= 0) {
|
|
return Math.floor(override);
|
|
}
|
|
const fetch = resolveFirecrawlFetchConfig(cfg);
|
|
if (
|
|
typeof fetch?.maxAgeMs === "number" &&
|
|
Number.isFinite(fetch.maxAgeMs) &&
|
|
fetch.maxAgeMs >= 0
|
|
) {
|
|
return Math.floor(fetch.maxAgeMs);
|
|
}
|
|
return DEFAULT_FIRECRAWL_MAX_AGE_MS;
|
|
}
|
|
|
|
export function resolveFirecrawlScrapeTimeoutSeconds(
|
|
cfg?: OpenClawConfig,
|
|
override?: number,
|
|
): number {
|
|
const fetch = resolveFirecrawlFetchConfig(cfg);
|
|
return resolvePositiveTimeoutSeconds(
|
|
override,
|
|
resolvePositiveTimeoutSeconds(fetch?.timeoutSeconds, DEFAULT_FIRECRAWL_SCRAPE_TIMEOUT_SECONDS),
|
|
);
|
|
}
|
|
|
|
export function resolveFirecrawlSearchTimeoutSeconds(override?: number): number {
|
|
return resolvePositiveTimeoutSeconds(override, DEFAULT_FIRECRAWL_SEARCH_TIMEOUT_SECONDS);
|
|
}
|