{"version":3,"file":"tinyfish.mjs","names":[],"sources":["../../src/providers/tinyfish.ts"],"sourcesContent":["import type {\n  ProviderConfig,\n  ReadOptions,\n  ReadResult,\n  SearchRequestOptions,\n  SearchResult,\n} from \"../core/types.ts\";\nimport { Client } from \"../core/client.ts\";\nimport { Provider, assertProviderBaseURL, type ProviderSearchPage } from \"../core/provider.ts\";\nimport { TINYFISH_SEARCH_CATEGORIES } from \"../core/providers.ts\";\nimport {\n  AuthError,\n  HTTPError,\n  InvalidSearchContinuationError,\n  WebError,\n  normalizeError,\n} from \"../core/errors.ts\";\n\ninterface TinyfishSearchResult {\n  readonly position?: number;\n  readonly site_name?: string;\n  readonly title: string;\n  readonly snippet: string;\n  readonly url: string;\n  readonly date?: string;\n  readonly publisher?: string;\n  readonly authors?: readonly string[];\n  readonly venue?: string;\n  readonly year?: number;\n  readonly cited_by_count?: number;\n  readonly pdf_url?: string;\n}\n\ninterface TinyfishSearchResponse {\n  readonly query?: string;\n  readonly results?: readonly TinyfishSearchResult[];\n  readonly total_results?: number;\n  readonly page?: number;\n}\n\ninterface TinyfishFetchResult {\n  readonly url: string;\n  readonly final_url?: string;\n  readonly title?: string | null;\n  readonly description?: string | null;\n  readonly language?: string | null;\n  readonly author?: string | null;\n  readonly published_date?: string | null;\n  readonly text: string | Readonly<Record<string, unknown>>;\n  readonly links?: readonly string[];\n  readonly image_links?: readonly string[];\n  readonly unmatched_selectors?: readonly string[];\n  readonly latency_ms?: number | null;\n  readonly format: string;\n}\n\ninterface TinyfishFetchError {\n  readonly url: string;\n  readonly error: string;\n  readonly status?: number;\n  readonly unmatched_selectors?: readonly string[];\n  readonly candidate_selectors?: readonly string[];\n}\n\ninterface TinyfishFetchResponse {\n  readonly results?: readonly TinyfishFetchResult[];\n  readonly errors?: readonly TinyfishFetchError[];\n}\n\nconst TINYFISH_MAX_FETCH_TIMEOUT_MS = 110_000;\nconst TINYFISH_CLIENT_TIMEOUT_MS = 150_000;\n\nexport class TinyfishProvider extends Provider {\n  static readonly providerName = \"tinyfish\";\n  static readonly defaultBaseURL = \"https://api.search.tinyfish.ai\";\n\n  private readonly apiKey: string;\n  private readonly readBaseURL: string;\n  private readonly readClient: Client;\n\n  constructor(config: Readonly<ProviderConfig>) {\n    super(config, TinyfishProvider);\n    if (!config.apiKey) {\n      throw new AuthError(\"Missing API key for TinyFish. Set TINYFISH_API_KEY\", \"tinyfish\");\n    }\n\n    this.apiKey = config.apiKey;\n    this.readBaseURL = (config.readBaseURL ?? \"https://api.fetch.tinyfish.ai\").replace(/\\/+$/, \"\");\n    assertProviderBaseURL(this.readBaseURL, TinyfishProvider.providerName);\n    this.readClient = new Client({ maxRetries: 0, timeout: TINYFISH_CLIENT_TIMEOUT_MS });\n  }\n\n  async search(query: string, options?: SearchRequestOptions): Promise<SearchResult[]> {\n    return (await this.searchPage(query, options)).results;\n  }\n\n  async searchPage(\n    query: string,\n    options?: SearchRequestOptions,\n    continuation?: string,\n  ): Promise<ProviderSearchPage> {\n    try {\n      const page = tinyfishPage(continuation);\n      const response = await this.client.getJSON<TinyfishSearchResponse>(\n        `${this.baseURL}?${searchParams(query, options, page)}`,\n        this.authHeaders(),\n        options?.signal,\n      );\n      const providerResults = response.results ?? [];\n      return {\n        results: providerResults\n          .slice(0, clampMaxResults(options?.maxResults))\n          .map(mapSearchResult),\n        ...(providerResults.length > 0 && page < 10\n          ? { continuation: String(page + 1), continuationStatus: \"unknown\" as const }\n          : {}),\n      };\n    } catch (error) {\n      throw normalizeError(error, \"tinyfish\");\n    }\n  }\n\n  async read(url: string, options?: Readonly<ReadOptions>): Promise<ReadResult> {\n    try {\n      const response = await this.readClient.postJSON<TinyfishFetchResponse>(\n        this.readBaseURL,\n        fetchBody(url, options),\n        this.authHeaders(),\n        options?.signal,\n      );\n      const result = response.results?.[0];\n      if (result) return mapReadResult(result);\n      throw fetchFailure(response.errors?.[0]);\n    } catch (error) {\n      throw normalizeError(error, \"tinyfish\");\n    }\n  }\n\n  private authHeaders(): Record<string, string> {\n    return { \"X-API-Key\": this.apiKey };\n  }\n}\n\nfunction searchParams(\n  query: string,\n  options: SearchRequestOptions | undefined,\n  page: number,\n): string {\n  return new URLSearchParams({\n    query,\n    ...(page === 0 ? {} : { page: String(page) }),\n    ...domainSearchParams(options),\n    ...categorySearchParams(options?.category),\n    ...dateSearchParams(options),\n  }).toString();\n}\n\nfunction tinyfishPage(continuation?: string): number {\n  if (continuation === undefined) return 0;\n  if (!/^(?:[1-9]|10)$/u.test(continuation)) throw new InvalidSearchContinuationError();\n  return Number(continuation);\n}\n\nfunction domainSearchParams(options?: SearchRequestOptions): Record<string, string> {\n  return {\n    ...(options?.includeDomains?.length\n      ? { include_domains: options.includeDomains.join(\",\") }\n      : {}),\n    ...(options?.excludeDomains?.length\n      ? { exclude_domains: options.excludeDomains.join(\",\") }\n      : {}),\n  };\n}\n\nfunction categorySearchParams(category?: string): Record<string, string> {\n  if (!isTinyfishSearchCategory(category)) return {};\n  return { domain_type: category };\n}\n\nfunction isTinyfishSearchCategory(\n  category: string | undefined,\n): category is (typeof TINYFISH_SEARCH_CATEGORIES)[number] {\n  return TINYFISH_SEARCH_CATEGORIES.some((supported) => supported === category);\n}\n\nfunction dateSearchParams(options?: SearchRequestOptions): Record<string, string> {\n  if (!options) return {};\n  return options.category === \"research_paper\"\n    ? publicationYearParams(options)\n    : calendarDateParams(options);\n}\n\nfunction publicationYearParams(options: SearchRequestOptions): Record<string, string> {\n  return {\n    ...(options.startPublishedDate ? { pub_year_min: options.startPublishedDate.slice(0, 4) } : {}),\n    ...(options.endPublishedDate ? { pub_year_max: options.endPublishedDate.slice(0, 4) } : {}),\n  };\n}\n\nfunction calendarDateParams(options: SearchRequestOptions): Record<string, string> {\n  return {\n    ...(options.startPublishedDate ? { after_date: options.startPublishedDate.slice(0, 10) } : {}),\n    ...(options.endPublishedDate ? { before_date: options.endPublishedDate.slice(0, 10) } : {}),\n  };\n}\n\nfunction clampMaxResults(maxResults?: number): number {\n  return Math.max(maxResults ?? 10, 1);\n}\n\nfunction mapSearchResult(result: Readonly<TinyfishSearchResult>): SearchResult {\n  return {\n    url: result.url,\n    title: result.title,\n    snippet: result.snippet,\n    publishedDate: result.date,\n    author: result.authors?.join(\", \"),\n    metadata: searchResultMetadata(result),\n  };\n}\n\nfunction searchResultMetadata(\n  result: Readonly<TinyfishSearchResult>,\n): Record<string, unknown> | undefined {\n  const metadata = {\n    ...(result.position === undefined ? {} : { position: result.position }),\n    ...(result.site_name === undefined ? {} : { siteName: result.site_name }),\n    ...(result.publisher === undefined ? {} : { publisher: result.publisher }),\n    ...researchResultMetadata(result),\n  };\n  return Object.keys(metadata).length > 0 ? metadata : undefined;\n}\n\nfunction researchResultMetadata(result: Readonly<TinyfishSearchResult>): Record<string, unknown> {\n  return {\n    ...(result.authors === undefined ? {} : { authors: [...result.authors] }),\n    ...(result.venue === undefined ? {} : { venue: result.venue }),\n    ...(result.year === undefined ? {} : { year: result.year }),\n    ...(result.cited_by_count === undefined ? {} : { citedByCount: result.cited_by_count }),\n    ...(result.pdf_url === undefined ? {} : { pdfUrl: result.pdf_url }),\n  };\n}\n\nfunction fetchBody(url: string, options?: Readonly<ReadOptions>): Record<string, unknown> {\n  return {\n    urls: [url],\n    format: normalizeReadFormat(options?.format),\n    links: true,\n    image_links: true,\n    ...cacheParams(options?.noCache),\n    ...timeoutParams(options?.timeout),\n    ...selectorParams(options),\n  };\n}\n\nfunction cacheParams(noCache?: boolean): Record<string, number> {\n  return noCache ? { ttl: 0 } : {};\n}\n\nfunction timeoutParams(timeout?: number): Record<string, number> {\n  if (timeout === undefined) return {};\n  const timeoutMs = Math.round(timeout * 1000);\n  return {\n    per_url_timeout_ms: Math.min(Math.max(timeoutMs, 1), TINYFISH_MAX_FETCH_TIMEOUT_MS),\n  };\n}\n\nfunction selectorParams(options?: Readonly<ReadOptions>): Record<string, readonly string[]> {\n  return {\n    ...(options?.targetSelector ? { include_selectors: [options.targetSelector] } : {}),\n    ...(options?.removeSelector ? { exclude_selectors: [options.removeSelector] } : {}),\n  };\n}\n\nfunction normalizeReadFormat(format?: ReadOptions[\"format\"]): \"markdown\" | \"html\" {\n  return format === \"html\" ? \"html\" : \"markdown\";\n}\n\nfunction mapReadResult(result: Readonly<TinyfishFetchResult>): ReadResult {\n  const content = readContent(result.text);\n  const images = copyStrings(result.image_links);\n  return {\n    url: result.final_url ?? result.url,\n    title: optionalString(result.title),\n    description: optionalString(result.description),\n    content,\n    ...htmlContent(result.format, content),\n    publishedDate: optionalString(result.published_date),\n    image: images?.[0],\n    links: copyStrings(result.links),\n    images,\n    metadata: readResultMetadata(result),\n  };\n}\n\nfunction readContent(text: TinyfishFetchResult[\"text\"]): string {\n  return typeof text === \"string\" ? text : JSON.stringify(text);\n}\n\nfunction htmlContent(format: string, content: string): Record<string, string> {\n  return format === \"html\" ? { html: content } : {};\n}\n\nfunction optionalString(value: string | null | undefined): string | undefined {\n  return value ?? undefined;\n}\n\nfunction copyStrings(value?: readonly string[]): string[] | undefined {\n  return value ? [...value] : undefined;\n}\n\nfunction readResultMetadata(result: Readonly<TinyfishFetchResult>): Record<string, unknown> {\n  return {\n    originalUrl: result.url,\n    ...(result.language === undefined || result.language === null\n      ? {}\n      : { language: result.language }),\n    ...(result.author === undefined || result.author === null ? {} : { author: result.author }),\n    format: result.format,\n    ...(result.latency_ms === undefined || result.latency_ms === null\n      ? {}\n      : { latencyMs: result.latency_ms }),\n    ...(result.unmatched_selectors === undefined\n      ? {}\n      : { unmatchedSelectors: [...result.unmatched_selectors] }),\n  };\n}\n\nfunction fetchFailure(error?: Readonly<TinyfishFetchError>): WebError {\n  const reason = error?.error ?? \"no result returned\";\n  if (error?.error === \"page_not_found\" && error.status !== undefined) {\n    return new HTTPError(error.status, \"\", reason);\n  }\n\n  return new WebError(\n    `TinyFish fetch failed: ${reason}${statusSuffix(error)}${selectorHint(error)}`,\n  );\n}\n\nfunction statusSuffix(error?: Readonly<TinyfishFetchError>): string {\n  return error?.status === undefined ? \"\" : ` (HTTP ${error.status})`;\n}\n\nfunction selectorHint(error?: Readonly<TinyfishFetchError>): string {\n  const selectors = error?.candidate_selectors;\n  if (!selectors?.length) return \"\";\n  return `; candidate selectors: ${JSON.stringify(selectors)}`;\n}\n"],"mappings":"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"}