import {z} from 'zod' export type SearchQuery = string; export type Count = number; export type Freshness = 'day' | 'week' | 'month' | 'year'; export type FreshnessValue = Freshness | string; export type Offset = number; export type Country = 'AR' | 'AU' | 'AT' | 'BE' | 'BR' | 'CA' | 'CL' | 'DK' | 'FI' | 'FR' | 'DE' | 'HK' | 'IN' | 'ID' | 'IT' | 'JP' | 'KR' | 'MY' | 'MX' | 'NL' | 'NZ' | 'NO' | 'CN' | 'PL' | 'PT' | 'PH' | 'RU' | 'SA' | 'ZA' | 'ES' | 'SE' | 'CH' | 'TW' | 'TR' | 'GB' | 'US'; export type Language = 'AR' | 'EU' | 'BN' | 'BG' | 'CA' | 'ZH-HANS' | 'ZH-HANT' | 'HR' | 'CS' | 'DA' | 'NL' | 'EN' | 'EN-GB' | 'ET' | 'FI' | 'FR' | 'GL' | 'DE' | 'EL' | 'GU' | 'HE' | 'HI' | 'HU' | 'IS' | 'IT' | 'JA' | 'KN' | 'KO' | 'LV' | 'LT' | 'MS' | 'ML' | 'MR' | 'NB' | 'PL' | 'PT-BR' | 'PT-PT' | 'PA' | 'RO' | 'RU' | 'SR' | 'SK' | 'SL' | 'ES' | 'SV' | 'TA' | 'TE' | 'TH' | 'TR' | 'UK' | 'VI'; export type SafeSearch = 'off' | 'moderate' | 'strict'; export type Knowledge = 'core'; export type IncludeDomains = Array; export type ExcludeDomains = Array; export type BoostDomains = Array; export type StrictOperators = boolean; export type HighlightsConfig = {total_max_tokens?: number | undefined}; export type FullPageConfig = {extraction_formats?: (Array<'html' | 'markdown'>) | undefined}; export type Extraction = {extraction_mode: 'highlights' | 'full_page', extraction_source?: ('blend' | 'cache' | 'fetch') | undefined, highlights?: HighlightsConfig | undefined, full_page?: FullPageConfig | undefined}; export type LiveCrawl = 'web' | 'all'; export type LiveCrawlFormats = Array<'html' | 'markdown'>; export type CrawlTimeout = number; export type SearchRequestBody = {query: SearchQuery, count?: Count | undefined, freshness?: FreshnessValue | undefined, offset?: Offset | undefined, country?: Country | undefined, language?: Language | undefined, safesearch?: SafeSearch | undefined, knowledge?: Knowledge | undefined, include_domains?: IncludeDomains | undefined, exclude_domains?: ExcludeDomains | undefined, boost_domains?: BoostDomains | undefined, strict_operators?: StrictOperators | undefined, extraction?: Extraction | undefined, livecrawl?: LiveCrawl | undefined, livecrawl_formats?: LiveCrawlFormats | undefined, crawl_timeout?: CrawlTimeout | undefined}; export type CreateApiV1SearchArgs = {body: SearchRequestBody}; export type CreateApiV1SearchOptions = {baseUrl?: string | undefined, ApiKeyAuth?: string | undefined, fetch?: typeof fetch | undefined}; export const webContentsPost = z.object({html: z.string().optional(), markdown: z.string().optional(), highlights: z.array(z.string()).optional()}); export const webResultPost = z.object({url: z.string().optional(), title: z.string().optional(), description: z.string().optional(), snippets: z.array(z.string()).optional(), thumbnail_url: z.string().optional(), page_age: z.string().optional(), contents: webContentsPost.optional(), favicon_url: z.string().optional()}); export const knowledgeAttribution = z.object({name: z.string(), source_description: z.string().optional()}); export const knowledgeResult = z.object({type: z.string(), title: z.string(), attribution: z.array(knowledgeAttribution), description: z.string().optional(), as_of: z.string().optional()}); export const searchMetadata = z.object({search_uuid: z.string().optional(), query: z.string().optional(), latency: z.number().optional()}); export const searchPostResponse = z.object({results: z.object({web: z.array(webResultPost).optional(), knowledge: z.array(knowledgeResult).optional()}).optional(), metadata: searchMetadata.optional()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Returns a list of unified search results from web and news sources * * POST /v1/search */ export const createApiV1Search = async (args: CreateApiV1SearchArgs, options?: CreateApiV1SearchOptions) => { const {baseUrl = "https://ydc-index.io", fetch: fetchFn = fetch, ApiKeyAuth} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (ApiKeyAuth !== undefined) headers.set("X-API-Key", ApiKeyAuth) const url = `${baseUrl.replace(/\/+$/, '')}/v1/search${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "POST", headers, body: JSON.stringify(args.body)}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(searchPostResponse, await res.json()) };