{"version":3,"sources":["../src/polly-fetch.ts","../src/types.ts","../package.json","../src/client.ts","../src/services/youtube.ts","../src/services/web.ts","../src/services/transcript.ts","../src/index.ts"],"names":["polly_fetch_default","crossFetch","SupadataError","error","package_default","USER_AGENT","BaseClient","config","endpoint","params","method","url","queryParams","key","value","item","body","options","response","contentType","errorData","YouTubeService","jobId","min","max","operation","WebService","request","pages","nextUrl","TranscriptService","Supadata"],"mappings":"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","file":"index.mjs","sourcesContent":["import crossFetch from 'cross-fetch';\n\nexport default fetch || crossFetch","export interface TranscriptChunk {\n  text: string;\n  offset: number;\n  duration: number;\n  lang: string;\n}\n\nexport interface Transcript {\n  content: TranscriptChunk[] | string;\n  lang: string;\n  availableLangs: string[];\n}\n\nexport interface TranslatedTranscript {\n  content: TranscriptChunk[] | string;\n  lang: string;\n}\n\nexport interface Scrape {\n  url: string;\n  content: string;\n  name: string;\n  description: string;\n  ogUrl: string;\n  countCharacters: number;\n  urls: string[];\n}\n\nexport interface SiteMap {\n  urls: string[];\n}\n\nexport interface CrawlRequest {\n  url: string;\n  limit?: number;\n}\n\nexport interface CrawlJob {\n  status: 'scraping' | 'completed' | 'failed' | 'cancelled';\n  pages?: Scrape[];\n  next?: string;\n}\n\nexport interface SupadataConfig {\n  apiKey: string;\n  baseUrl?: string;\n}\n\nexport class SupadataError extends Error {\n  error:\n    | 'invalid-request'\n    | 'internal-error'\n    | 'transcript-unavailable'\n    | 'not-found'\n    | 'unauthorized'\n    | 'upgrade-required'\n    | 'limit-exceeded';\n  details: string;\n  documentationUrl: string;\n\n  constructor(error: {\n    error: SupadataError['error'];\n    message?: string;\n    details?: string;\n    documentationUrl?: string;\n  }) {\n    super(error.message || 'An unexpected error occurred');\n    this.error = error.error || 'internal-error';\n    this.details = error.details || 'An unexpected error occurred';\n    this.documentationUrl = error.documentationUrl || '';\n    this.name = 'SupadataError';\n  }\n}\n\nexport interface YoutubeVideo {\n  id: string;\n  title: string;\n  description: string;\n  duration: number;\n  channel: {\n    id: string;\n    name: string;\n  };\n  tags: string[];\n  thumbnail: string;\n  uploadDate: string;\n  viewCount: number;\n  likeCount: number;\n  transcriptLanguages: string[];\n}\n\nexport interface YoutubeChannel {\n  id: string;\n  name: string;\n  handle: string;\n  description: string;\n  subscriberCount: number;\n  videoCount: number;\n  thumbnail: string;\n  banner: string;\n}\n\nexport interface YoutubePlaylist {\n  id: string;\n  title: string;\n  videoCount: number;\n  viewCount: number;\n  lastUpdated: string;\n  description: string;\n  thumbnail: string;\n}\n\nexport interface YoutubeBatchSource {\n  videoIds?: string[];\n  playlistId?: string;\n  channelId?: string;\n  limit?: number;\n}\n\nexport interface YoutubeTranscriptBatchRequest extends YoutubeBatchSource {\n  lang?: string;\n  text?: boolean;\n}\n\nexport interface YoutubeVideoBatchRequest extends YoutubeBatchSource {}\n\nexport interface JobId {\n  jobId: string;\n}\n\nexport interface YoutubeBatchJob extends JobId {}\n\nexport type JobStatus = 'queued' | 'active' | 'completed' | 'failed';\n\nexport type YoutubeBatchJobStatus = JobStatus;\n\nexport interface YoutubeBatchResultItem {\n  videoId: string;\n  transcript?: Transcript;\n  video?: YoutubeVideo;\n  errorCode?: string;\n}\n\nexport interface YoutubeBatchStats {\n  total: number;\n  succeeded: number;\n  failed: number;\n}\n\nexport interface YoutubeBatchResults {\n  status: YoutubeBatchJobStatus;\n  results?: YoutubeBatchResultItem[];\n  stats?: YoutubeBatchStats;\n  completedAt?: string;\n}\n\nexport type TranscriptOrJobId = Transcript | JobId;\n\nexport interface JobResult<T = any> {\n  status: JobStatus;\n  result?: T | null;\n  error?: {\n    error: SupadataError['error'];\n    message: string;\n    details: string;\n    documentationUrl?: string;\n  } | null;\n}\n\n// YouTube Search Types\nexport type YoutubeSearchUploadDate =\n  | 'all'\n  | 'hour'\n  | 'today'\n  | 'week'\n  | 'month'\n  | 'year';\nexport type YoutubeSearchType =\n  | 'all'\n  | 'video'\n  | 'channel'\n  | 'playlist'\n  | 'movie';\nexport type YoutubeSearchDuration = 'all' | 'short' | 'medium' | 'long';\nexport type YoutubeSearchSortBy = 'relevance' | 'rating' | 'date' | 'views';\n\nexport interface YoutubeSearchParams {\n  query: string;\n  uploadDate?: YoutubeSearchUploadDate;\n  type?: YoutubeSearchType;\n  duration?: YoutubeSearchDuration;\n  sortBy?: YoutubeSearchSortBy;\n  features?: string[];\n  limit?: number;\n  nextPageToken?: string;\n}\n\nexport interface YoutubeSearchVideoResult {\n  type: 'video';\n  id: string;\n  title: string;\n  description: string;\n  thumbnail: string;\n  duration: number;\n  viewCount: number;\n  uploadDate: string;\n  channel: {\n    id: string;\n    name: string;\n  };\n}\n\nexport interface YoutubeSearchChannelResult {\n  type: 'channel';\n  id: string;\n  name: string;\n  handle: string;\n  description: string;\n  thumbnail: string;\n  subscriberCount: number;\n  videoCount: number;\n}\n\nexport interface YoutubeSearchPlaylistResult {\n  type: 'playlist';\n  id: string;\n  title: string;\n  description: string;\n  thumbnail: string;\n  videoCount: number;\n  channel: {\n    id: string;\n    name: string;\n  };\n}\n\nexport type YoutubeSearchResult =\n  | YoutubeSearchVideoResult\n  | YoutubeSearchChannelResult\n  | YoutubeSearchPlaylistResult;\n\nexport interface YoutubeSearchResponse {\n  query: string;\n  results: YoutubeSearchResult[];\n  totalResults: number;\n  nextPageToken?: string;\n}\n\n// Metadata Types\nexport type MetadataPlatform = 'youtube' | 'tiktok' | 'instagram' | 'twitter';\nexport type MetadataType = 'video' | 'image' | 'carousel' | 'post';\n\nexport interface MetadataAuthor {\n  username: string;\n  displayName: string;\n  avatarUrl: string;\n  verified: boolean;\n}\n\nexport interface MetadataStats {\n  views: number | null;\n  likes: number | null;\n  comments: number | null;\n  shares: number | null;\n}\n\nexport interface VideoMedia {\n  type: 'video';\n  url: string;\n  duration: number;\n  width: number;\n  height: number;\n  thumbnailUrl: string;\n}\n\nexport interface ImageMedia {\n  type: 'image';\n  url: string;\n  width: number;\n  height: number;\n}\n\nexport interface CarouselMedia {\n  type: 'carousel';\n  items: Array<VideoMedia | ImageMedia>;\n}\n\nexport interface PostMedia {\n  type: 'post';\n  text: string;\n}\n\nexport type Media = VideoMedia | ImageMedia | CarouselMedia | PostMedia;\n\nexport interface Metadata {\n  platform: MetadataPlatform;\n  type: MetadataType;\n  id: string;\n  url: string;\n  title: string | null;\n  description: string | null;\n  author: MetadataAuthor;\n  stats: MetadataStats;\n  media: Media;\n  tags: string[];\n  createdAt: string;\n  additionalData: Record<string, any>;\n}\n","{\n  \"name\": \"@supadata/js\",\n  \"version\": \"1.3.2\",\n  \"description\": \"TypeScript / JavaScript SDK for Supadata API\",\n  \"homepage\": \"https://supadata.ai\",\n  \"repository\": \"https://github.com/supadata-ai/js\",\n  \"main\": \"./dist/index.cjs\",\n  \"module\": \"./dist/index.mjs\",\n  \"types\": \"./dist/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.ts\",\n      \"import\": \"./dist/index.mjs\",\n      \"require\": \"./dist/index.cjs\",\n      \"default\": \"./dist/index.mjs\"\n    }\n  },\n  \"scripts\": {\n    \"dev\": \"tsup --watch\",\n    \"build\": \"tsup\",\n    \"test\": \"node --experimental-vm-modules node_modules/jest/bin/jest.js\",\n    \"prepare\": \"npm run build\",\n    \"format\": \"prettier --write \\\"src/**/*.{js,ts}\\\"\",\n    \"format:check\": \"prettier --check \\\"src/**/*.{js,ts}\\\"\"\n  },\n  \"files\": [\n    \"dist\",\n    \"README.md\"\n  ],\n  \"keywords\": [\n    \"supadata\",\n    \"api\",\n    \"sdk\",\n    \"typescript\",\n    \"youtube\",\n    \"tiktok\",\n    \"instagram\",\n    \"twitter\",\n    \"transcript\",\n    \"web scraping\"\n  ],\n  \"author\": \"Supadata AI\",\n  \"license\": \"MIT\",\n  \"engines\": {\n    \"node\": \">=18\"\n  },\n  \"dependencies\": {\n    \"cross-fetch\": \"^4.0.0\"\n  },\n  \"devDependencies\": {\n    \"@types/jest\": \"^29.5.14\",\n    \"@types/node\": \"^22.10.10\",\n    \"jest\": \"^29.7.0\",\n    \"jest-fetch-mock\": \"^3.0.3\",\n    \"prettier\": \"^3.4.2\",\n    \"ts-jest\": \"^29.2.5\",\n    \"typescript\": \"^5.7.3\",\n    \"tsup\": \"^8.3.6\"\n  }\n}","import fetch from './polly-fetch';\nimport { SupadataConfig, SupadataError } from './types.js';\n// @ts-expect-error: Non-TS import for version from package.json\nimport pkg from '../package.json';\n\nconst USER_AGENT = `supadata-js/${pkg.version}`;\n\nexport class BaseClient {\n  protected config: SupadataConfig;\n\n  constructor(config: SupadataConfig) {\n    this.config = config;\n  }\n\n  protected async fetch<T>(\n    endpoint: string,\n    params: Record<string, any> = {},\n    method: 'GET' | 'POST' = 'GET'\n  ): Promise<T> {\n    const baseUrl = this.config.baseUrl || 'https://api.supadata.ai/v1';\n    let url = `${baseUrl}${\n      endpoint.startsWith('/') ? endpoint : `/${endpoint}`\n    }`;\n\n    if (method === 'GET' && Object.keys(params).length > 0) {\n      const queryParams = new URLSearchParams();\n      Object.entries(params).forEach(([key, value]) => {\n        if (value !== undefined && value !== null) {\n          if (Array.isArray(value)) {\n            value.forEach((item) => queryParams.append(key, String(item)));\n          } else {\n            queryParams.append(key, String(value));\n          }\n        }\n      });\n      url += `?${queryParams.toString()}`;\n    }\n\n    return this.fetchUrl<T>(url, method, params);\n  }\n\n  protected async fetchUrl<T>(\n    url: string,\n    method: 'GET' | 'POST' = 'GET',\n    body?: Record<string, any>\n  ): Promise<T> {\n    const options: RequestInit = {\n      method,\n      headers: {\n        'x-api-key': this.config.apiKey,\n        'Content-Type': 'application/json',\n        'User-Agent': USER_AGENT,\n      },\n    };\n\n    if (method === 'POST' && body) {\n      options.body = JSON.stringify(body);\n    }\n\n    const response = await fetch(url, options);\n\n    const contentType = response.headers.get('content-type');\n\n    if (!response.ok) {\n      // Handle standard API errors\n      if (contentType?.includes('application/json')) {\n        const errorData = await response.json();\n        throw new SupadataError(errorData);\n      } else {\n        // Fallback for unexpected non-JSON errors\n        throw new SupadataError({\n          error: 'internal-error',\n          message: 'Unexpected error response format',\n          details: await response.text(),\n        });\n      }\n    }\n\n    try {\n      if (!contentType?.includes('application/json')) {\n        throw new SupadataError({\n          error: 'internal-error',\n          message: 'Invalid response format',\n          details: 'Expected JSON response but received different content type',\n        });\n      }\n\n      return (await response.json()) as T;\n    } catch (error) {\n      throw new SupadataError({\n        error: 'internal-error',\n        message: 'Failed to parse response',\n        details: error instanceof Error ? error.message : 'Unknown error',\n      });\n    }\n  }\n}\n","import { BaseClient } from '../client.js';\nimport {\n  SupadataError,\n  Transcript,\n  TranslatedTranscript,\n  YoutubeBatchJob,\n  YoutubeBatchResults,\n  YoutubeChannel,\n  YoutubePlaylist,\n  YoutubeTranscriptBatchRequest,\n  YoutubeVideo,\n  YoutubeVideoBatchRequest,\n  YoutubeSearchParams,\n  YoutubeSearchResponse,\n} from '../types.js';\n\n/**\n * Ensures exactly one property from the specified keys is provided.\n * @example\n * // Valid: { url: \"...\" } or { videoId: \"...\" }\n * // Invalid: {} or { url: \"...\", videoId: \"...\" }\n */\ntype ExactlyOne<T, Keys extends keyof T> = {\n  [K in Keys]: { [P in K]-?: T[P] } & { [P in Exclude<Keys, K>]?: never };\n}[Keys] &\n  Omit<T, Keys>;\n\nexport type TranscriptParams = {\n  lang?: string;\n  text?: boolean;\n} & ExactlyOne<{ videoId: string; url: string }, 'videoId' | 'url'>;\n\nexport interface TranslateParams extends Omit<TranscriptParams, 'lang'> {\n  lang: string;\n}\n\nexport interface ResourceParams {\n  id: string;\n}\n\nexport interface ChannelVideosParams extends ResourceParams {\n  limit?: number;\n  type?: 'video' | 'short' | 'live' | 'all';\n}\n\nexport interface PlaylistVideosParams extends ResourceParams {\n  limit?: number;\n}\n\nexport interface VideoIds {\n  videoIds: string[];\n  shortIds: string[];\n  liveIds: string[];\n}\n\nexport class YouTubeService extends BaseClient {\n  /**\n   * Handles YouTube Transcript operations.\n   * @deprecated Use `supadata.transcript()` instead for multi-platform support\n   */\n  transcript = Object.assign(\n    /**\n     * Fetches a transcript for a YouTube video.\n     * @param params - Parameters for fetching the transcript\n     * @param params.videoId - The YouTube video ID (mutually exclusive with url)\n     * @param params.url - The YouTube video URL (mutually exclusive with videoId)\n     * @param params.lang - The language code for the transcript (optional)\n     * @param params.text - Whether to return only the text content (optional)\n     * @returns A promise that resolves to a Transcript object\n     * @deprecated Use `supadata.transcript()` instead for multi-platform support\n     */\n    async (params: TranscriptParams): Promise<Transcript> => {\n      return this.fetch<Transcript>('/youtube/transcript', params);\n    },\n    {\n      /**\n       * Batch fetches transcripts for multiple YouTube videos.\n       * @param params - Parameters for the transcript batch job\n       * @param params.videoIds - Array of YouTube video IDs to fetch transcripts for\n       * @param params.lang - The language code for the transcripts (optional)\n       * @param params.limit - Maximum number of videos to process (optional, default: 10, max: 5000)\n       * @param params.text - Whether to return only the text content (optional)\n       * @returns A promise that resolves to a YoutubeBatchJob object with the job ID\n       */\n      batch: async (\n        params: YoutubeTranscriptBatchRequest\n      ): Promise<YoutubeBatchJob> => {\n        this.validateLimit(params, 1, 5000, 'batch operation');\n        return this.fetch<YoutubeBatchJob>(\n          '/youtube/transcript/batch',\n          params,\n          'POST'\n        );\n      },\n    }\n  );\n\n  /**\n   * Handles YouTube video operations.\n   * @deprecated Use `supadata.metadata()` instead for multi-platform support\n   */\n  video = Object.assign(\n    /**\n     * Fetches a YouTube video based on the provided parameters.\n     * @param params - The parameters required to fetch the YouTube video\n     * @param params.id - The YouTube video ID\n     * @returns A promise that resolves to a YoutubeVideo object\n     * @deprecated Use `supadata.metadata()` instead for multi-platform support\n     */\n    async (params: ResourceParams): Promise<YoutubeVideo> => {\n      return this.fetch<YoutubeVideo>('/youtube/video', params);\n    },\n    {\n      /**\n       * Batch fetches metadata for multiple YouTube videos.\n       * @param params - Parameters for the video metadata batch job\n       * @param params.videoIds - Array of YouTube video IDs to fetch metadata for\n       * @param params.limit - Maximum number of videos to process (optional, default: 10, max: 5000)\n       * @returns A promise that resolves to a YoutubeBatchJob object with the job ID\n       */\n      batch: async (\n        params: YoutubeVideoBatchRequest\n      ): Promise<YoutubeBatchJob> => {\n        this.validateLimit(params, 1, 5000, 'batch operation');\n        return this.fetch<YoutubeBatchJob>(\n          '/youtube/video/batch',\n          params,\n          'POST'\n        );\n      },\n    }\n  );\n\n  /**\n   * Handles YouTube channel operations.\n   */\n  channel = Object.assign(\n    /**\n     * Fetches YouTube channel information.\n     * @param params - The parameters required to fetch the YouTube channel information\n     * @param params.id - The YouTube channel ID\n     * @returns A promise that resolves to a YoutubeChannel object containing the channel information\n     */\n    async (params: ResourceParams): Promise<YoutubeChannel> => {\n      return this.fetch<YoutubeChannel>('/youtube/channel', params);\n    },\n    {\n      /**\n       * Fetches the videos of a YouTube channel.\n       * @param params - The parameters required to fetch the YouTube channel videos\n       * @param params.id - The YouTube channel ID\n       * @param params.limit - The maximum number of videos to fetch (default: 30, max: 5000)\n       * @param params.type - The type of videos to fetch ('video', 'short', 'live', or 'all', default: 'video')\n       * @returns A promise that resolves to an object containing arrays of video IDs, short IDs, and live IDs\n       * @throws {SupadataError} If the limit is invalid (less than 1 or greater than 5000)\n       */\n      videos: async (params: ChannelVideosParams): Promise<VideoIds> => {\n        this.validateLimit(params);\n        return this.fetch<VideoIds>('/youtube/channel/videos', params);\n      },\n    }\n  );\n\n  /**\n   * Handles YouTube playlist operations.\n   */\n  playlist = Object.assign(\n    /**\n     * Fetches a YouTube playlist.\n     * @param params - The parameters required to fetch the playlist\n     * @param params.id - The YouTube playlist ID\n     * @returns A promise that resolves to a YoutubePlaylist object\n     */\n    async (params: ResourceParams): Promise<YoutubePlaylist> => {\n      return this.fetch<YoutubePlaylist>('/youtube/playlist', params);\n    },\n    {\n      /**\n       * Fetches the videos of a YouTube playlist.\n       * @param params - The parameters required to fetch the playlist videos\n       * @param params.id - The YouTube playlist ID\n       * @param params.limit - The maximum number of videos to fetch (default: 30, max: 5000)\n       * @returns A promise that resolves to an object containing arrays of video IDs, short IDs, and live IDs\n       * @throws {SupadataError} If the limit is invalid (less than 1 or greater than 5000)\n       */\n      videos: async (params: PlaylistVideosParams): Promise<VideoIds> => {\n        this.validateLimit(params);\n        return this.fetch<VideoIds>('/youtube/playlist/videos', params);\n      },\n    }\n  );\n\n  /**\n   * Handles YouTube batch operations.\n   */\n  batch = {\n    /**\n     * Retrieves the status and results of a batch job.\n     * @param jobId - The ID of the batch job\n     * @returns A promise that resolves to the YoutubeBatchResults containing job status and results\n     * @throws {SupadataError} If jobId is not provided\n     */\n    getBatchResults: async (jobId: string): Promise<YoutubeBatchResults> => {\n      if (!jobId) {\n        throw new SupadataError({\n          error: 'invalid-request',\n          message: 'Missing jobId',\n          details: 'The jobId parameter is required to get batch results.',\n        });\n      }\n      return this.fetch<YoutubeBatchResults>(`/youtube/batch/${jobId}`);\n    },\n  };\n\n  /**\n   * Translates a YouTube video transcript to a specified language.\n   * @param params - Parameters for translating the transcript\n   * @param params.videoId - The YouTube video ID (mutually exclusive with url)\n   * @param params.url - The YouTube video URL (mutually exclusive with videoId)\n   * @param params.lang - The target language code for translation\n   * @param params.text - Whether to return only the text content (optional)\n   * @returns A promise that resolves to a TranslatedTranscript object\n   */\n  translate = async (\n    params: TranslateParams\n  ): Promise<TranslatedTranscript> => {\n    return this.fetch<TranslatedTranscript>(\n      '/youtube/transcript/translate',\n      params\n    );\n  };\n\n  /**\n   * Search YouTube for videos, channels, and playlists with advanced filters.\n   * @param params - Parameters for the search\n   * @param params.query - The search query string\n   * @param params.uploadDate - Filter by upload date (\"all\", \"hour\", \"today\", \"week\", \"month\", \"year\")\n   * @param params.type - Filter by content type (\"all\", \"video\", \"channel\", \"playlist\", \"movie\")\n   * @param params.duration - Filter video length (\"all\", \"short\", \"medium\", \"long\")\n   * @param params.sortBy - Sort results by (\"relevance\", \"rating\", \"date\", \"views\")\n   * @param params.features - Array of special video features\n   * @param params.limit - Maximum results to return\n   * @param params.nextPageToken - Token for pagination\n   * @returns A promise that resolves to a YoutubeSearchResponse object\n   */\n  search = async (\n    params: YoutubeSearchParams\n  ): Promise<YoutubeSearchResponse> => {\n    if (!params.query) {\n      throw new SupadataError({\n        error: 'invalid-request',\n        message: 'Missing query parameter',\n        details: 'The query parameter is required for search.',\n      });\n    }\n\n    this.validateLimit(params, 1, 5000, 'search');\n\n    return this.fetch<YoutubeSearchResponse>('/youtube/search', params);\n  };\n\n  private validateLimit(\n    params: { limit?: number },\n    min: number = 1,\n    max: number = 5000,\n    operation: string = 'operation'\n  ) {\n    if (\n      params.limit != undefined &&\n      params.limit != null &&\n      (params.limit < min || params.limit > max)\n    ) {\n      throw new SupadataError({\n        error: 'invalid-request',\n        message: `Invalid limit for ${operation}.`,\n        details: `The limit must be between ${min} and ${max}.`,\n      });\n    }\n  }\n}\n","import { BaseClient } from '../client.js';\nimport { CrawlJob, CrawlRequest, JobId, Scrape, SiteMap } from '../types.js';\n\nexport class WebService extends BaseClient {\n  /**\n   * Extract content from any web page to Markdown format.\n   *\n   * @param url - URL of the webpage to scrape\n   * @returns A promise that resolves to the scraped content\n   */\n  async scrape(url: string): Promise<Scrape> {\n    return this.fetch<Scrape>('/web/scrape', { url });\n  }\n\n  /**\n   * Extract all links found on a webpage.\n   *\n   * @param url - URL of the webpage to map\n   * @returns A promise that resolves to a map of URLs found on the page\n   */\n  async map(url: string): Promise<SiteMap> {\n    return this.fetch<SiteMap>('/web/map', { url });\n  }\n\n  /**\n   * Create a crawl job to extract content from all pages on a website.\n   *\n   * @param request - Crawl request parameters\n   * @param request.url - URL of the website to crawl\n   * @param request.limit - Maximum number of pages to crawl (default: 100, max: 5000)\n   * @returns A promise that resolves to the crawl job id\n   */\n  async crawl(request: CrawlRequest): Promise<JobId> {\n    return this.fetch<JobId>('/web/crawl', request, 'POST');\n  }\n\n  /**\n   * Get the status and results of a crawl job.\n   * Automatically handles pagination to retrieve all pages from the crawl.\n   *\n   * @param jobId - The ID of the crawl job to retrieve\n   * @returns A promise that resolves to the complete crawl job results\n   */\n  async getCrawlResults(jobId: string): Promise<CrawlJob> {\n    let response: CrawlJob;\n    let pages: Scrape[] = [];\n    let nextUrl: string | undefined;\n\n    do {\n      response = await (nextUrl\n        ? this.fetchUrl<CrawlJob>(nextUrl)\n        : this.fetch<CrawlJob>(`/web/crawl/${jobId}`));\n\n      if (response.pages) {\n        pages = [...pages, ...response.pages];\n      }\n      nextUrl = response.next;\n    } while (nextUrl);\n\n    return response;\n  }\n}\n","import { BaseClient } from '../client.js';\nimport {\n  JobId,\n  JobResult,\n  SupadataError,\n  Transcript,\n  TranscriptOrJobId,\n} from '../types.js';\n\nexport interface GeneralTranscriptParams {\n  url: string;\n  lang?: string;\n  text?: boolean;\n  chunkSize?: number;\n  mode?: 'native' | 'auto' | 'generate';\n}\n\nexport class TranscriptService extends BaseClient {\n  /**\n   * Get transcript from a supported video platform or file URL.\n   * @param params - Parameters for fetching the transcript\n   * @returns A promise that resolves to either a Transcript or JobId for async processing\n   */\n  get = async (params: GeneralTranscriptParams): Promise<TranscriptOrJobId> => {\n    return this.fetch<TranscriptOrJobId>('/transcript', params);\n  };\n\n  /**\n   * Get results for a transcript job by job ID.\n   * @param jobId - The ID of the transcript job\n   * @returns A promise that resolves to the job result containing status and transcript if completed\n   * @throws {SupadataError} If jobId is not provided\n   */\n  getJobStatus = async (jobId: string): Promise<JobResult<Transcript>> => {\n    if (!jobId) {\n      throw new SupadataError({\n        error: 'invalid-request',\n        message: 'Missing jobId',\n        details:\n          'The jobId parameter is required to get transcript job status.',\n      });\n    }\n    return this.fetch<JobResult<Transcript>>(`/transcript/${jobId}`);\n  };\n}\n","import {\n  JobResult,\n  Metadata,\n  SupadataConfig,\n  Transcript,\n  TranscriptOrJobId,\n} from './types.js';\nimport { YouTubeService } from './services/youtube.js';\nimport { WebService } from './services/web.js';\nimport {\n  TranscriptService,\n  GeneralTranscriptParams,\n} from './services/transcript.js';\nimport { BaseClient } from './client.js';\n\nexport * from './types.js';\nexport * from './client.js';\nexport * from './services/youtube.js';\nexport * from './services/web.js';\nexport {\n  TranscriptService,\n  GeneralTranscriptParams,\n} from './services/transcript.js';\n\nexport interface MetadataParams {\n  url: string;\n}\n\nexport class Supadata extends BaseClient {\n  readonly youtube: YouTubeService;\n  readonly web: WebService;\n  private _transcriptService: TranscriptService;\n\n  constructor(config: SupadataConfig) {\n    super(config);\n    this.youtube = new YouTubeService(config);\n    this.web = new WebService(config);\n    this._transcriptService = new TranscriptService(config);\n  }\n\n  /**\n   * Get transcript from a supported video platform (YouTube, TikTok, Instagram, Twitter) or file URL.\n   * If the video is too large to return transcript immediately, request returns a job ID.\n   */\n  transcript = Object.assign(\n    async (params: GeneralTranscriptParams): Promise<TranscriptOrJobId> => {\n      return this._transcriptService.get(params);\n    },\n    {\n      getJobStatus: (jobId: string): Promise<JobResult<Transcript>> => {\n        return this._transcriptService.getJobStatus(jobId);\n      },\n    }\n  );\n\n  /**\n   * Get metadata from any supported platform (YouTube, TikTok, Instagram, Twitter).\n   * @param params - Parameters for fetching metadata\n   * @param params.url - Media URL from YouTube, TikTok, Instagram, or Twitter\n   * @returns A promise that resolves to a Metadata object\n   */\n  metadata = async (params: MetadataParams): Promise<Metadata> => {\n    return this.fetch<Metadata>('/metadata', params);\n  };\n}\n"]}