@supadata/js 1.0.6 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -57,7 +57,7 @@ const channel: YoutubeChannel = await supadata.youtube.channel({
57
57
  // Get a list of video IDs from a YouTube channel
58
58
  const channelVideos: VideoIds = await supadata.youtube.channel.videos({
59
59
  id: 'https://youtube.com/@RickAstleyVEVO', // can be url, channel id, handle
60
- type: 'all', // 'video', 'short', 'all'
60
+ type: 'all', // 'video', 'short', 'live', 'all'
61
61
  limit: 10,
62
62
  });
63
63
 
@@ -72,6 +72,34 @@ const playlistVideos: VideoIds = await supadata.youtube.playlist.videos({
72
72
  limit: 10,
73
73
  });
74
74
 
75
+ // Start a YouTube transcript batch job
76
+ const transcriptBatch = await supadata.youtube.transcript.batch({
77
+ videoIds: ['dQw4w9WgXcQ', 'xvFZjo5PgG0'],
78
+ // playlistId: 'PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc' // alternatively
79
+ // channelId: 'UC_9-kyTW8ZkZNDHQJ6FgpwQ' // alternatively
80
+ lang: 'en',
81
+ });
82
+ console.log(`Started transcript batch job: ${transcriptBatch.jobId}`);
83
+
84
+ // Start a YouTube video metadata batch job
85
+ const videoBatch = await supadata.youtube.video.batch({
86
+ videoIds: ['dQw4w9WgXcQ', 'xvFZjo5PgG0', 'L_jWHffIx5E'],
87
+ // playlistId: 'PLlaN88a7y2_plecYoJxvRFTLHVbIVAOoc' // alternatively
88
+ // channelId: 'UC_9-kyTW8ZkZNDHQJ6FgpwQ' // alternatively
89
+ });
90
+ console.log(`Started video batch job: ${videoBatch.jobId}`);
91
+
92
+ // Get results for a batch job (poll until status is 'completed' or 'failed')
93
+ const batchResults = await supadata.youtube.batch.getBatchResults(
94
+ transcriptBatch.jobId
95
+ ); // or videoBatch.jobId
96
+ if (batchResults.status === 'completed') {
97
+ console.log('Batch job completed:', batchResults.results);
98
+ console.log('Stats:', batchResults.stats);
99
+ } else {
100
+ console.log('Batch job status:', batchResults.status);
101
+ }
102
+
75
103
  // Scrape web content
76
104
  const webContent: Scrape = await supadata.web.scrape('https://supadata.ai');
77
105
 
package/dist/index.cjs CHANGED
@@ -1,3 +1,3 @@
1
- 'use strict';var t=class extends Error{error;details;documentationUrl;constructor(e){super(e.message||"An unexpected error occurred"),this.error=e.error||"internal-error",this.details=e.details||"An unexpected error occurred",this.documentationUrl=e.documentationUrl||"",this.name="SupadataError";}};var d={403:{error:"invalid-request",message:"Invalid or missing API key",details:"Please ensure you have provided a valid API key"},404:{error:"invalid-request",message:"Endpoint does not exist",details:"The API endpoint you are trying to access does not exist"},429:{error:"limit-exceeded",message:"Limit exceeded",details:"You have exceeded the allowed request rate or quota limits"}},f=(n,e)=>n in d?new t({...d[n],message:d[n].message,details:e||d[n].details}):new t({error:"internal-error",message:"An unexpected error occurred",details:e});var c=class{config;constructor(e){this.config=e;}async fetch(e,r={},s="GET"){let i=`${this.config.baseUrl||"https://api.supadata.ai/v1"}${e.startsWith("/")?e:`/${e}`}`;if(s==="GET"&&Object.keys(r).length>0){let l=new URLSearchParams;Object.entries(r).forEach(([o,g])=>{g!=null&&l.append(o,String(g));}),i+=`?${l.toString()}`;}return this.fetchUrl(i,s,r)}async fetchUrl(e,r="GET",s){let a={method:r,headers:{"x-api-key":this.config.apiKey,"Content-Type":"application/json"}};r==="POST"&&s&&(a.body=JSON.stringify(s));let i=await fetch(e,a),l=i.headers.get("content-type");if(!i.ok){if([403,404,429].includes(i.status)){let o=await i.json();throw f(i.status,o.message)}if(l?.includes("application/json")){let o=await i.json();throw new t(o)}else throw new t({error:"internal-error",message:"Unexpected error response format",details:await i.text()})}try{if(!l?.includes("application/json"))throw new t({error:"internal-error",message:"Invalid response format",details:"Expected JSON response but received different content type"});return await i.json()}catch(o){throw new t({error:"internal-error",message:"Failed to parse response",details:o instanceof Error?o.message:"Unknown error"})}}};var p=class extends c{async transcript(e){return this.fetch("/youtube/transcript",e)}async translate(e){return this.fetch("/youtube/transcript/translate",e)}async video(e){return this.fetch("/youtube/video",e)}channel=Object.assign(async e=>this.fetch("/youtube/channel",e),{videos:async e=>(this.validateLimit(e),this.fetch("/youtube/channel/videos",e))});playlist=Object.assign(async e=>this.fetch("/youtube/playlist",e),{videos:async e=>(this.validateLimit(e),this.fetch("/youtube/playlist/videos",e))});validateLimit(e){if(e.limit!=null&&e.limit!=null&&(e.limit<1||e.limit>5e3))throw new t({error:"invalid-request",message:"Invalid limit.",details:"The limit must be between 1 and 5000."})}};var m=class extends c{async scrape(e){return this.fetch("/web/scrape",{url:e})}async map(e){return this.fetch("/web/map",{url:e})}async crawl(e){return this.fetch("/web/crawl",e,"POST")}async getCrawlResults(e){let r,s=[],a;do r=await(a?this.fetchUrl(a):this.fetch(`/web/crawl/${e}`)),r.pages&&(s=[...s,...r.pages]),a=r.next;while(a);return r}};var h=class{youtube;web;constructor(e){this.youtube=new p(e),this.web=new m(e);}};
2
- exports.BaseClient=c;exports.Supadata=h;exports.SupadataError=t;exports.WebService=m;exports.YouTubeService=p;//# sourceMappingURL=index.cjs.map
1
+ 'use strict';var t=class extends Error{error;details;documentationUrl;constructor(e){super(e.message||"An unexpected error occurred"),this.error=e.error||"internal-error",this.details=e.details||"An unexpected error occurred",this.documentationUrl=e.documentationUrl||"",this.name="SupadataError";}};var d={403:{error:"invalid-request",message:"Invalid or missing API key",details:"Please ensure you have provided a valid API key"},404:{error:"invalid-request",message:"Endpoint does not exist",details:"The API endpoint you are trying to access does not exist"},429:{error:"limit-exceeded",message:"Limit exceeded",details:"You have exceeded the allowed request rate or quota limits"}},g=(s,e)=>s in d?new t({...d[s],message:d[s].message,details:e||d[s].details}):new t({error:"internal-error",message:"An unexpected error occurred",details:e});var u=class{config;constructor(e){this.config=e;}async fetch(e,r={},a="GET"){let i=`${this.config.baseUrl||"https://api.supadata.ai/v1"}${e.startsWith("/")?e:`/${e}`}`;if(a==="GET"&&Object.keys(r).length>0){let c=new URLSearchParams;Object.entries(r).forEach(([o,b])=>{b!=null&&c.append(o,String(b));}),i+=`?${c.toString()}`;}return this.fetchUrl(i,a,r)}async fetchUrl(e,r="GET",a){let n={method:r,headers:{"x-api-key":this.config.apiKey,"Content-Type":"application/json"}};r==="POST"&&a&&(n.body=JSON.stringify(a));let i=await fetch(e,n),c=i.headers.get("content-type");if(!i.ok){if([403,404,429].includes(i.status)){let o=await i.json();throw g(i.status,o.message)}if(c?.includes("application/json")){let o=await i.json();throw new t(o)}else throw new t({error:"internal-error",message:"Unexpected error response format",details:await i.text()})}try{if(!c?.includes("application/json"))throw new t({error:"internal-error",message:"Invalid response format",details:"Expected JSON response but received different content type"});return await i.json()}catch(o){throw new t({error:"internal-error",message:"Failed to parse response",details:o instanceof Error?o.message:"Unknown error"})}}};var p=class extends u{transcript=Object.assign(async e=>this.fetch("/youtube/transcript",e),{batch:async e=>(this.validateBatchLimit(e),this.fetch("/youtube/transcript/batch",e,"POST"))});video=Object.assign(async e=>this.fetch("/youtube/video",e),{batch:async e=>(this.validateBatchLimit(e),this.fetch("/youtube/video/batch",e,"POST"))});channel=Object.assign(async e=>this.fetch("/youtube/channel",e),{videos:async e=>(this.validateLimit(e),this.fetch("/youtube/channel/videos",e))});playlist=Object.assign(async e=>this.fetch("/youtube/playlist",e),{videos:async e=>(this.validateLimit(e),this.fetch("/youtube/playlist/videos",e))});batch={getBatchResults:async e=>{if(!e)throw new t({error:"missing-parameters",message:"Missing jobId",details:"The jobId parameter is required to get batch results."});return this.fetch(`/youtube/batch/${e}`)}};translate=async e=>this.fetch("/youtube/transcript/translate",e);validateLimit(e){if(e.limit!=null&&e.limit!=null&&(e.limit<1||e.limit>5e3))throw new t({error:"invalid-request",message:"Invalid limit.",details:"The limit must be between 1 and 5000."})}validateBatchLimit(e){if(e.limit!=null&&e.limit!=null&&(e.limit<1||e.limit>5e3))throw new t({error:"invalid-request",message:"Invalid limit for batch operation.",details:"The limit must be between 1 and 5000."})}};var m=class extends u{async scrape(e){return this.fetch("/web/scrape",{url:e})}async map(e){return this.fetch("/web/map",{url:e})}async crawl(e){return this.fetch("/web/crawl",e,"POST")}async getCrawlResults(e){let r,a=[],n;do r=await(n?this.fetchUrl(n):this.fetch(`/web/crawl/${e}`)),r.pages&&(a=[...a,...r.pages]),n=r.next;while(n);return r}};var h=class{youtube;web;constructor(e){this.youtube=new p(e),this.web=new m(e);}};
2
+ exports.BaseClient=u;exports.Supadata=h;exports.SupadataError=t;exports.WebService=m;exports.YouTubeService=p;//# sourceMappingURL=index.cjs.map
3
3
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/gateway-error-mapper.ts","../src/client.ts","../src/services/youtube.ts","../src/services/web.ts","../src/index.ts"],"names":["SupadataError","error","GATEWAY_STATUS_ERRORS","mapGatewayError","statusCode","errorText","BaseClient","config","endpoint","params","method","url","queryParams","key","value","body","options","response","contentType","errorData","YouTubeService","WebService","request","jobId","pages","nextUrl","Supadata"],"mappings":"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","file":"index.cjs","sourcesContent":["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 Crawl {\n jobId: string;\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 | 'missing-parameters'\n | 'internal-error'\n | 'transcript-unavailable'\n | 'video-not-found'\n | 'video-id-invalid'\n | 'youtube-api-error'\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","import { SupadataError } from './types';\n\n/*\nThe API gateway returns errors in text/plain content type. \nAs a temporary workaround we're mapping them to SupadataError.\n*/\n\nconst GATEWAY_STATUS_ERRORS = {\n 403: {\n error: 'invalid-request' as const,\n message: 'Invalid or missing API key',\n details: 'Please ensure you have provided a valid API key',\n },\n 404: {\n error: 'invalid-request' as const,\n message: 'Endpoint does not exist',\n details: 'The API endpoint you are trying to access does not exist',\n },\n 429: {\n error: 'limit-exceeded' as const,\n message: 'Limit exceeded',\n details: 'You have exceeded the allowed request rate or quota limits',\n },\n};\n\nexport const mapGatewayError = (\n statusCode: number,\n errorText: string\n): SupadataError => {\n if (statusCode in GATEWAY_STATUS_ERRORS) {\n return new SupadataError({\n ...GATEWAY_STATUS_ERRORS[\n statusCode as keyof typeof GATEWAY_STATUS_ERRORS\n ],\n message:\n GATEWAY_STATUS_ERRORS[statusCode as keyof typeof GATEWAY_STATUS_ERRORS]\n .message,\n details:\n errorText ||\n GATEWAY_STATUS_ERRORS[statusCode as keyof typeof GATEWAY_STATUS_ERRORS]\n .details,\n });\n }\n\n // Default error if status code is not recognized\n return new SupadataError({\n error: 'internal-error',\n message: 'An unexpected error occurred',\n details: errorText,\n });\n};\n","import { SupadataConfig, SupadataError } from './types.js';\nimport { mapGatewayError } from './gateway-error-mapper.js';\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 queryParams.append(key, String(value));\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 },\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 // First check for gateway-specific status codes\n if ([403, 404, 429].includes(response.status)) {\n const errorData = await response.json();\n throw mapGatewayError(response.status, errorData.message);\n }\n\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 YoutubeChannel,\n YoutubePlaylist,\n YoutubeVideo,\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' | 'all';\n}\n\nexport interface PlaylistVideosParams extends ResourceParams {\n limit?: number;\n}\n\nexport interface VideoIds {\n videoIds: string[];\n shortIds: string[];\n}\n\nexport class YouTubeService extends BaseClient {\n /**\n * Fetches a transcript for a YouTube video.\n *\n * @param params - Parameters for fetching the transcript\n * @param params.videoId - The YouTube video ID (provide either this OR url)\n * @param params.url - The YouTube video URL (provide either this OR videoId)\n * @param params.lang - Optional language code for the transcript\n * @param params.text - Optional flag to return plain text instead of timestamped list\n * @returns A promise that resolves to the video transcript\n */\n async transcript(params: TranscriptParams): Promise<Transcript> {\n return this.fetch<Transcript>('/youtube/transcript', params);\n }\n\n /**\n * Translates a YouTube video transcript to a specified language.\n *\n * @param params - Parameters for translating the transcript\n * @param params.videoId - The YouTube video ID (provide either this OR url)\n * @param params.url - The YouTube video URL (provide either this OR videoId)\n * @param params.lang - The target language code for translation\n * @param params.text - Optional flag to return plain text instead of timestamped list\n * @returns A promise that resolves to the translated transcript\n */\n async translate(params: TranslateParams): Promise<TranslatedTranscript> {\n return this.fetch<TranslatedTranscript>(\n '/youtube/transcript/translate',\n params\n );\n }\n\n /**\n * Fetches a YouTube video based on the provided parameters.\n *\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 */\n async video(params: ResourceParams): Promise<YoutubeVideo> {\n return this.fetch<YoutubeVideo>('/youtube/video', params);\n }\n\n /**\n * Fetches YouTube channel information and videos.\n *\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 * @property videos - Fetches the videos of the 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.\n * Default: 30. Max: 5000.\n * @param params.type - The type of videos to fetch.\n * Default: 'video'.\n * Allowed values: 'video', 'short', 'all'.\n * @returns A promise that resolves to an array of video IDs.\n *\n * @throws {SupadataError} If the limit is invalid (less than 1 or greater than 5000).\n */\n channel = Object.assign(\n async (params: ResourceParams): Promise<YoutubeChannel> => {\n return this.fetch<YoutubeChannel>('/youtube/channel', params);\n },\n {\n videos: async (params: ChannelVideosParams): Promise<VideoIds> => {\n // Validate the limit locally to avoid unnecessary API calls.\n this.validateLimit(params);\n return this.fetch<VideoIds>('/youtube/channel/videos', params);\n },\n }\n );\n\n /**\n * Fetches a YouTube playlist and its videos.\n *\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 * @property videos - 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.\n * Default: 30. Max: 5000.\n * @returns A promise that resolves to an array of video IDs.\n *\n * @throws {SupadataError} If the limit is invalid (less than 1 or greater than 5000).\n */\n playlist = Object.assign(\n async (params: ResourceParams): Promise<YoutubePlaylist> => {\n return this.fetch<YoutubePlaylist>('/youtube/playlist', params);\n },\n {\n videos: async (params: PlaylistVideosParams): Promise<VideoIds> => {\n // Validate the limit locally to avoid unnecessary API calls.\n this.validateLimit(params);\n return this.fetch<VideoIds>('/youtube/playlist/videos', params);\n },\n }\n );\n\n private validateLimit(params: { limit?: number }) {\n if (\n params.limit != undefined &&\n params.limit != null &&\n (params.limit < 1 || params.limit > 5000)\n ) {\n throw new SupadataError({\n error: 'invalid-request',\n message: 'Invalid limit.',\n details: 'The limit must be between 1 and 5000.',\n });\n }\n }\n}\n","import { BaseClient } from '../client.js';\nimport { Crawl, CrawlJob, CrawlRequest, 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<Crawl> {\n return this.fetch<Crawl>('/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 { SupadataConfig } from './types.js';\nimport { YouTubeService } from './services/youtube.js';\nimport { WebService } from './services/web.js';\n\nexport * from './types.js';\nexport * from './client.js';\nexport * from './services/youtube.js';\nexport * from './services/web.js';\n\nexport class Supadata {\n readonly youtube: YouTubeService;\n readonly web: WebService;\n\n constructor(config: SupadataConfig) {\n this.youtube = new YouTubeService(config);\n this.web = new WebService(config);\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/types.ts","../src/gateway-error-mapper.ts","../src/client.ts","../src/services/youtube.ts","../src/services/web.ts","../src/index.ts"],"names":["SupadataError","error","GATEWAY_STATUS_ERRORS","mapGatewayError","statusCode","errorText","BaseClient","config","endpoint","params","method","url","queryParams","key","value","body","options","response","contentType","errorData","YouTubeService","jobId","WebService","request","pages","nextUrl","Supadata"],"mappings":"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","file":"index.cjs","sourcesContent":["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 Crawl {\n jobId: string;\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 | 'missing-parameters'\n | 'internal-error'\n | 'transcript-unavailable'\n | 'video-not-found'\n | 'video-id-invalid'\n | 'youtube-api-error'\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 YoutubeBatchJob {\n jobId: string;\n}\n\nexport type YoutubeBatchJobStatus =\n | 'queued'\n | 'active'\n | 'completed'\n | 'failed';\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","import { SupadataError } from './types';\n\n/*\nThe API gateway returns errors in text/plain content type. \nAs a temporary workaround we're mapping them to SupadataError.\n*/\n\nconst GATEWAY_STATUS_ERRORS = {\n 403: {\n error: 'invalid-request' as const,\n message: 'Invalid or missing API key',\n details: 'Please ensure you have provided a valid API key',\n },\n 404: {\n error: 'invalid-request' as const,\n message: 'Endpoint does not exist',\n details: 'The API endpoint you are trying to access does not exist',\n },\n 429: {\n error: 'limit-exceeded' as const,\n message: 'Limit exceeded',\n details: 'You have exceeded the allowed request rate or quota limits',\n },\n};\n\nexport const mapGatewayError = (\n statusCode: number,\n errorText: string\n): SupadataError => {\n if (statusCode in GATEWAY_STATUS_ERRORS) {\n return new SupadataError({\n ...GATEWAY_STATUS_ERRORS[\n statusCode as keyof typeof GATEWAY_STATUS_ERRORS\n ],\n message:\n GATEWAY_STATUS_ERRORS[statusCode as keyof typeof GATEWAY_STATUS_ERRORS]\n .message,\n details:\n errorText ||\n GATEWAY_STATUS_ERRORS[statusCode as keyof typeof GATEWAY_STATUS_ERRORS]\n .details,\n });\n }\n\n // Default error if status code is not recognized\n return new SupadataError({\n error: 'internal-error',\n message: 'An unexpected error occurred',\n details: errorText,\n });\n};\n","import { SupadataConfig, SupadataError } from './types.js';\nimport { mapGatewayError } from './gateway-error-mapper.js';\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 queryParams.append(key, String(value));\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 },\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 // First check for gateway-specific status codes\n if ([403, 404, 429].includes(response.status)) {\n const errorData = await response.json();\n throw mapGatewayError(response.status, errorData.message);\n }\n\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} 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 */\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 */\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.validateBatchLimit(params);\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 */\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 */\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.validateBatchLimit(params);\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: 'missing-parameters',\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 private validateLimit(params: { limit?: number }) {\n if (\n params.limit != undefined &&\n params.limit != null &&\n (params.limit < 1 || params.limit > 5000)\n ) {\n throw new SupadataError({\n error: 'invalid-request',\n message: 'Invalid limit.',\n details: 'The limit must be between 1 and 5000.',\n });\n }\n }\n\n // Add a specific validator for batch limits as per documentation (Max: 5000, Default: 10)\n private validateBatchLimit(params: { limit?: number }) {\n if (\n params.limit != undefined &&\n params.limit != null &&\n (params.limit < 1 || params.limit > 5000)\n ) {\n throw new SupadataError({\n error: 'invalid-request',\n message: 'Invalid limit for batch operation.',\n details: 'The limit must be between 1 and 5000.',\n });\n }\n }\n}\n","import { BaseClient } from '../client.js';\nimport { Crawl, CrawlJob, CrawlRequest, 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<Crawl> {\n return this.fetch<Crawl>('/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 { SupadataConfig } from './types.js';\nimport { YouTubeService } from './services/youtube.js';\nimport { WebService } from './services/web.js';\n\nexport * from './types.js';\nexport * from './client.js';\nexport * from './services/youtube.js';\nexport * from './services/web.js';\n\nexport class Supadata {\n readonly youtube: YouTubeService;\n readonly web: WebService;\n\n constructor(config: SupadataConfig) {\n this.youtube = new YouTubeService(config);\n this.web = new WebService(config);\n }\n}\n"]}
package/dist/index.d.mts CHANGED
@@ -87,6 +87,39 @@ interface YoutubePlaylist {
87
87
  description: string;
88
88
  thumbnail: string;
89
89
  }
90
+ interface YoutubeBatchSource {
91
+ videoIds?: string[];
92
+ playlistId?: string;
93
+ channelId?: string;
94
+ limit?: number;
95
+ }
96
+ interface YoutubeTranscriptBatchRequest extends YoutubeBatchSource {
97
+ lang?: string;
98
+ text?: boolean;
99
+ }
100
+ interface YoutubeVideoBatchRequest extends YoutubeBatchSource {
101
+ }
102
+ interface YoutubeBatchJob {
103
+ jobId: string;
104
+ }
105
+ type YoutubeBatchJobStatus = 'queued' | 'active' | 'completed' | 'failed';
106
+ interface YoutubeBatchResultItem {
107
+ videoId: string;
108
+ transcript?: Transcript;
109
+ video?: YoutubeVideo;
110
+ errorCode?: string;
111
+ }
112
+ interface YoutubeBatchStats {
113
+ total: number;
114
+ succeeded: number;
115
+ failed: number;
116
+ }
117
+ interface YoutubeBatchResults {
118
+ status: YoutubeBatchJobStatus;
119
+ results?: YoutubeBatchResultItem[];
120
+ stats?: YoutubeBatchStats;
121
+ completedAt?: string;
122
+ }
90
123
 
91
124
  declare class BaseClient {
92
125
  protected config: SupadataConfig;
@@ -123,7 +156,7 @@ interface ResourceParams {
123
156
  }
124
157
  interface ChannelVideosParams extends ResourceParams {
125
158
  limit?: number;
126
- type?: 'video' | 'short' | 'all';
159
+ type?: 'video' | 'short' | 'live' | 'all';
127
160
  }
128
161
  interface PlaylistVideosParams extends ResourceParams {
129
162
  limit?: number;
@@ -131,80 +164,90 @@ interface PlaylistVideosParams extends ResourceParams {
131
164
  interface VideoIds {
132
165
  videoIds: string[];
133
166
  shortIds: string[];
167
+ liveIds: string[];
134
168
  }
135
169
  declare class YouTubeService extends BaseClient {
136
170
  /**
137
- * Fetches a transcript for a YouTube video.
138
- *
139
- * @param params - Parameters for fetching the transcript
140
- * @param params.videoId - The YouTube video ID (provide either this OR url)
141
- * @param params.url - The YouTube video URL (provide either this OR videoId)
142
- * @param params.lang - Optional language code for the transcript
143
- * @param params.text - Optional flag to return plain text instead of timestamped list
144
- * @returns A promise that resolves to the video transcript
145
- */
146
- transcript(params: TranscriptParams): Promise<Transcript>;
147
- /**
148
- * Translates a YouTube video transcript to a specified language.
149
- *
150
- * @param params - Parameters for translating the transcript
151
- * @param params.videoId - The YouTube video ID (provide either this OR url)
152
- * @param params.url - The YouTube video URL (provide either this OR videoId)
153
- * @param params.lang - The target language code for translation
154
- * @param params.text - Optional flag to return plain text instead of timestamped list
155
- * @returns A promise that resolves to the translated transcript
171
+ * Handles YouTube Transcript operations.
156
172
  */
157
- translate(params: TranslateParams): Promise<TranslatedTranscript>;
173
+ transcript: ((params: TranscriptParams) => Promise<Transcript>) & {
174
+ /**
175
+ * Batch fetches transcripts for multiple YouTube videos.
176
+ * @param params - Parameters for the transcript batch job
177
+ * @param params.videoIds - Array of YouTube video IDs to fetch transcripts for
178
+ * @param params.lang - The language code for the transcripts (optional)
179
+ * @param params.limit - Maximum number of videos to process (optional, default: 10, max: 5000)
180
+ * @param params.text - Whether to return only the text content (optional)
181
+ * @returns A promise that resolves to a YoutubeBatchJob object with the job ID
182
+ */
183
+ batch: (params: YoutubeTranscriptBatchRequest) => Promise<YoutubeBatchJob>;
184
+ };
158
185
  /**
159
- * Fetches a YouTube video based on the provided parameters.
160
- *
161
- * @param params - The parameters required to fetch the YouTube video.
162
- * @param params.id - The YouTube video ID.
163
- * @returns A promise that resolves to a `YoutubeVideo` object.
186
+ * Handles YouTube video operations.
164
187
  */
165
- video(params: ResourceParams): Promise<YoutubeVideo>;
188
+ video: ((params: ResourceParams) => Promise<YoutubeVideo>) & {
189
+ /**
190
+ * Batch fetches metadata for multiple YouTube videos.
191
+ * @param params - Parameters for the video metadata batch job
192
+ * @param params.videoIds - Array of YouTube video IDs to fetch metadata for
193
+ * @param params.limit - Maximum number of videos to process (optional, default: 10, max: 5000)
194
+ * @returns A promise that resolves to a YoutubeBatchJob object with the job ID
195
+ */
196
+ batch: (params: YoutubeVideoBatchRequest) => Promise<YoutubeBatchJob>;
197
+ };
166
198
  /**
167
- * Fetches YouTube channel information and videos.
168
- *
169
- * @param params - The parameters required to fetch the YouTube channel information.
170
- * @param params.id - The YouTube channel ID.
171
- * @returns A promise that resolves to a `YoutubeChannel` object containing the channel information.
172
- *
173
- * @property videos - Fetches the videos of the YouTube channel.
174
- * @param params - The parameters required to fetch the YouTube channel videos.
175
- * @param params.id - The YouTube channel ID.
176
- * @param params.limit - The maximum number of videos to fetch.
177
- * Default: 30. Max: 5000.
178
- * @param params.type - The type of videos to fetch.
179
- * Default: 'video'.
180
- * Allowed values: 'video', 'short', 'all'.
181
- * @returns A promise that resolves to an array of video IDs.
182
- *
183
- * @throws {SupadataError} If the limit is invalid (less than 1 or greater than 5000).
199
+ * Handles YouTube channel operations.
184
200
  */
185
201
  channel: ((params: ResourceParams) => Promise<YoutubeChannel>) & {
202
+ /**
203
+ * Fetches the videos of a YouTube channel.
204
+ * @param params - The parameters required to fetch the YouTube channel videos
205
+ * @param params.id - The YouTube channel ID
206
+ * @param params.limit - The maximum number of videos to fetch (default: 30, max: 5000)
207
+ * @param params.type - The type of videos to fetch ('video', 'short', 'live', or 'all', default: 'video')
208
+ * @returns A promise that resolves to an object containing arrays of video IDs, short IDs, and live IDs
209
+ * @throws {SupadataError} If the limit is invalid (less than 1 or greater than 5000)
210
+ */
186
211
  videos: (params: ChannelVideosParams) => Promise<VideoIds>;
187
212
  };
188
213
  /**
189
- * Fetches a YouTube playlist and its videos.
190
- *
191
- * @param params - The parameters required to fetch the playlist.
192
- * @param params.id - The YouTube playlist ID.
193
- * @returns A promise that resolves to a `YoutubePlaylist` object.
194
- *
195
- * @property videos - Fetches the videos of a YouTube playlist.
196
- * @param params - The parameters required to fetch the playlist videos.
197
- * @param params.id - The YouTube playlist ID.
198
- * @param params.limit - The maximum number of videos to fetch.
199
- * Default: 30. Max: 5000.
200
- * @returns A promise that resolves to an array of video IDs.
201
- *
202
- * @throws {SupadataError} If the limit is invalid (less than 1 or greater than 5000).
214
+ * Handles YouTube playlist operations.
203
215
  */
204
216
  playlist: ((params: ResourceParams) => Promise<YoutubePlaylist>) & {
217
+ /**
218
+ * Fetches the videos of a YouTube playlist.
219
+ * @param params - The parameters required to fetch the playlist videos
220
+ * @param params.id - The YouTube playlist ID
221
+ * @param params.limit - The maximum number of videos to fetch (default: 30, max: 5000)
222
+ * @returns A promise that resolves to an object containing arrays of video IDs, short IDs, and live IDs
223
+ * @throws {SupadataError} If the limit is invalid (less than 1 or greater than 5000)
224
+ */
205
225
  videos: (params: PlaylistVideosParams) => Promise<VideoIds>;
206
226
  };
227
+ /**
228
+ * Handles YouTube batch operations.
229
+ */
230
+ batch: {
231
+ /**
232
+ * Retrieves the status and results of a batch job.
233
+ * @param jobId - The ID of the batch job
234
+ * @returns A promise that resolves to the YoutubeBatchResults containing job status and results
235
+ * @throws {SupadataError} If jobId is not provided
236
+ */
237
+ getBatchResults: (jobId: string) => Promise<YoutubeBatchResults>;
238
+ };
239
+ /**
240
+ * Translates a YouTube video transcript to a specified language.
241
+ * @param params - Parameters for translating the transcript
242
+ * @param params.videoId - The YouTube video ID (mutually exclusive with url)
243
+ * @param params.url - The YouTube video URL (mutually exclusive with videoId)
244
+ * @param params.lang - The target language code for translation
245
+ * @param params.text - Whether to return only the text content (optional)
246
+ * @returns A promise that resolves to a TranslatedTranscript object
247
+ */
248
+ translate: (params: TranslateParams) => Promise<TranslatedTranscript>;
207
249
  private validateLimit;
250
+ private validateBatchLimit;
208
251
  }
209
252
 
210
253
  declare class WebService extends BaseClient {
@@ -247,4 +290,4 @@ declare class Supadata {
247
290
  constructor(config: SupadataConfig);
248
291
  }
249
292
 
250
- export { BaseClient, type ChannelVideosParams, type Crawl, type CrawlJob, type CrawlRequest, type PlaylistVideosParams, type ResourceParams, type Scrape, type SiteMap, Supadata, type SupadataConfig, SupadataError, type Transcript, type TranscriptChunk, type TranscriptParams, type TranslateParams, type TranslatedTranscript, type VideoIds, WebService, YouTubeService, type YoutubeChannel, type YoutubePlaylist, type YoutubeVideo };
293
+ export { BaseClient, type ChannelVideosParams, type Crawl, type CrawlJob, type CrawlRequest, type PlaylistVideosParams, type ResourceParams, type Scrape, type SiteMap, Supadata, type SupadataConfig, SupadataError, type Transcript, type TranscriptChunk, type TranscriptParams, type TranslateParams, type TranslatedTranscript, type VideoIds, WebService, YouTubeService, type YoutubeBatchJob, type YoutubeBatchJobStatus, type YoutubeBatchResultItem, type YoutubeBatchResults, type YoutubeBatchSource, type YoutubeBatchStats, type YoutubeChannel, type YoutubePlaylist, type YoutubeTranscriptBatchRequest, type YoutubeVideo, type YoutubeVideoBatchRequest };
package/dist/index.d.ts CHANGED
@@ -87,6 +87,39 @@ interface YoutubePlaylist {
87
87
  description: string;
88
88
  thumbnail: string;
89
89
  }
90
+ interface YoutubeBatchSource {
91
+ videoIds?: string[];
92
+ playlistId?: string;
93
+ channelId?: string;
94
+ limit?: number;
95
+ }
96
+ interface YoutubeTranscriptBatchRequest extends YoutubeBatchSource {
97
+ lang?: string;
98
+ text?: boolean;
99
+ }
100
+ interface YoutubeVideoBatchRequest extends YoutubeBatchSource {
101
+ }
102
+ interface YoutubeBatchJob {
103
+ jobId: string;
104
+ }
105
+ type YoutubeBatchJobStatus = 'queued' | 'active' | 'completed' | 'failed';
106
+ interface YoutubeBatchResultItem {
107
+ videoId: string;
108
+ transcript?: Transcript;
109
+ video?: YoutubeVideo;
110
+ errorCode?: string;
111
+ }
112
+ interface YoutubeBatchStats {
113
+ total: number;
114
+ succeeded: number;
115
+ failed: number;
116
+ }
117
+ interface YoutubeBatchResults {
118
+ status: YoutubeBatchJobStatus;
119
+ results?: YoutubeBatchResultItem[];
120
+ stats?: YoutubeBatchStats;
121
+ completedAt?: string;
122
+ }
90
123
 
91
124
  declare class BaseClient {
92
125
  protected config: SupadataConfig;
@@ -123,7 +156,7 @@ interface ResourceParams {
123
156
  }
124
157
  interface ChannelVideosParams extends ResourceParams {
125
158
  limit?: number;
126
- type?: 'video' | 'short' | 'all';
159
+ type?: 'video' | 'short' | 'live' | 'all';
127
160
  }
128
161
  interface PlaylistVideosParams extends ResourceParams {
129
162
  limit?: number;
@@ -131,80 +164,90 @@ interface PlaylistVideosParams extends ResourceParams {
131
164
  interface VideoIds {
132
165
  videoIds: string[];
133
166
  shortIds: string[];
167
+ liveIds: string[];
134
168
  }
135
169
  declare class YouTubeService extends BaseClient {
136
170
  /**
137
- * Fetches a transcript for a YouTube video.
138
- *
139
- * @param params - Parameters for fetching the transcript
140
- * @param params.videoId - The YouTube video ID (provide either this OR url)
141
- * @param params.url - The YouTube video URL (provide either this OR videoId)
142
- * @param params.lang - Optional language code for the transcript
143
- * @param params.text - Optional flag to return plain text instead of timestamped list
144
- * @returns A promise that resolves to the video transcript
145
- */
146
- transcript(params: TranscriptParams): Promise<Transcript>;
147
- /**
148
- * Translates a YouTube video transcript to a specified language.
149
- *
150
- * @param params - Parameters for translating the transcript
151
- * @param params.videoId - The YouTube video ID (provide either this OR url)
152
- * @param params.url - The YouTube video URL (provide either this OR videoId)
153
- * @param params.lang - The target language code for translation
154
- * @param params.text - Optional flag to return plain text instead of timestamped list
155
- * @returns A promise that resolves to the translated transcript
171
+ * Handles YouTube Transcript operations.
156
172
  */
157
- translate(params: TranslateParams): Promise<TranslatedTranscript>;
173
+ transcript: ((params: TranscriptParams) => Promise<Transcript>) & {
174
+ /**
175
+ * Batch fetches transcripts for multiple YouTube videos.
176
+ * @param params - Parameters for the transcript batch job
177
+ * @param params.videoIds - Array of YouTube video IDs to fetch transcripts for
178
+ * @param params.lang - The language code for the transcripts (optional)
179
+ * @param params.limit - Maximum number of videos to process (optional, default: 10, max: 5000)
180
+ * @param params.text - Whether to return only the text content (optional)
181
+ * @returns A promise that resolves to a YoutubeBatchJob object with the job ID
182
+ */
183
+ batch: (params: YoutubeTranscriptBatchRequest) => Promise<YoutubeBatchJob>;
184
+ };
158
185
  /**
159
- * Fetches a YouTube video based on the provided parameters.
160
- *
161
- * @param params - The parameters required to fetch the YouTube video.
162
- * @param params.id - The YouTube video ID.
163
- * @returns A promise that resolves to a `YoutubeVideo` object.
186
+ * Handles YouTube video operations.
164
187
  */
165
- video(params: ResourceParams): Promise<YoutubeVideo>;
188
+ video: ((params: ResourceParams) => Promise<YoutubeVideo>) & {
189
+ /**
190
+ * Batch fetches metadata for multiple YouTube videos.
191
+ * @param params - Parameters for the video metadata batch job
192
+ * @param params.videoIds - Array of YouTube video IDs to fetch metadata for
193
+ * @param params.limit - Maximum number of videos to process (optional, default: 10, max: 5000)
194
+ * @returns A promise that resolves to a YoutubeBatchJob object with the job ID
195
+ */
196
+ batch: (params: YoutubeVideoBatchRequest) => Promise<YoutubeBatchJob>;
197
+ };
166
198
  /**
167
- * Fetches YouTube channel information and videos.
168
- *
169
- * @param params - The parameters required to fetch the YouTube channel information.
170
- * @param params.id - The YouTube channel ID.
171
- * @returns A promise that resolves to a `YoutubeChannel` object containing the channel information.
172
- *
173
- * @property videos - Fetches the videos of the YouTube channel.
174
- * @param params - The parameters required to fetch the YouTube channel videos.
175
- * @param params.id - The YouTube channel ID.
176
- * @param params.limit - The maximum number of videos to fetch.
177
- * Default: 30. Max: 5000.
178
- * @param params.type - The type of videos to fetch.
179
- * Default: 'video'.
180
- * Allowed values: 'video', 'short', 'all'.
181
- * @returns A promise that resolves to an array of video IDs.
182
- *
183
- * @throws {SupadataError} If the limit is invalid (less than 1 or greater than 5000).
199
+ * Handles YouTube channel operations.
184
200
  */
185
201
  channel: ((params: ResourceParams) => Promise<YoutubeChannel>) & {
202
+ /**
203
+ * Fetches the videos of a YouTube channel.
204
+ * @param params - The parameters required to fetch the YouTube channel videos
205
+ * @param params.id - The YouTube channel ID
206
+ * @param params.limit - The maximum number of videos to fetch (default: 30, max: 5000)
207
+ * @param params.type - The type of videos to fetch ('video', 'short', 'live', or 'all', default: 'video')
208
+ * @returns A promise that resolves to an object containing arrays of video IDs, short IDs, and live IDs
209
+ * @throws {SupadataError} If the limit is invalid (less than 1 or greater than 5000)
210
+ */
186
211
  videos: (params: ChannelVideosParams) => Promise<VideoIds>;
187
212
  };
188
213
  /**
189
- * Fetches a YouTube playlist and its videos.
190
- *
191
- * @param params - The parameters required to fetch the playlist.
192
- * @param params.id - The YouTube playlist ID.
193
- * @returns A promise that resolves to a `YoutubePlaylist` object.
194
- *
195
- * @property videos - Fetches the videos of a YouTube playlist.
196
- * @param params - The parameters required to fetch the playlist videos.
197
- * @param params.id - The YouTube playlist ID.
198
- * @param params.limit - The maximum number of videos to fetch.
199
- * Default: 30. Max: 5000.
200
- * @returns A promise that resolves to an array of video IDs.
201
- *
202
- * @throws {SupadataError} If the limit is invalid (less than 1 or greater than 5000).
214
+ * Handles YouTube playlist operations.
203
215
  */
204
216
  playlist: ((params: ResourceParams) => Promise<YoutubePlaylist>) & {
217
+ /**
218
+ * Fetches the videos of a YouTube playlist.
219
+ * @param params - The parameters required to fetch the playlist videos
220
+ * @param params.id - The YouTube playlist ID
221
+ * @param params.limit - The maximum number of videos to fetch (default: 30, max: 5000)
222
+ * @returns A promise that resolves to an object containing arrays of video IDs, short IDs, and live IDs
223
+ * @throws {SupadataError} If the limit is invalid (less than 1 or greater than 5000)
224
+ */
205
225
  videos: (params: PlaylistVideosParams) => Promise<VideoIds>;
206
226
  };
227
+ /**
228
+ * Handles YouTube batch operations.
229
+ */
230
+ batch: {
231
+ /**
232
+ * Retrieves the status and results of a batch job.
233
+ * @param jobId - The ID of the batch job
234
+ * @returns A promise that resolves to the YoutubeBatchResults containing job status and results
235
+ * @throws {SupadataError} If jobId is not provided
236
+ */
237
+ getBatchResults: (jobId: string) => Promise<YoutubeBatchResults>;
238
+ };
239
+ /**
240
+ * Translates a YouTube video transcript to a specified language.
241
+ * @param params - Parameters for translating the transcript
242
+ * @param params.videoId - The YouTube video ID (mutually exclusive with url)
243
+ * @param params.url - The YouTube video URL (mutually exclusive with videoId)
244
+ * @param params.lang - The target language code for translation
245
+ * @param params.text - Whether to return only the text content (optional)
246
+ * @returns A promise that resolves to a TranslatedTranscript object
247
+ */
248
+ translate: (params: TranslateParams) => Promise<TranslatedTranscript>;
207
249
  private validateLimit;
250
+ private validateBatchLimit;
208
251
  }
209
252
 
210
253
  declare class WebService extends BaseClient {
@@ -247,4 +290,4 @@ declare class Supadata {
247
290
  constructor(config: SupadataConfig);
248
291
  }
249
292
 
250
- export { BaseClient, type ChannelVideosParams, type Crawl, type CrawlJob, type CrawlRequest, type PlaylistVideosParams, type ResourceParams, type Scrape, type SiteMap, Supadata, type SupadataConfig, SupadataError, type Transcript, type TranscriptChunk, type TranscriptParams, type TranslateParams, type TranslatedTranscript, type VideoIds, WebService, YouTubeService, type YoutubeChannel, type YoutubePlaylist, type YoutubeVideo };
293
+ export { BaseClient, type ChannelVideosParams, type Crawl, type CrawlJob, type CrawlRequest, type PlaylistVideosParams, type ResourceParams, type Scrape, type SiteMap, Supadata, type SupadataConfig, SupadataError, type Transcript, type TranscriptChunk, type TranscriptParams, type TranslateParams, type TranslatedTranscript, type VideoIds, WebService, YouTubeService, type YoutubeBatchJob, type YoutubeBatchJobStatus, type YoutubeBatchResultItem, type YoutubeBatchResults, type YoutubeBatchSource, type YoutubeBatchStats, type YoutubeChannel, type YoutubePlaylist, type YoutubeTranscriptBatchRequest, type YoutubeVideo, type YoutubeVideoBatchRequest };
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- var t=class extends Error{error;details;documentationUrl;constructor(e){super(e.message||"An unexpected error occurred"),this.error=e.error||"internal-error",this.details=e.details||"An unexpected error occurred",this.documentationUrl=e.documentationUrl||"",this.name="SupadataError";}};var p={403:{error:"invalid-request",message:"Invalid or missing API key",details:"Please ensure you have provided a valid API key"},404:{error:"invalid-request",message:"Endpoint does not exist",details:"The API endpoint you are trying to access does not exist"},429:{error:"limit-exceeded",message:"Limit exceeded",details:"You have exceeded the allowed request rate or quota limits"}},h=(n,e)=>n in p?new t({...p[n],message:p[n].message,details:e||p[n].details}):new t({error:"internal-error",message:"An unexpected error occurred",details:e});var c=class{config;constructor(e){this.config=e;}async fetch(e,r={},s="GET"){let i=`${this.config.baseUrl||"https://api.supadata.ai/v1"}${e.startsWith("/")?e:`/${e}`}`;if(s==="GET"&&Object.keys(r).length>0){let l=new URLSearchParams;Object.entries(r).forEach(([o,f])=>{f!=null&&l.append(o,String(f));}),i+=`?${l.toString()}`;}return this.fetchUrl(i,s,r)}async fetchUrl(e,r="GET",s){let a={method:r,headers:{"x-api-key":this.config.apiKey,"Content-Type":"application/json"}};r==="POST"&&s&&(a.body=JSON.stringify(s));let i=await fetch(e,a),l=i.headers.get("content-type");if(!i.ok){if([403,404,429].includes(i.status)){let o=await i.json();throw h(i.status,o.message)}if(l?.includes("application/json")){let o=await i.json();throw new t(o)}else throw new t({error:"internal-error",message:"Unexpected error response format",details:await i.text()})}try{if(!l?.includes("application/json"))throw new t({error:"internal-error",message:"Invalid response format",details:"Expected JSON response but received different content type"});return await i.json()}catch(o){throw new t({error:"internal-error",message:"Failed to parse response",details:o instanceof Error?o.message:"Unknown error"})}}};var m=class extends c{async transcript(e){return this.fetch("/youtube/transcript",e)}async translate(e){return this.fetch("/youtube/transcript/translate",e)}async video(e){return this.fetch("/youtube/video",e)}channel=Object.assign(async e=>this.fetch("/youtube/channel",e),{videos:async e=>(this.validateLimit(e),this.fetch("/youtube/channel/videos",e))});playlist=Object.assign(async e=>this.fetch("/youtube/playlist",e),{videos:async e=>(this.validateLimit(e),this.fetch("/youtube/playlist/videos",e))});validateLimit(e){if(e.limit!=null&&e.limit!=null&&(e.limit<1||e.limit>5e3))throw new t({error:"invalid-request",message:"Invalid limit.",details:"The limit must be between 1 and 5000."})}};var g=class extends c{async scrape(e){return this.fetch("/web/scrape",{url:e})}async map(e){return this.fetch("/web/map",{url:e})}async crawl(e){return this.fetch("/web/crawl",e,"POST")}async getCrawlResults(e){let r,s=[],a;do r=await(a?this.fetchUrl(a):this.fetch(`/web/crawl/${e}`)),r.pages&&(s=[...s,...r.pages]),a=r.next;while(a);return r}};var b=class{youtube;web;constructor(e){this.youtube=new m(e),this.web=new g(e);}};
2
- export{c as BaseClient,b as Supadata,t as SupadataError,g as WebService,m as YouTubeService};//# sourceMappingURL=index.mjs.map
1
+ var t=class extends Error{error;details;documentationUrl;constructor(e){super(e.message||"An unexpected error occurred"),this.error=e.error||"internal-error",this.details=e.details||"An unexpected error occurred",this.documentationUrl=e.documentationUrl||"",this.name="SupadataError";}};var p={403:{error:"invalid-request",message:"Invalid or missing API key",details:"Please ensure you have provided a valid API key"},404:{error:"invalid-request",message:"Endpoint does not exist",details:"The API endpoint you are trying to access does not exist"},429:{error:"limit-exceeded",message:"Limit exceeded",details:"You have exceeded the allowed request rate or quota limits"}},h=(s,e)=>s in p?new t({...p[s],message:p[s].message,details:e||p[s].details}):new t({error:"internal-error",message:"An unexpected error occurred",details:e});var u=class{config;constructor(e){this.config=e;}async fetch(e,r={},a="GET"){let i=`${this.config.baseUrl||"https://api.supadata.ai/v1"}${e.startsWith("/")?e:`/${e}`}`;if(a==="GET"&&Object.keys(r).length>0){let c=new URLSearchParams;Object.entries(r).forEach(([o,g])=>{g!=null&&c.append(o,String(g));}),i+=`?${c.toString()}`;}return this.fetchUrl(i,a,r)}async fetchUrl(e,r="GET",a){let n={method:r,headers:{"x-api-key":this.config.apiKey,"Content-Type":"application/json"}};r==="POST"&&a&&(n.body=JSON.stringify(a));let i=await fetch(e,n),c=i.headers.get("content-type");if(!i.ok){if([403,404,429].includes(i.status)){let o=await i.json();throw h(i.status,o.message)}if(c?.includes("application/json")){let o=await i.json();throw new t(o)}else throw new t({error:"internal-error",message:"Unexpected error response format",details:await i.text()})}try{if(!c?.includes("application/json"))throw new t({error:"internal-error",message:"Invalid response format",details:"Expected JSON response but received different content type"});return await i.json()}catch(o){throw new t({error:"internal-error",message:"Failed to parse response",details:o instanceof Error?o.message:"Unknown error"})}}};var m=class extends u{transcript=Object.assign(async e=>this.fetch("/youtube/transcript",e),{batch:async e=>(this.validateBatchLimit(e),this.fetch("/youtube/transcript/batch",e,"POST"))});video=Object.assign(async e=>this.fetch("/youtube/video",e),{batch:async e=>(this.validateBatchLimit(e),this.fetch("/youtube/video/batch",e,"POST"))});channel=Object.assign(async e=>this.fetch("/youtube/channel",e),{videos:async e=>(this.validateLimit(e),this.fetch("/youtube/channel/videos",e))});playlist=Object.assign(async e=>this.fetch("/youtube/playlist",e),{videos:async e=>(this.validateLimit(e),this.fetch("/youtube/playlist/videos",e))});batch={getBatchResults:async e=>{if(!e)throw new t({error:"missing-parameters",message:"Missing jobId",details:"The jobId parameter is required to get batch results."});return this.fetch(`/youtube/batch/${e}`)}};translate=async e=>this.fetch("/youtube/transcript/translate",e);validateLimit(e){if(e.limit!=null&&e.limit!=null&&(e.limit<1||e.limit>5e3))throw new t({error:"invalid-request",message:"Invalid limit.",details:"The limit must be between 1 and 5000."})}validateBatchLimit(e){if(e.limit!=null&&e.limit!=null&&(e.limit<1||e.limit>5e3))throw new t({error:"invalid-request",message:"Invalid limit for batch operation.",details:"The limit must be between 1 and 5000."})}};var b=class extends u{async scrape(e){return this.fetch("/web/scrape",{url:e})}async map(e){return this.fetch("/web/map",{url:e})}async crawl(e){return this.fetch("/web/crawl",e,"POST")}async getCrawlResults(e){let r,a=[],n;do r=await(n?this.fetchUrl(n):this.fetch(`/web/crawl/${e}`)),r.pages&&(a=[...a,...r.pages]),n=r.next;while(n);return r}};var f=class{youtube;web;constructor(e){this.youtube=new m(e),this.web=new b(e);}};
2
+ export{u as BaseClient,f as Supadata,t as SupadataError,b as WebService,m as YouTubeService};//# sourceMappingURL=index.mjs.map
3
3
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/gateway-error-mapper.ts","../src/client.ts","../src/services/youtube.ts","../src/services/web.ts","../src/index.ts"],"names":["SupadataError","error","GATEWAY_STATUS_ERRORS","mapGatewayError","statusCode","errorText","BaseClient","config","endpoint","params","method","url","queryParams","key","value","body","options","response","contentType","errorData","YouTubeService","WebService","request","jobId","pages","nextUrl","Supadata"],"mappings":"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","file":"index.mjs","sourcesContent":["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 Crawl {\n jobId: string;\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 | 'missing-parameters'\n | 'internal-error'\n | 'transcript-unavailable'\n | 'video-not-found'\n | 'video-id-invalid'\n | 'youtube-api-error'\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","import { SupadataError } from './types';\n\n/*\nThe API gateway returns errors in text/plain content type. \nAs a temporary workaround we're mapping them to SupadataError.\n*/\n\nconst GATEWAY_STATUS_ERRORS = {\n 403: {\n error: 'invalid-request' as const,\n message: 'Invalid or missing API key',\n details: 'Please ensure you have provided a valid API key',\n },\n 404: {\n error: 'invalid-request' as const,\n message: 'Endpoint does not exist',\n details: 'The API endpoint you are trying to access does not exist',\n },\n 429: {\n error: 'limit-exceeded' as const,\n message: 'Limit exceeded',\n details: 'You have exceeded the allowed request rate or quota limits',\n },\n};\n\nexport const mapGatewayError = (\n statusCode: number,\n errorText: string\n): SupadataError => {\n if (statusCode in GATEWAY_STATUS_ERRORS) {\n return new SupadataError({\n ...GATEWAY_STATUS_ERRORS[\n statusCode as keyof typeof GATEWAY_STATUS_ERRORS\n ],\n message:\n GATEWAY_STATUS_ERRORS[statusCode as keyof typeof GATEWAY_STATUS_ERRORS]\n .message,\n details:\n errorText ||\n GATEWAY_STATUS_ERRORS[statusCode as keyof typeof GATEWAY_STATUS_ERRORS]\n .details,\n });\n }\n\n // Default error if status code is not recognized\n return new SupadataError({\n error: 'internal-error',\n message: 'An unexpected error occurred',\n details: errorText,\n });\n};\n","import { SupadataConfig, SupadataError } from './types.js';\nimport { mapGatewayError } from './gateway-error-mapper.js';\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 queryParams.append(key, String(value));\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 },\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 // First check for gateway-specific status codes\n if ([403, 404, 429].includes(response.status)) {\n const errorData = await response.json();\n throw mapGatewayError(response.status, errorData.message);\n }\n\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 YoutubeChannel,\n YoutubePlaylist,\n YoutubeVideo,\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' | 'all';\n}\n\nexport interface PlaylistVideosParams extends ResourceParams {\n limit?: number;\n}\n\nexport interface VideoIds {\n videoIds: string[];\n shortIds: string[];\n}\n\nexport class YouTubeService extends BaseClient {\n /**\n * Fetches a transcript for a YouTube video.\n *\n * @param params - Parameters for fetching the transcript\n * @param params.videoId - The YouTube video ID (provide either this OR url)\n * @param params.url - The YouTube video URL (provide either this OR videoId)\n * @param params.lang - Optional language code for the transcript\n * @param params.text - Optional flag to return plain text instead of timestamped list\n * @returns A promise that resolves to the video transcript\n */\n async transcript(params: TranscriptParams): Promise<Transcript> {\n return this.fetch<Transcript>('/youtube/transcript', params);\n }\n\n /**\n * Translates a YouTube video transcript to a specified language.\n *\n * @param params - Parameters for translating the transcript\n * @param params.videoId - The YouTube video ID (provide either this OR url)\n * @param params.url - The YouTube video URL (provide either this OR videoId)\n * @param params.lang - The target language code for translation\n * @param params.text - Optional flag to return plain text instead of timestamped list\n * @returns A promise that resolves to the translated transcript\n */\n async translate(params: TranslateParams): Promise<TranslatedTranscript> {\n return this.fetch<TranslatedTranscript>(\n '/youtube/transcript/translate',\n params\n );\n }\n\n /**\n * Fetches a YouTube video based on the provided parameters.\n *\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 */\n async video(params: ResourceParams): Promise<YoutubeVideo> {\n return this.fetch<YoutubeVideo>('/youtube/video', params);\n }\n\n /**\n * Fetches YouTube channel information and videos.\n *\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 * @property videos - Fetches the videos of the 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.\n * Default: 30. Max: 5000.\n * @param params.type - The type of videos to fetch.\n * Default: 'video'.\n * Allowed values: 'video', 'short', 'all'.\n * @returns A promise that resolves to an array of video IDs.\n *\n * @throws {SupadataError} If the limit is invalid (less than 1 or greater than 5000).\n */\n channel = Object.assign(\n async (params: ResourceParams): Promise<YoutubeChannel> => {\n return this.fetch<YoutubeChannel>('/youtube/channel', params);\n },\n {\n videos: async (params: ChannelVideosParams): Promise<VideoIds> => {\n // Validate the limit locally to avoid unnecessary API calls.\n this.validateLimit(params);\n return this.fetch<VideoIds>('/youtube/channel/videos', params);\n },\n }\n );\n\n /**\n * Fetches a YouTube playlist and its videos.\n *\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 * @property videos - 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.\n * Default: 30. Max: 5000.\n * @returns A promise that resolves to an array of video IDs.\n *\n * @throws {SupadataError} If the limit is invalid (less than 1 or greater than 5000).\n */\n playlist = Object.assign(\n async (params: ResourceParams): Promise<YoutubePlaylist> => {\n return this.fetch<YoutubePlaylist>('/youtube/playlist', params);\n },\n {\n videos: async (params: PlaylistVideosParams): Promise<VideoIds> => {\n // Validate the limit locally to avoid unnecessary API calls.\n this.validateLimit(params);\n return this.fetch<VideoIds>('/youtube/playlist/videos', params);\n },\n }\n );\n\n private validateLimit(params: { limit?: number }) {\n if (\n params.limit != undefined &&\n params.limit != null &&\n (params.limit < 1 || params.limit > 5000)\n ) {\n throw new SupadataError({\n error: 'invalid-request',\n message: 'Invalid limit.',\n details: 'The limit must be between 1 and 5000.',\n });\n }\n }\n}\n","import { BaseClient } from '../client.js';\nimport { Crawl, CrawlJob, CrawlRequest, 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<Crawl> {\n return this.fetch<Crawl>('/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 { SupadataConfig } from './types.js';\nimport { YouTubeService } from './services/youtube.js';\nimport { WebService } from './services/web.js';\n\nexport * from './types.js';\nexport * from './client.js';\nexport * from './services/youtube.js';\nexport * from './services/web.js';\n\nexport class Supadata {\n readonly youtube: YouTubeService;\n readonly web: WebService;\n\n constructor(config: SupadataConfig) {\n this.youtube = new YouTubeService(config);\n this.web = new WebService(config);\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/types.ts","../src/gateway-error-mapper.ts","../src/client.ts","../src/services/youtube.ts","../src/services/web.ts","../src/index.ts"],"names":["SupadataError","error","GATEWAY_STATUS_ERRORS","mapGatewayError","statusCode","errorText","BaseClient","config","endpoint","params","method","url","queryParams","key","value","body","options","response","contentType","errorData","YouTubeService","jobId","WebService","request","pages","nextUrl","Supadata"],"mappings":"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","file":"index.mjs","sourcesContent":["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 Crawl {\n jobId: string;\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 | 'missing-parameters'\n | 'internal-error'\n | 'transcript-unavailable'\n | 'video-not-found'\n | 'video-id-invalid'\n | 'youtube-api-error'\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 YoutubeBatchJob {\n jobId: string;\n}\n\nexport type YoutubeBatchJobStatus =\n | 'queued'\n | 'active'\n | 'completed'\n | 'failed';\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","import { SupadataError } from './types';\n\n/*\nThe API gateway returns errors in text/plain content type. \nAs a temporary workaround we're mapping them to SupadataError.\n*/\n\nconst GATEWAY_STATUS_ERRORS = {\n 403: {\n error: 'invalid-request' as const,\n message: 'Invalid or missing API key',\n details: 'Please ensure you have provided a valid API key',\n },\n 404: {\n error: 'invalid-request' as const,\n message: 'Endpoint does not exist',\n details: 'The API endpoint you are trying to access does not exist',\n },\n 429: {\n error: 'limit-exceeded' as const,\n message: 'Limit exceeded',\n details: 'You have exceeded the allowed request rate or quota limits',\n },\n};\n\nexport const mapGatewayError = (\n statusCode: number,\n errorText: string\n): SupadataError => {\n if (statusCode in GATEWAY_STATUS_ERRORS) {\n return new SupadataError({\n ...GATEWAY_STATUS_ERRORS[\n statusCode as keyof typeof GATEWAY_STATUS_ERRORS\n ],\n message:\n GATEWAY_STATUS_ERRORS[statusCode as keyof typeof GATEWAY_STATUS_ERRORS]\n .message,\n details:\n errorText ||\n GATEWAY_STATUS_ERRORS[statusCode as keyof typeof GATEWAY_STATUS_ERRORS]\n .details,\n });\n }\n\n // Default error if status code is not recognized\n return new SupadataError({\n error: 'internal-error',\n message: 'An unexpected error occurred',\n details: errorText,\n });\n};\n","import { SupadataConfig, SupadataError } from './types.js';\nimport { mapGatewayError } from './gateway-error-mapper.js';\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 queryParams.append(key, String(value));\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 },\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 // First check for gateway-specific status codes\n if ([403, 404, 429].includes(response.status)) {\n const errorData = await response.json();\n throw mapGatewayError(response.status, errorData.message);\n }\n\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} 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 */\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 */\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.validateBatchLimit(params);\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 */\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 */\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.validateBatchLimit(params);\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: 'missing-parameters',\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 private validateLimit(params: { limit?: number }) {\n if (\n params.limit != undefined &&\n params.limit != null &&\n (params.limit < 1 || params.limit > 5000)\n ) {\n throw new SupadataError({\n error: 'invalid-request',\n message: 'Invalid limit.',\n details: 'The limit must be between 1 and 5000.',\n });\n }\n }\n\n // Add a specific validator for batch limits as per documentation (Max: 5000, Default: 10)\n private validateBatchLimit(params: { limit?: number }) {\n if (\n params.limit != undefined &&\n params.limit != null &&\n (params.limit < 1 || params.limit > 5000)\n ) {\n throw new SupadataError({\n error: 'invalid-request',\n message: 'Invalid limit for batch operation.',\n details: 'The limit must be between 1 and 5000.',\n });\n }\n }\n}\n","import { BaseClient } from '../client.js';\nimport { Crawl, CrawlJob, CrawlRequest, 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<Crawl> {\n return this.fetch<Crawl>('/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 { SupadataConfig } from './types.js';\nimport { YouTubeService } from './services/youtube.js';\nimport { WebService } from './services/web.js';\n\nexport * from './types.js';\nexport * from './client.js';\nexport * from './services/youtube.js';\nexport * from './services/web.js';\n\nexport class Supadata {\n readonly youtube: YouTubeService;\n readonly web: WebService;\n\n constructor(config: SupadataConfig) {\n this.youtube = new YouTubeService(config);\n this.web = new WebService(config);\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supadata/js",
3
- "version": "1.0.6",
3
+ "version": "1.1.1",
4
4
  "description": "TypeScript / JavaScript SDK for Supadata API",
5
5
  "homepage": "https://supadata.ai",
6
6
  "repository": "https://github.com/supadata-ai/js",