import type { EngineMap } from "./engines/engine_map.ts";import { version } from "../version.ts";
type UrlParameters = Record< string, string | number | boolean | undefined | null>;
export const _internals = { fetch: fetch, execute: execute, getBaseUrl: getBaseUrl,};
function getBaseUrl() { return "https://serpapi.com";}
type NextParametersKeys<E extends keyof EngineMap> = Omit< EngineMap[E]["parameters"], "api_key" | "no_cache" | "async" | "timeout">;type NextParameters<E extends keyof EngineMap> = { [K in keyof NextParametersKeys<E>]: string;};export function extractNextParameters< E extends keyof EngineMap,>(json: { serpapi_pagination?: { next: string }; pagination?: { next: string };}) { const nextUrlString = json["serpapi_pagination"]?.["next"] || json["pagination"]?.["next"];
if (nextUrlString) { const nextUrl = new URL(nextUrlString); const nextParameters = Object.fromEntries(nextUrl.searchParams.entries()); delete nextParameters["engine"]; return nextParameters as NextParameters<E>; }}
export function haveParametersChanged( parameters: Record<string, unknown>, nextParameters: Record<string, unknown>,) { const keys = [ ...Object.keys(parameters), ...Object.keys(nextParameters), ]; const uniqueKeys = new Set(keys); return [...uniqueKeys].some((key) => `${parameters[key]}` !== `${nextParameters[key]}` );}
function getSource() { const moduleSource = `serpapi@${version}`; try { const nodeVersion = (globalThis as any).process?.versions?.node; if (nodeVersion) { return `nodejs@${nodeVersion},${moduleSource}`; }
const denoVersion = (globalThis as any).Deno?.version?.deno; if (denoVersion) { return `deno@${denoVersion},${moduleSource}`; }
return `nodejs,${moduleSource}`; } catch { return `nodejs,${moduleSource}`; }}
export function buildUrl<P extends UrlParameters>( path: string, parameters: P,): string { const nonUndefinedParams: [string, string][] = Object.entries(parameters) .filter(([_, value]) => value !== undefined) .map(([key, value]) => [key, `${value}`]); const searchParams = new URLSearchParams(nonUndefinedParams); return `${_internals.getBaseUrl()}${path}?${searchParams}`;}
export async function execute<P extends UrlParameters>( path: string, parameters: P, timeout: number,): Promise<Response> { const url = buildUrl(path, { ...parameters, source: getSource(), }); return await _internals.fetch(url, { signal: AbortSignal.timeout(timeout), });}