@mks2508/bundlp 0.1.1 → 0.1.2
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/dist/index.d.mts +614 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +3072 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +18 -8
- package/dist/core/extractor.d.ts +0 -30
- package/dist/core/extractor.d.ts.map +0 -1
- package/dist/http/client.d.ts +0 -50
- package/dist/http/client.d.ts.map +0 -1
- package/dist/http/retry.d.ts +0 -22
- package/dist/http/retry.d.ts.map +0 -1
- package/dist/index.d.ts +0 -20
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -19021
- package/dist/innertube/client.d.ts +0 -62
- package/dist/innertube/client.d.ts.map +0 -1
- package/dist/player/ast/analyzer.d.ts +0 -16
- package/dist/player/ast/analyzer.d.ts.map +0 -1
- package/dist/player/ast/extractor.d.ts +0 -35
- package/dist/player/ast/extractor.d.ts.map +0 -1
- package/dist/player/ast/matchers.d.ts +0 -40
- package/dist/player/ast/matchers.d.ts.map +0 -1
- package/dist/player/cache.d.ts +0 -60
- package/dist/player/cache.d.ts.map +0 -1
- package/dist/player/player.d.ts +0 -49
- package/dist/player/player.d.ts.map +0 -1
- package/dist/po-token/botguard/challenge.d.ts +0 -22
- package/dist/po-token/botguard/challenge.d.ts.map +0 -1
- package/dist/po-token/botguard/client.d.ts +0 -25
- package/dist/po-token/botguard/client.d.ts.map +0 -1
- package/dist/po-token/cache/token-cache.d.ts +0 -24
- package/dist/po-token/cache/token-cache.d.ts.map +0 -1
- package/dist/po-token/index.d.ts +0 -14
- package/dist/po-token/index.d.ts.map +0 -1
- package/dist/po-token/manager.d.ts +0 -34
- package/dist/po-token/manager.d.ts.map +0 -1
- package/dist/po-token/minter/web-minter.d.ts +0 -20
- package/dist/po-token/minter/web-minter.d.ts.map +0 -1
- package/dist/po-token/policies.d.ts +0 -18
- package/dist/po-token/policies.d.ts.map +0 -1
- package/dist/po-token/providers/local.provider.d.ts +0 -26
- package/dist/po-token/providers/local.provider.d.ts.map +0 -1
- package/dist/po-token/providers/provider.interface.d.ts +0 -15
- package/dist/po-token/providers/provider.interface.d.ts.map +0 -1
- package/dist/po-token/types.d.ts +0 -160
- package/dist/po-token/types.d.ts.map +0 -1
- package/dist/result/index.d.ts +0 -6
- package/dist/result/index.d.ts.map +0 -1
- package/dist/result/result.types.d.ts +0 -14
- package/dist/result/result.types.d.ts.map +0 -1
- package/dist/result/result.utils.d.ts +0 -32
- package/dist/result/result.utils.d.ts.map +0 -1
- package/dist/streaming/dash/parser.d.ts +0 -37
- package/dist/streaming/dash/parser.d.ts.map +0 -1
- package/dist/streaming/dash/segments.d.ts +0 -58
- package/dist/streaming/dash/segments.d.ts.map +0 -1
- package/dist/streaming/decipher.d.ts +0 -24
- package/dist/streaming/decipher.d.ts.map +0 -1
- package/dist/streaming/drm.d.ts +0 -26
- package/dist/streaming/drm.d.ts.map +0 -1
- package/dist/streaming/formats.d.ts +0 -20
- package/dist/streaming/formats.d.ts.map +0 -1
- package/dist/streaming/hls/parser.d.ts +0 -10
- package/dist/streaming/hls/parser.d.ts.map +0 -1
- package/dist/streaming/hls/segments.d.ts +0 -37
- package/dist/streaming/hls/segments.d.ts.map +0 -1
- package/dist/streaming/processor.d.ts +0 -20
- package/dist/streaming/processor.d.ts.map +0 -1
- package/dist/types/error.types.d.ts +0 -12
- package/dist/types/error.types.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -8
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/innertube.types.d.ts +0 -155
- package/dist/types/innertube.types.d.ts.map +0 -1
- package/dist/types/player.types.d.ts +0 -30
- package/dist/types/player.types.d.ts.map +0 -1
- package/dist/types/video.types.d.ts +0 -112
- package/dist/types/video.types.d.ts.map +0 -1
- package/dist/utils/constants.d.ts +0 -129
- package/dist/utils/constants.d.ts.map +0 -1
- package/dist/utils/m3u8.d.ts +0 -31
- package/dist/utils/m3u8.d.ts.map +0 -1
- package/dist/utils/xml.d.ts +0 -41
- package/dist/utils/xml.d.ts.map +0 -1
- package/dist/validation/schemas.d.ts +0 -290
- package/dist/validation/schemas.d.ts.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["cookie: Cookie","context: InnerTubeContext","payload: InnerTubePayload","errors: Array<{ client: ClientName; error: BundlpError }>","stack: ASTNode[]","foundCallExpr: ASTNode | null","candidates: string[]","foundProperty: ASTNode | null","found: ASTNode | null","parent: ASTNode | null","definition: ASTNode | null","result: string | null","parts: string[]","match","bestCandidate: { name: string; code: string; size: number } | null","lastError: Error","match","combined: Format[]","video: Format[]","audio: Format[]","player: Player","variants: HlsVariant[]","segments: HlsSegment[]","match","root: XmlNode","stack: XmlNode[]","match: RegExpExecArray | null","match","node: XmlNode","attrs: Record<string, string>","results: XmlNode[]","adaptationSets: DashAdaptationSet[]","parsedReps: DashRepresentation[]","match","videoStreams: DashStreamInfo[]","audioStreams: DashStreamInfo[]","match","PO_TOKEN_POLICIES: Record<ClientName, PoTokenPolicy>","GOOG_API_KEY","REQUEST_KEY","result: string","webPoSignalOutput: unknown[]","snapshot: string","u8ToBase64Url","context: PoTokenContext","err"],"sources":["../src/result/result.utils.ts","../src/utils/constants.ts","../src/types/error.types.ts","../src/http/client.ts","../src/validation/schemas.ts","../src/streaming/drm.ts","../src/innertube/client.ts","../src/player/ast/matchers.ts","../src/player/ast/analyzer.ts","../src/player/ast/extractor.ts","../src/player/cache.ts","../src/player/player.ts","../src/http/retry.ts","../src/streaming/formats.ts","../src/streaming/decipher.ts","../src/utils/m3u8.ts","../src/streaming/hls/parser.ts","../src/utils/xml.ts","../src/streaming/dash/parser.ts","../src/streaming/hls/segments.ts","../src/streaming/dash/segments.ts","../src/streaming/processor.ts","../src/core/extractor.ts","../src/utils/headers.ts","../src/po-token/policies.ts","../src/po-token/botguard/challenge.ts","../src/po-token/botguard/client.ts","../src/po-token/minter/web-minter.ts","../src/po-token/providers/local.provider.ts","../src/po-token/cache/token-cache.ts","../src/po-token/manager.ts","../src/utils/logger.ts","../src/index.ts"],"sourcesContent":["/**\n * Result Pattern Utilities\n */\n\nimport type { Result, ResultOk, ResultErr } from './result.types';\n\n/** Create a successful result */\nexport const ok = <T>(value: T): ResultOk<T> => ({ ok: true, value });\n\n/** Create an error result */\nexport const err = <E>(error: E): ResultErr<E> => ({ ok: false, error });\n\n/** Type guard for successful result */\nexport const isOk = <T, E>(result: Result<T, E>): result is ResultOk<T> => result.ok;\n\n/** Type guard for error result */\nexport const isErr = <T, E>(result: Result<T, E>): result is ResultErr<E> => !result.ok;\n\n/** Pattern match on a Result */\nexport function match<T, E, U>(\n result: Result<T, E>,\n handlers: { ok: (value: T) => U; err: (error: E) => U }\n): U {\n return result.ok ? handlers.ok(result.value) : handlers.err(result.error);\n}\n\n/** Map over a successful result */\nexport function map<T, E, U>(\n result: Result<T, E>,\n fn: (value: T) => U\n): Result<U, E> {\n return result.ok ? ok(fn(result.value)) : result;\n}\n\n/** Map over an error result */\nexport function mapErr<T, E, F>(\n result: Result<T, E>,\n fn: (error: E) => F\n): Result<T, F> {\n return result.ok ? result : err(fn(result.error));\n}\n\n/** Chain Results (flatMap) */\nexport function andThen<T, E, U>(\n result: Result<T, E>,\n fn: (value: T) => Result<U, E>\n): Result<U, E> {\n return result.ok ? fn(result.value) : result;\n}\n\n/** Unwrap with default value */\nexport function unwrapOr<T, E>(result: Result<T, E>, defaultValue: T): T {\n return result.ok ? result.value : defaultValue;\n}\n\n/** Unwrap or throw */\nexport function unwrap<T, E>(result: Result<T, E>): T {\n if (result.ok) return result.value;\n throw new Error(`Unwrap called on Err: ${JSON.stringify(result.error)}`);\n}\n\n/** Try to execute a function and wrap in Result */\nexport function tryCatch<T, E = Error>(fn: () => T): Result<T, E> {\n try {\n return ok(fn());\n } catch (e) {\n return err(e as E);\n }\n}\n\n/** Try to execute an async function and wrap in Result */\nexport async function tryCatchAsync<T, E = Error>(\n fn: () => Promise<T>\n): Promise<Result<T, E>> {\n try {\n return ok(await fn());\n } catch (e) {\n return err(e as E);\n }\n}\n","export const YOUTUBE_BASE_URL = 'https://www.youtube.com';\nexport const INNER_TUBE_API_URL = `${YOUTUBE_BASE_URL}/youtubei/v1`;\nexport const VIDEO_ID_LENGTH = 11;\n\nexport const RETRY_DEFAULTS = {\n RETRIES: 3,\n DELAY: 1000,\n BACKOFF: 2,\n MAX_DELAY: 30000,\n} as const;\n\nexport const INNERTUBE_CLIENTS = {\n WEB: {\n NAME: 'WEB',\n VERSION: '2.20250222.10.00',\n CLIENT_ID: 1,\n API_KEY: 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8',\n INNERTUBE_CONTEXT: {\n client: {\n clientName: 'WEB',\n clientVersion: '2.20250222.10.00',\n platform: 'DESKTOP',\n },\n },\n HEADERS: {\n 'User-Agent':\n 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',\n 'X-YouTube-Client-Name': '1',\n 'X-YouTube-Client-Version': '2.20250222.10.00',\n },\n },\n ANDROID: {\n NAME: 'ANDROID',\n VERSION: '19.35.36',\n CLIENT_ID: 3,\n API_KEY: 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8',\n SDK_VERSION: 33,\n INNERTUBE_CONTEXT: {\n client: {\n clientName: 'ANDROID',\n clientVersion: '19.35.36',\n androidSdkVersion: 33,\n },\n },\n HEADERS: {\n 'User-Agent':\n 'com.google.android.youtube/19.35.36(Linux; U; Android 13; en_US; SM-S908E Build/TP1A.220624.014) gzip',\n 'X-YouTube-Client-Name': '3',\n 'X-YouTube-Client-Version': '19.35.36',\n },\n },\n TV: {\n NAME: 'TVHTML5',\n VERSION: '7.20250923.13.00',\n CLIENT_ID: 7,\n API_KEY: 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8',\n INNERTUBE_CONTEXT: {\n client: {\n clientName: 'TVHTML5',\n clientVersion: '7.20250923.13.00',\n userAgent: 'Mozilla/5.0 (ChromiumStylePlatform) Cobalt/Version',\n },\n },\n HEADERS: {\n 'User-Agent': 'Mozilla/5.0 (ChromiumStylePlatform) Cobalt/Version',\n 'X-YouTube-Client-Name': '7',\n 'X-YouTube-Client-Version': '7.20250923.13.00',\n },\n },\n IOS: {\n NAME: 'IOS',\n VERSION: '20.10.4',\n CLIENT_ID: 5,\n API_KEY: 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8',\n INNERTUBE_CONTEXT: {\n client: {\n clientName: 'IOS',\n clientVersion: '20.10.4',\n deviceMake: 'Apple',\n deviceModel: 'iPhone16,2',\n osName: 'iPhone',\n osVersion: '18.3.2.22D82',\n },\n },\n HEADERS: {\n 'User-Agent':\n 'com.google.ios.youtube/20.10.4 (iPhone16,2; U; CPU iOS 18_3_2 like Mac OS X;)',\n 'X-YouTube-Client-Name': '5',\n 'X-YouTube-Client-Version': '20.10.4',\n },\n },\n ANDROID_SDKLESS: {\n NAME: 'ANDROID',\n VERSION: '20.10.38',\n CLIENT_ID: 3,\n API_KEY: 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8',\n INNERTUBE_CONTEXT: {\n client: {\n clientName: 'ANDROID',\n clientVersion: '20.10.38',\n osName: 'Android',\n osVersion: '11',\n }\n },\n HEADERS: {\n 'User-Agent': 'com.google.android.youtube/20.10.38 (Linux; U; Android 11) gzip',\n 'X-YouTube-Client-Name': '3',\n 'X-YouTube-Client-Version': '20.10.38'\n }\n },\n TV_EMBEDDED: {\n NAME: 'TVHTML5_SIMPLY_EMBEDDED_PLAYER',\n VERSION: '2.0',\n CLIENT_ID: 85,\n API_KEY: 'AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8',\n INNERTUBE_CONTEXT: {\n client: {\n clientName: 'TVHTML5_SIMPLY_EMBEDDED_PLAYER',\n clientVersion: '2.0',\n clientScreen: 'EMBED',\n platform: 'TV',\n },\n thirdParty: {\n embedUrl: 'https://www.youtube.com/',\n }\n },\n HEADERS: {\n 'User-Agent': 'Mozilla/5.0 (ChromiumStylePlatform) Cobalt/Version',\n 'X-YouTube-Client-Name': '85',\n 'X-YouTube-Client-Version': '2.0'\n }\n }\n} as const;\n\nexport type ClientName = keyof typeof INNERTUBE_CLIENTS;\n","/**\n * Error Types for bundlp\n */\n\nexport type ErrorCode =\n | 'INVALID_URL'\n | 'INVALID_CLIENT'\n | 'VIDEO_NOT_FOUND'\n | 'VIDEO_UNAVAILABLE'\n | 'VIDEO_PRIVATE'\n | 'VIDEO_REGION_BLOCKED'\n | 'VIDEO_AGE_RESTRICTED'\n | 'VIDEO_DRM_PROTECTED'\n | 'LOGIN_REQUIRED'\n | 'RATE_LIMITED'\n | 'PO_TOKEN_REQUIRED'\n | 'PO_TOKEN_EXPIRED'\n | 'BOTGUARD_INIT_FAILED'\n | 'BOTGUARD_SNAPSHOT_FAILED'\n | 'INTEGRITY_TOKEN_FAILED'\n | 'ALL_PROVIDERS_FAILED'\n | 'CIPHER_FAILED'\n | 'PLAYER_FETCH_FAILED'\n | 'INNERTUBE_ERROR'\n | 'NETWORK_ERROR'\n | 'PARSE_ERROR'\n | 'CACHE_ERROR'\n | 'UNKNOWN_ERROR';\n\nexport interface BundlpError {\n code: ErrorCode;\n message: string;\n cause?: unknown;\n recoverable?: boolean;\n}\n\nexport function createError(\n code: ErrorCode,\n message: string,\n cause?: unknown\n): BundlpError {\n return { code, message, cause, recoverable: isRecoverable(code) };\n}\n\nfunction isRecoverable(code: ErrorCode): boolean {\n const recoverableCodes: ErrorCode[] = [\n 'RATE_LIMITED',\n 'NETWORK_ERROR',\n 'PO_TOKEN_REQUIRED',\n 'PO_TOKEN_EXPIRED',\n 'BOTGUARD_INIT_FAILED',\n 'ALL_PROVIDERS_FAILED',\n ];\n return recoverableCodes.includes(code);\n}\n","import { ok, err, type Result } from '../result';\nimport type { BundlpError } from '../types/error.types';\nimport { createError } from '../types/error.types';\n\nexport interface HttpClientOptions extends RequestInit {\n timeout?: number;\n maxRedirects?: number;\n manualRedirects?: boolean;\n}\n\ninterface Cookie {\n name: string;\n value: string;\n domain?: string;\n path?: string;\n expires?: Date;\n secure?: boolean;\n httpOnly?: boolean;\n}\n\nfunction parseCookies(setCookieHeaders: string[]): Cookie[] {\n return setCookieHeaders.map(header => {\n const parts = header.split(';').map(p => p.trim());\n const [nameValue, ...attributes] = parts;\n const [name, value] = nameValue.split('=');\n\n const cookie: Cookie = { name, value };\n\n for (const attr of attributes) {\n const [key, val] = attr.split('=');\n const keyLower = key.toLowerCase();\n if (keyLower === 'domain') cookie.domain = val;\n else if (keyLower === 'path') cookie.path = val;\n else if (keyLower === 'secure') cookie.secure = true;\n else if (keyLower === 'httponly') cookie.httpOnly = true;\n else if (keyLower === 'expires') cookie.expires = new Date(val);\n }\n\n return cookie;\n });\n}\n\nfunction cookiesToHeader(cookies: Map<string, Cookie>): string {\n return Array.from(cookies.values())\n .map(c => `${c.name}=${c.value}`)\n .join('; ');\n}\n\n/**\n * HTTP client with cookie jar and controlled redirect handling.\n * Superior to YouTube.js: tracks cookies across redirects, prevents loops.\n */\nexport class HttpClient {\n private cookies: Map<string, Cookie> = new Map();\n\n /**\n * Performs a fetch request with automatic cookie and redirect handling.\n * @param url - The URL to fetch\n * @param options - Fetch options. Use manualRedirects=true for controlled redirects\n * @returns Result containing the Response or a BundlpError\n */\n async request(\n url: string,\n options: HttpClientOptions = {}\n ): Promise<Result<Response, BundlpError>> {\n const { maxRedirects = 10, manualRedirects = false, timeout, ...fetchOptions } = options;\n\n if (!manualRedirects) {\n try {\n const response = await fetch(url, {\n ...fetchOptions,\n signal: timeout ? AbortSignal.timeout(timeout) : undefined\n });\n\n return ok(response);\n } catch (error) {\n return err(\n createError(\n 'NETWORK_ERROR',\n `Request to ${url} failed: ${(error as Error).message}`,\n error\n )\n );\n }\n }\n\n let currentUrl = url;\n let redirectCount = 0;\n const visitedUrls = new Set<string>();\n\n while (redirectCount <= maxRedirects) {\n if (visitedUrls.has(currentUrl)) {\n return err(\n createError('NETWORK_ERROR', `Redirect loop detected at ${currentUrl}`)\n );\n }\n visitedUrls.add(currentUrl);\n\n try {\n const headers = new Headers(fetchOptions.headers);\n const cookieHeader = cookiesToHeader(this.cookies);\n if (cookieHeader) headers.set('Cookie', cookieHeader);\n\n const response = await fetch(currentUrl, {\n ...fetchOptions,\n headers,\n redirect: 'manual',\n signal: timeout ? AbortSignal.timeout(timeout) : undefined\n });\n\n const setCookies = response.headers.getSetCookie?.() || [];\n for (const cookie of parseCookies(setCookies)) {\n this.cookies.set(cookie.name, cookie);\n }\n\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get('location');\n if (!location) {\n return ok(response);\n }\n\n currentUrl = new URL(location, currentUrl).href;\n redirectCount++;\n continue;\n }\n\n return ok(response);\n } catch (error) {\n return err(\n createError(\n 'NETWORK_ERROR',\n `Request to ${currentUrl} failed: ${(error as Error).message}`,\n error\n )\n );\n }\n }\n\n return err(\n createError(\n 'NETWORK_ERROR',\n `Too many redirects (${redirectCount}) for ${url}`\n )\n );\n }\n\n clearCookies(): void {\n this.cookies.clear();\n }\n\n getCookies(): Map<string, Cookie> {\n return new Map(this.cookies);\n }\n\n /**\n * Performs a GET request.\n * @param url - The URL to fetch\n * @param options - Optional fetch options\n * @returns Result containing the Response or a BundlpError\n */\n async get(\n url: string,\n options: HttpClientOptions = {}\n ): Promise<Result<Response, BundlpError>> {\n return this.request(url, { ...options, method: 'GET' });\n }\n\n /**\n * Performs a POST request with JSON body.\n * @param url - The URL to post to\n * @param body - The request body (will be JSON stringified)\n * @param options - Optional fetch options\n * @returns Result containing the Response or a BundlpError\n */\n async post(\n url: string,\n body: unknown,\n options: HttpClientOptions = {}\n ): Promise<Result<Response, BundlpError>> {\n return this.request(url, {\n ...options,\n method: 'POST',\n body: JSON.stringify(body),\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n });\n }\n}\n\nexport const httpClient = new HttpClient();\n","import { type } from 'arktype';\n\n/**\n * Schema for playability status returned by InnerTube API.\n */\nexport const PlayabilityStatusSchema = type({\n status: \"'OK' | 'UNPLAYABLE' | 'LOGIN_REQUIRED' | 'AGE_CHECK_REQUIRED' | 'ERROR'\",\n 'reason?': 'string',\n 'playableInEmbed?': 'boolean',\n 'liveStreamability?': 'unknown',\n});\n\n/**\n * Schema for thumbnail objects.\n */\nexport const ThumbnailSchema = type({\n url: 'string',\n width: 'number',\n height: 'number',\n});\n\n/**\n * Schema for video details from InnerTube response.\n * Some fields are optional as TV and other clients may omit them.\n */\nexport const VideoDetailsSchema = type({\n videoId: 'string',\n 'title?': 'string',\n lengthSeconds: 'string',\n channelId: 'string',\n 'shortDescription?': 'string',\n 'thumbnail?': {\n thumbnails: ThumbnailSchema.array(),\n },\n 'viewCount?': 'string',\n 'author?': 'string',\n isLiveContent: 'boolean',\n 'isPrivate?': 'boolean',\n 'keywords?': 'string[]',\n});\n\n/**\n * Schema for raw format objects from streaming data.\n */\nexport const RawFormatSchema = type({\n itag: 'number',\n 'url?': 'string',\n 'signatureCipher?': 'string',\n 'cipher?': 'string',\n mimeType: 'string',\n bitrate: 'number',\n 'width?': 'number',\n 'height?': 'number',\n 'fps?': 'number',\n 'qualityLabel?': 'string',\n quality: 'string',\n 'audioQuality?': 'string',\n 'audioSampleRate?': 'string',\n 'audioChannels?': 'number',\n 'contentLength?': 'string',\n 'approxDurationMs?': 'string',\n 'initRange?': { start: 'string', end: 'string' },\n 'indexRange?': { start: 'string', end: 'string' },\n 'lastModified?': 'string',\n 'drmFamilies?': 'string[]',\n});\n\n/**\n * Schema for streaming data section of player response.\n */\nexport const StreamingDataSchema = type({\n expiresInSeconds: 'string',\n 'formats?': RawFormatSchema.array(),\n 'adaptiveFormats?': RawFormatSchema.array(),\n 'hlsManifestUrl?': 'string',\n 'dashManifestUrl?': 'string',\n});\n\n/**\n * Schema for caption track information.\n * Note: name can be either { simpleText } or { runs } format.\n */\nexport const CaptionTrackSchema = type({\n baseUrl: 'string',\n languageCode: 'string',\n 'name?': 'unknown',\n 'kind?': 'string',\n 'isTranslatable?': 'boolean',\n});\n\n/**\n * Schema for captions data section.\n */\nexport const CaptionsDataSchema = type({\n 'playerCaptionsTracklistRenderer?': {\n 'captionTracks?': CaptionTrackSchema.array(),\n },\n});\n\n/**\n * Schema for microformat data section.\n */\nexport const MicroformatDataSchema = type({\n 'playerMicroformatRenderer?': {\n 'uploadDate?': 'string',\n 'publishDate?': 'string',\n 'category?': 'string',\n 'isFamilySafe?': 'boolean',\n 'lengthSeconds?': 'string',\n },\n});\n\n/**\n * Schema for the complete InnerTube player response.\n */\nexport const PlayerResponseSchema = type({\n playabilityStatus: PlayabilityStatusSchema,\n 'videoDetails?': VideoDetailsSchema,\n 'streamingData?': StreamingDataSchema,\n 'captions?': CaptionsDataSchema,\n 'microformat?': MicroformatDataSchema,\n 'storyboards?': 'unknown',\n});\n\nexport type PlayerResponse = typeof PlayerResponseSchema.infer;\nexport type StreamingData = typeof StreamingDataSchema.infer;\nexport type RawFormat = typeof RawFormatSchema.infer;\nexport type VideoDetails = typeof VideoDetailsSchema.infer;\nexport type PlayabilityStatus = typeof PlayabilityStatusSchema.infer;\n","import type { RawFormat } from '../validation/schemas';\n\n/**\n * Checks if a format is DRM-protected.\n * @param format - Format to check\n * @returns Whether format has DRM\n */\nexport function hasDrm(format: RawFormat): boolean {\n return !!(format.drmFamilies && format.drmFamilies.length > 0);\n}\n\n/**\n * Checks if all formats are DRM-only.\n * @param formats - Array of formats\n * @returns Whether all formats have DRM\n */\nexport function isDrmOnly(formats: RawFormat[]): boolean {\n if (formats.length === 0) return false;\n return formats.every(hasDrm);\n}\n\n/**\n * Filters out DRM-protected formats.\n * @param formats - Array of formats\n * @returns Formats without DRM\n */\nexport function filterDrm(formats: RawFormat[]): RawFormat[] {\n return formats.filter(f => !hasDrm(f));\n}\n\n/**\n * Counts non-DRM formats.\n * @param formats - Array of formats\n * @returns Number of formats without DRM\n */\nexport function countNonDrm(formats: RawFormat[]): number {\n return formats.filter(f => !hasDrm(f)).length;\n}\n","import {\n INNERTUBE_CLIENTS,\n INNER_TUBE_API_URL,\n YOUTUBE_BASE_URL,\n type ClientName,\n} from '../utils/constants';\nimport { httpClient } from '../http/client';\nimport { ok, err, type Result, isErr, isOk } from '../result';\nimport { createError, type BundlpError } from '../types/error.types';\nimport type { InnerTubeContext, InnerTubePayload } from '../types/innertube.types';\nimport { type } from 'arktype';\nimport { PlayerResponseSchema, type PlayerResponse, type StreamingData } from '../validation/schemas';\nimport { isDrmOnly } from '../streaming/drm';\n\nexport interface InnerTubeClientConfig {\n initialClient?: ClientName;\n}\n\n/**\n * Client for interacting with YouTube's InnerTube API.\n */\nexport class InnerTubeClient {\n private currentClient: ClientName;\n private readonly FALLBACK_ORDER: ClientName[] = [\n 'ANDROID_SDKLESS', // First: Doesn't require po_token, works best\n 'TV', // Second: May return HLS\n 'WEB' // Last: Requires po_token\n ];\n\n constructor(config: InnerTubeClientConfig = {}) {\n this.currentClient = config.initialClient || 'WEB';\n }\n\n /**\n * Sets the client type to use for API requests.\n * @param client - The client name to use\n * @returns Result indicating success or error if client is unknown\n */\n setClient(client: ClientName): Result<void, BundlpError> {\n if (!INNERTUBE_CLIENTS[client]) {\n return err(createError('INVALID_CLIENT', `Unknown client: ${client}`));\n }\n this.currentClient = client;\n return ok(undefined);\n }\n\n /**\n * Gets the current client name being used.\n * @returns The current client name\n */\n getClientName(): ClientName {\n return this.currentClient;\n }\n\n private getHeaders(): Record<string, string> {\n const config = INNERTUBE_CLIENTS[this.currentClient];\n\n return {\n 'Content-Type': 'application/json',\n Accept: '*/*',\n Origin: YOUTUBE_BASE_URL,\n Referer: `${YOUTUBE_BASE_URL}/`,\n ...config.HEADERS,\n };\n }\n\n private buildContext(): InnerTubeContext {\n const config = INNERTUBE_CLIENTS[this.currentClient];\n\n const context: InnerTubeContext = {\n client: {\n hl: 'en',\n gl: 'US',\n ...config.INNERTUBE_CONTEXT?.client,\n },\n user: {\n lockedSafetyMode: false,\n },\n request: {\n useSsl: true,\n },\n };\n\n const innertubeContext = config.INNERTUBE_CONTEXT as { thirdParty?: { embedUrl: string } } | undefined;\n if (innertubeContext?.thirdParty) {\n context.thirdParty = innertubeContext.thirdParty;\n }\n\n return context;\n }\n\n /**\n * Fetches video player data from the InnerTube API.\n * @param videoId - The YouTube video ID\n * @param options - Optional parameters for the request\n * @returns Result containing PlayerResponse or BundlpError\n */\n async fetchPlayer(\n videoId: string,\n options: { signatureTimestamp?: number; poToken?: string } = {}\n ): Promise<Result<PlayerResponse, BundlpError>> {\n const config = INNERTUBE_CLIENTS[this.currentClient];\n\n const payload: InnerTubePayload = {\n context: this.buildContext(),\n videoId,\n contentCheckOk: true,\n racyCheckOk: true,\n };\n\n if (options.signatureTimestamp) {\n payload.playbackContext = {\n contentPlaybackContext: {\n signatureTimestamp: options.signatureTimestamp,\n },\n };\n }\n\n if (options.poToken) {\n if (!payload.serviceIntegrityDimensions) {\n payload.serviceIntegrityDimensions = {};\n }\n payload.serviceIntegrityDimensions.poToken = options.poToken;\n }\n\n const url = `${INNER_TUBE_API_URL}/player?key=${config.API_KEY || ''}`;\n\n const responseResult = await httpClient.post(url, payload, {\n headers: this.getHeaders(),\n });\n\n if (isErr(responseResult)) {\n return responseResult;\n }\n\n const response = responseResult.value;\n\n if (!response.ok) {\n return err(createError('INNERTUBE_ERROR', `Player request failed with status ${response.status}`));\n }\n\n try {\n const data = await response.json();\n const validated = PlayerResponseSchema(data);\n\n if (validated instanceof type.errors) {\n return err(createError('PARSE_ERROR', `Invalid player response: ${validated.summary}`));\n }\n\n if (validated.playabilityStatus.status === 'ERROR') {\n return err(createError('VIDEO_UNAVAILABLE', validated.playabilityStatus.reason || 'Video unavailable'));\n }\n\n return ok(validated);\n } catch (error) {\n return err(createError('PARSE_ERROR', 'Failed to parse InnerTube response', error));\n }\n }\n\n /**\n * Fetches player data with automatic client fallback.\n * Tries clients in order: ANDROID_SDKLESS → TV → IOS → WEB\n * @param videoId - Video ID to fetch\n * @param options - Fetch options\n * @returns Result containing player response or error\n */\n async fetchPlayerWithFallback(\n videoId: string,\n options: { signatureTimestamp?: number; poToken?: string } = {}\n ): Promise<Result<PlayerResponse, BundlpError>> {\n const errors: Array<{ client: ClientName; error: BundlpError }> = [];\n\n for (const clientName of this.FALLBACK_ORDER) {\n const setResult = this.setClient(clientName);\n if (isErr(setResult)) continue;\n\n const result = await this.fetchPlayer(videoId, options);\n\n if (isOk(result)) {\n if (this.isValidResponse(result.value)) {\n return result;\n }\n errors.push({\n client: clientName,\n error: createError('VIDEO_UNAVAILABLE', 'Invalid or DRM-only response')\n });\n } else {\n errors.push({ client: clientName, error: result.error });\n }\n }\n\n return err(createError('VIDEO_UNAVAILABLE', 'All clients failed', errors));\n }\n\n /**\n * Validates if a player response is usable.\n * @param response - Player response to validate\n * @returns Whether response is valid\n */\n private isValidResponse(response: PlayerResponse): boolean {\n if (response.playabilityStatus.status !== 'OK') return false;\n if (!response.streamingData) return false;\n if (this.hasDrmOnly(response.streamingData)) return false;\n return true;\n }\n\n /**\n * Checks if streaming data contains only DRM-protected formats.\n * @param streamingData - Streaming data to check\n * @returns Whether all formats are DRM-protected\n */\n private hasDrmOnly(streamingData: StreamingData): boolean {\n const allFormats = [\n ...(streamingData.formats || []),\n ...(streamingData.adaptiveFormats || [])\n ];\n\n if (allFormats.length === 0) return true;\n\n return isDrmOnly(allFormats);\n }\n}\n","export interface ASTNode {\n type: string;\n [key: string]: unknown;\n}\n\nexport const WALK_STOP = Symbol('stop');\n\n/**\n * Recursively walks an AST tree and applies a callback to each node.\n * Uses iterative approach with explicit stack for better performance on large ASTs.\n */\nexport function walkAst<T>(\n node: ASTNode,\n callback: (node: ASTNode) => T | typeof WALK_STOP | undefined\n): T | undefined {\n const stack: ASTNode[] = [node];\n\n while (stack.length > 0) {\n const current = stack.pop()!;\n const result = callback(current);\n\n if (result === WALK_STOP) return undefined;\n if (result) return result;\n\n for (const key of Object.keys(current)) {\n const child = current[key];\n if (child && typeof child === 'object') {\n if (Array.isArray(child)) {\n for (let i = child.length - 1; i >= 0; i--) {\n const item = child[i];\n if (item && typeof item === 'object' && 'type' in item) {\n stack.push(item as ASTNode);\n }\n }\n } else if ('type' in child) {\n stack.push(child as ASTNode);\n }\n }\n }\n }\n return undefined;\n}\n\n/**\n * Extracts FunctionExpression from either VariableDeclarator or AssignmentExpression\n */\nfunction getFunctionExpression(node: ASTNode): ASTNode | null {\n if (node.type === 'VariableDeclarator') {\n const init = node.init as ASTNode | undefined;\n if (init?.type === 'FunctionExpression') return init;\n }\n if (node.type === 'AssignmentExpression') {\n const right = node.right as ASTNode | undefined;\n if (right?.type === 'FunctionExpression') return right;\n }\n return null;\n}\n\n/**\n * Finds the signature decipher function call in YouTube's player.js.\n * Supports multiple patterns:\n * - Pattern 1: LogicalExpression with SequenceExpression (YouTube.js style)\n * - Pattern 2: Direct CallExpression with decodeURIComponent argument\n * - Pattern 3: AssignmentExpression with cipher function call\n */\nexport function sigMatcher(node: ASTNode): ASTNode | false {\n // Get function expression from either VariableDeclarator or AssignmentExpression\n const funcExpr = getFunctionExpression(node);\n if (!funcExpr) return false;\n\n // Flexible param count: 1-5 params (not exactly 3)\n const params = funcExpr.params as unknown[];\n if (!params || params.length < 1 || params.length > 5) return false;\n\n const body = funcExpr.body as ASTNode | undefined;\n if (body?.type !== 'BlockStatement') return false;\n\n let foundCallExpr: ASTNode | null = null;\n\n walkAst(body, (innerNode) => {\n // Pattern 1: LogicalExpression && SequenceExpression (YouTube.js style)\n if (\n innerNode.type === 'LogicalExpression' &&\n (innerNode.operator as string) === '&&'\n ) {\n const right = innerNode.right as ASTNode;\n if (right?.type === 'SequenceExpression') {\n const expressions = right.expressions as ASTNode[];\n if (expressions?.[0]?.type === 'AssignmentExpression') {\n const assignRight = (expressions[0] as ASTNode).right as ASTNode;\n if (assignRight?.type === 'CallExpression') {\n // Check if any argument is decodeURIComponent call\n const args = assignRight.arguments as ASTNode[];\n const hasDecodeURI = args?.some((arg) => {\n if (arg.type !== 'CallExpression') return false;\n const callee = arg.callee as ASTNode;\n return callee?.type === 'Identifier' &&\n (callee.name as string) === 'decodeURIComponent';\n });\n if (hasDecodeURI) {\n foundCallExpr = assignRight;\n return WALK_STOP;\n }\n }\n }\n }\n }\n\n // Pattern 2: CipherFn(number, decodeURIComponent(sig)) - typical cipher pattern\n if (innerNode.type === 'CallExpression') {\n const args = innerNode.arguments as ASTNode[];\n if (!args || args.length !== 2) return undefined;\n\n // First arg should be a number literal (mode flag)\n const firstArg = args[0];\n if (firstArg?.type !== 'Literal' || typeof firstArg.value !== 'number') {\n return undefined;\n }\n\n // Second arg should be decodeURIComponent(...)\n const secondArg = args[1];\n if (secondArg?.type !== 'CallExpression') return undefined;\n const secondCallee = secondArg.callee as ASTNode;\n if (secondCallee?.type !== 'Identifier' ||\n (secondCallee.name as string) !== 'decodeURIComponent') {\n return undefined;\n }\n\n // Verify callee is an identifier\n const callee = innerNode.callee as ASTNode;\n if (callee?.type === 'Identifier') {\n foundCallExpr = innerNode;\n return WALK_STOP;\n }\n }\n\n // Pattern 3: AssignmentExpression = cipherFn(number, decodeURIComponent(Y))\n if (innerNode.type === 'AssignmentExpression') {\n const right = innerNode.right as ASTNode;\n if (right?.type === 'CallExpression') {\n const args = right.arguments as ASTNode[];\n if (args?.length === 2) {\n const firstArg = args[0];\n const secondArg = args[1];\n if (firstArg?.type === 'Literal' && typeof firstArg.value === 'number' &&\n secondArg?.type === 'CallExpression') {\n const secondCallee = secondArg.callee as ASTNode;\n if (secondCallee?.type === 'Identifier' &&\n (secondCallee.name as string) === 'decodeURIComponent') {\n foundCallExpr = right;\n return WALK_STOP;\n }\n }\n }\n }\n }\n\n return undefined;\n });\n\n return foundCallExpr || false;\n}\n\n/**\n * Finds all potential 'n' parameter transformation function references.\n * Searches for patterns like: var XX = [functionName] or var XX = [functionName, \"string\"]\n * YouTube uses both single-element and multi-element arrays.\n * @param ast - Full AST to search\n * @returns Array of candidate function names\n */\nexport function findNFunctionCandidates(ast: ASTNode): string[] {\n const candidates: string[] = [];\n\n walkAst(ast, (node) => {\n if (node.type !== 'VariableDeclarator') return undefined;\n\n const id = node.id as ASTNode | undefined;\n const init = node.init as ASTNode | undefined;\n\n if (id?.type !== 'Identifier') return undefined;\n if (init?.type !== 'ArrayExpression') return undefined;\n\n const elements = init.elements as ASTNode[];\n if (!elements || elements.length === 0) return undefined;\n\n const firstElement = elements[0];\n if (firstElement?.type !== 'Identifier') return undefined;\n\n candidates.push(firstElement.name as string);\n return undefined;\n });\n\n return candidates;\n}\n\n/**\n * Legacy nMatcher for backward compatibility.\n * Searches for patterns: var XX = [functionName] or var XX = [functionName, \"string\"]\n * @param node - AST node to check\n * @returns The Identifier node containing function name, or false\n */\nexport function nMatcher(node: ASTNode): ASTNode | false {\n if (node.type !== 'VariableDeclarator') return false;\n\n const id = node.id as ASTNode | undefined;\n const init = node.init as ASTNode | undefined;\n\n if (id?.type !== 'Identifier') return false;\n if (init?.type !== 'ArrayExpression') return false;\n\n const elements = init.elements as ASTNode[];\n if (!elements || elements.length === 0) return false;\n\n const firstElement = elements[0];\n if (firstElement?.type !== 'Identifier') return false;\n\n return firstElement;\n}\n\n/**\n * Finds the signatureTimestamp value in player.js.\n * Pattern 1: Direct ObjectExpression property (fastest)\n * Pattern 2: Inside FunctionExpression body (fallback)\n */\nexport function timestampMatcher(node: ASTNode): ASTNode | false {\n // Pattern 1: Direct ObjectExpression with signatureTimestamp property\n if (node.type === 'ObjectExpression') {\n const properties = node.properties as ASTNode[];\n if (!properties) return false;\n\n for (const prop of properties) {\n if (prop.type !== 'Property') continue;\n const key = prop.key as ASTNode;\n // Handle both Identifier and Literal keys\n const keyName = key?.type === 'Identifier'\n ? (key.name as string)\n : key?.type === 'Literal'\n ? String(key.value)\n : null;\n\n if (keyName === 'signatureTimestamp') {\n return prop;\n }\n }\n return false;\n }\n\n // Pattern 2: Inside function body (VariableDeclarator or AssignmentExpression)\n const funcExpr = getFunctionExpression(node);\n if (!funcExpr) return false;\n\n const funcBody = funcExpr.body as ASTNode;\n if (!funcBody) return false;\n\n let foundProperty: ASTNode | null = null;\n\n walkAst(funcBody, (innerNode) => {\n if (innerNode.type !== 'ObjectExpression') return undefined;\n\n const properties = innerNode.properties as ASTNode[];\n if (!properties) return undefined;\n\n for (const prop of properties) {\n if (prop.type !== 'Property') continue;\n const key = prop.key as ASTNode;\n const keyName = key?.type === 'Identifier'\n ? (key.name as string)\n : key?.type === 'Literal'\n ? String(key.value)\n : null;\n\n if (keyName === 'signatureTimestamp') {\n foundProperty = prop;\n return WALK_STOP;\n }\n }\n return undefined;\n });\n\n return foundProperty || false;\n}\n","import type { ASTNode } from './matchers';\nimport { walkAst } from './matchers';\n\nconst JS_BUILTINS = new Set([\n 'Array', 'Object', 'String', 'Number', 'Boolean', 'Math', 'JSON', 'Date', 'RegExp',\n 'Error', 'TypeError', 'RangeError', 'SyntaxError',\n 'parseInt', 'parseFloat', 'isNaN', 'isFinite', 'eval',\n 'encodeURIComponent', 'decodeURIComponent', 'encodeURI', 'decodeURI',\n 'undefined', 'null', 'NaN', 'Infinity',\n 'console', 'window', 'document', 'navigator', 'location',\n 'setTimeout', 'setInterval', 'clearTimeout', 'clearInterval',\n 'Promise', 'Map', 'Set', 'WeakMap', 'WeakSet', 'Symbol',\n 'Uint8Array', 'Int8Array', 'Uint16Array', 'Int16Array',\n 'Uint32Array', 'Int32Array', 'Float32Array', 'Float64Array',\n 'ArrayBuffer', 'DataView', 'Blob', 'URL', 'URLSearchParams',\n 'fetch', 'Request', 'Response', 'Headers',\n 'atob', 'btoa', 'escape', 'unescape',\n 'Proxy', 'Reflect', 'Function',\n 'this', 'arguments', 'self',\n]);\n\nfunction isBuiltin(name: string): boolean {\n return JS_BUILTINS.has(name);\n}\n\n/**\n * Analyzes a function node to find all external dependencies it references.\n * Recursively discovers nested dependencies.\n * Filters out JavaScript built-ins.\n */\nconst MAX_DEPTH = 4;\n\nfunction isLocalParameterVar(name: string): boolean {\n if (name.length !== 1) return false;\n if (name === 'z' || name === 'g') return false;\n return true;\n}\n\nexport function analyzeDependencies(funcNode: ASTNode, ast: ASTNode, visited = new Set<string>(), depth = 0): Set<string> {\n const dependencies = new Set<string>();\n\n if (depth > MAX_DEPTH) return dependencies;\n\n const identifiers = extractReferencedIdentifiers(funcNode);\n\n for (const identifier of identifiers) {\n if (isBuiltin(identifier)) continue;\n if (visited.has(identifier)) continue;\n if (isLocalParameterVar(identifier)) continue;\n\n visited.add(identifier);\n\n const definition = findDefinition(identifier, ast);\n if (definition) {\n dependencies.add(identifier);\n\n const nestedDeps = analyzeDependencies(definition, ast, visited, depth + 1);\n for (const dep of nestedDeps) {\n dependencies.add(dep);\n }\n }\n }\n\n return dependencies;\n}\n\n/**\n * Extracts all identifiers referenced within a node that are not locally declared.\n * @param node - The AST node to scan\n * @returns Set of external identifier names\n */\nexport function extractReferencedIdentifiers(node: ASTNode): Set<string> {\n const identifiers = new Set<string>();\n const declared = new Set<string>();\n\n walkAst(node, (innerNode) => {\n if (innerNode.type === 'VariableDeclarator') {\n const id = innerNode.id as ASTNode;\n if (id?.type === 'Identifier') {\n declared.add(id.name as string);\n }\n }\n\n if (innerNode.type === 'FunctionDeclaration' || innerNode.type === 'FunctionExpression') {\n const params = innerNode.params as ASTNode[];\n if (params) {\n for (const param of params) {\n if (param.type === 'Identifier') {\n declared.add(param.name as string);\n }\n }\n }\n }\n\n if (innerNode.type === 'MemberExpression') {\n const object = innerNode.object as ASTNode;\n if (object?.type === 'Identifier') {\n const name = object.name as string;\n if (!declared.has(name)) {\n identifiers.add(name);\n }\n }\n }\n\n if (innerNode.type === 'Identifier') {\n const parent = getParent(node, innerNode);\n\n if (parent?.type === 'CallExpression' && parent.callee === innerNode) {\n const name = innerNode.name as string;\n if (!declared.has(name)) {\n identifiers.add(name);\n }\n }\n\n if (parent?.type === 'ArrayExpression') {\n const elements = parent.elements as ASTNode[] | undefined;\n if (elements?.includes(innerNode)) {\n const name = innerNode.name as string;\n if (!declared.has(name)) {\n identifiers.add(name);\n }\n }\n }\n\n if (parent?.type === 'UnaryExpression' && parent.operator === 'typeof') {\n const name = innerNode.name as string;\n if (!declared.has(name)) {\n identifiers.add(name);\n }\n }\n }\n\n return undefined;\n });\n\n return identifiers;\n}\n\n/**\n * Finds a variable or function definition by name in the AST.\n * @param name - The identifier name to find\n * @param ast - The AST to search\n * @returns The definition node if found, null otherwise\n */\nexport function findDefinition(name: string, ast: ASTNode): ASTNode | null {\n let found: ASTNode | null = null;\n\n walkAst(ast, (node) => {\n if (node.type === 'VariableDeclarator') {\n const id = node.id as ASTNode;\n if (id?.type === 'Identifier' && id.name === name) {\n const init = node.init as ASTNode | undefined;\n if (init) {\n found = init;\n return node;\n }\n }\n }\n\n if (node.type === 'FunctionDeclaration') {\n const id = node.id as ASTNode;\n if (id?.type === 'Identifier' && id.name === name) {\n found = node;\n return node;\n }\n }\n\n if (node.type === 'AssignmentExpression') {\n const left = node.left as ASTNode;\n if (left?.type === 'Identifier' && left.name === name) {\n const right = node.right as ASTNode;\n if (right) {\n found = right;\n return node;\n }\n }\n }\n\n return undefined;\n });\n\n return found;\n}\n\n/**\n * Finds the parent node of a target node within an AST.\n * @param root - The root node to search from\n * @param target - The target node to find the parent of\n * @returns The parent node if found, null otherwise\n */\nfunction getParent(root: ASTNode, target: ASTNode): ASTNode | null {\n let parent: ASTNode | null = null;\n\n walkAst(root, (node) => {\n for (const key of Object.keys(node)) {\n const child = node[key];\n if (child === target) {\n parent = node;\n return node;\n }\n if (Array.isArray(child) && child.includes(target)) {\n parent = node;\n return node;\n }\n }\n return undefined;\n });\n\n return parent;\n}\n","import type { ASTNode } from './matchers';\nimport { walkAst, WALK_STOP } from './matchers';\nimport { analyzeDependencies } from './analyzer';\n\n/**\n * Finds a function definition by name in the AST.\n * Supports function declarations, variable declarations with function expressions,\n * and assignment expressions.\n * @param ast - The AST root node to search\n * @param functionName - The name of the function to find\n * @returns The function node if found, null otherwise\n */\nexport function findFunctionDefinition(ast: ASTNode, functionName: string): ASTNode | null {\n let definition: ASTNode | null = null;\n\n walkAst(ast, (node) => {\n const id = node.id as ASTNode | undefined;\n\n if (node.type === 'FunctionDeclaration' && id?.name === functionName) {\n definition = node;\n return WALK_STOP;\n }\n\n // VariableDeclarator: only match if init is a function\n if (node.type === 'VariableDeclarator' &&\n id?.type === 'Identifier' &&\n id.name === functionName) {\n const init = node.init as ASTNode | undefined;\n if (init?.type === 'FunctionExpression' || init?.type === 'ArrowFunctionExpression') {\n definition = init;\n return WALK_STOP;\n }\n }\n\n // AssignmentExpression: $r = function() {}\n const left = node.left as ASTNode | undefined;\n if (node.type === 'AssignmentExpression' &&\n left?.type === 'Identifier' &&\n left.name === functionName) {\n const right = node.right as ASTNode | undefined;\n if (right?.type === 'FunctionExpression' || right?.type === 'ArrowFunctionExpression') {\n definition = right;\n return WALK_STOP;\n }\n }\n\n return undefined;\n });\n\n return definition;\n}\n\n/**\n * Extracts the source code for a given AST node.\n * @param code - The full source code string\n * @param node - The AST node with start and end positions\n * @returns The extracted code slice\n */\nexport function extractCode(code: string, node: ASTNode): string {\n const start = node.start as number | undefined;\n const end = node.end as number | undefined;\n if (typeof start !== 'number' || typeof end !== 'number') {\n return '';\n }\n return code.slice(start, end);\n}\n\nfunction isSafeInitializer(node: ASTNode | undefined): boolean {\n if (!node) return true;\n return true;\n}\n\n/**\n * Extracts a full declaration (var X = ...) for a given name from the AST.\n * Handles both VariableDeclaration and AssignmentExpression patterns.\n * Only extracts if initializer is \"safe\" (no side-effects).\n * @param code - The full source code string\n * @param name - The identifier name to find\n * @param ast - The AST root node\n * @returns The complete declaration code, or null if not found\n */\nfunction extractFullDeclaration(code: string, name: string, ast: ASTNode): string | null {\n let result: string | null = null;\n\n walkAst(ast, (node) => {\n // Case 1: FunctionDeclaration - function X() {}\n if (node.type === 'FunctionDeclaration') {\n const id = node.id as ASTNode | undefined;\n if (id?.name === name) {\n result = extractCode(code, node);\n return WALK_STOP;\n }\n }\n\n // Case 2: VariableDeclaration - var X = function(){} or var X = {...}\n if (node.type === 'VariableDeclaration') {\n const decls = node.declarations as ASTNode[] | undefined;\n if (decls) {\n for (const decl of decls) {\n const id = decl.id as ASTNode | undefined;\n const init = decl.init as ASTNode | undefined;\n if (id?.name === name && init && isSafeInitializer(init)) {\n result = extractCode(code, node);\n return WALK_STOP;\n }\n }\n }\n }\n\n // Case 3: ExpressionStatement with AssignmentExpression - X = function(){}\n if (node.type === 'ExpressionStatement') {\n const expr = node.expression as ASTNode | undefined;\n if (expr?.type === 'AssignmentExpression') {\n const left = expr.left as ASTNode | undefined;\n const right = expr.right as ASTNode | undefined;\n if (left?.type === 'Identifier' && left.name === name && isSafeInitializer(right)) {\n const rightCode = extractCode(code, right as ASTNode);\n if (rightCode) {\n result = `var ${name} = ${rightCode}`;\n return WALK_STOP;\n }\n }\n }\n }\n\n // Case 4: Bare AssignmentExpression - X = function(){} (not in ExpressionStatement)\n if (node.type === 'AssignmentExpression') {\n const left = node.left as ASTNode | undefined;\n if (left?.type === 'Identifier' && left.name === name) {\n const right = node.right as ASTNode | undefined;\n if (isSafeInitializer(right)) {\n const rightCode = extractCode(code, right as ASTNode);\n if (rightCode) {\n result = `var ${name} = ${rightCode}`;\n return WALK_STOP;\n }\n }\n }\n }\n\n return undefined;\n });\n\n return result;\n}\n\n/**\n * Extracts code for a function with a simplified approach.\n * Creates a self-contained IIFE with stubs for globals.\n * @param code - The full source code string\n * @param funcNode - The function AST node\n * @param ast - The full AST for dependency lookup\n * @param funcName - The name of the main function\n * @returns Combined code with dependencies wrapped in IIFE\n */\nexport function extractCodeWithDependencies(\n code: string,\n funcNode: ASTNode,\n ast: ASTNode,\n funcName: string\n): string {\n const dependencies = analyzeDependencies(funcNode, ast);\n const parts: string[] = [];\n const extracted = new Set<string>();\n const predeclared = new Set<string>();\n\n for (const depName of dependencies) {\n if (extracted.has(depName)) continue;\n\n const depCode = extractFullDeclaration(code, depName, ast);\n if (depCode) {\n parts.push(depCode);\n extracted.add(depName);\n } else {\n predeclared.add(depName);\n }\n }\n\n if (!extracted.has(funcName)) {\n const mainCode = extractFullDeclaration(code, funcName, ast);\n if (mainCode) {\n parts.push(mainCode);\n }\n }\n\n const stubs = [\n 'var g = { cF: function(a, b) { return b.indexOf(a) >= 0; }, C$: function(a) { return /\\\\s/.test(a); } };',\n ];\n\n const predeclareStmt = predeclared.size > 0\n ? `var ${Array.from(predeclared).join(', ')};`\n : '';\n\n const postProcess = \"if (typeof z === 'string' && z.indexOf(';') !== -1) z = z.split(';');\";\n\n return [\n ...stubs,\n predeclareStmt,\n parts.join(';\\n'),\n postProcess\n ].filter(Boolean).join('\\n');\n}\n\n/**\n * Finds a variable definition by name in the AST.\n * @param ast - The AST root node to search\n * @param varName - The name of the variable to find\n * @returns The variable declarator node if found, null otherwise\n */\nexport function findVariableDefinition(ast: ASTNode, varName: string): ASTNode | null {\n let definition: ASTNode | null = null;\n walkAst(ast, (node) => {\n const id = node.id as ASTNode | undefined;\n if (node.type === 'VariableDeclarator' &&\n id?.type === 'Identifier' &&\n id.name === varName) {\n definition = node;\n return WALK_STOP;\n }\n return undefined;\n });\n return definition;\n}\n","import { Database } from 'bun:sqlite';\nimport { ok, err, type Result } from '../result';\nimport { createError, type BundlpError } from '../types/error.types';\nimport { mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\n\nexport interface CachedPlayer {\n playerId: string;\n code: string;\n sigFunction: string;\n nFunction: string;\n signatureTimestamp: number;\n cachedAt: number;\n}\n\ninterface PlayerRow {\n player_id: string;\n code: string;\n sig_function: string | null;\n n_function: string | null;\n signature_timestamp: number | null;\n cached_at: number;\n}\n\n/**\n * SQLite-based cache for YouTube player.js cipher functions.\n * Stores extracted signature and n-transform functions to avoid re-parsing.\n */\nexport class PlayerCache {\n private db: Database;\n private readonly ttlMs: number;\n\n /**\n * Creates a new PlayerCache instance.\n * @param cachePath - Path to the SQLite database file\n * @param ttlDays - Time-to-live for cached entries in days\n */\n constructor(cachePath: string, ttlDays: number = 7) {\n const dir = dirname(cachePath);\n mkdirSync(dir, { recursive: true });\n\n this.db = new Database(cachePath);\n this.ttlMs = ttlDays * 24 * 60 * 60 * 1000;\n this.initializeSchema();\n }\n\n private initializeSchema(): void {\n this.db.run(`\n CREATE TABLE IF NOT EXISTS players (\n player_id TEXT PRIMARY KEY,\n code TEXT NOT NULL,\n sig_function TEXT,\n n_function TEXT,\n signature_timestamp INTEGER,\n cached_at INTEGER NOT NULL\n )\n `);\n }\n\n /**\n * Retrieves a cached player entry.\n * @param playerId - The player ID to look up\n * @returns Result containing the cached player or null if not found/expired\n */\n get(playerId: string): Result<CachedPlayer | null, BundlpError> {\n try {\n const stmt = this.db.prepare(`\n SELECT player_id, code, sig_function, n_function, signature_timestamp, cached_at\n FROM players\n WHERE player_id = ?\n `);\n\n const row = stmt.get(playerId) as PlayerRow | null;\n\n if (!row) {\n return ok(null);\n }\n\n if (this.isExpired(row.cached_at)) {\n this.delete(playerId);\n return ok(null);\n }\n\n return ok({\n playerId: row.player_id,\n code: row.code,\n sigFunction: row.sig_function || '',\n nFunction: row.n_function || '',\n signatureTimestamp: row.signature_timestamp || 0,\n cachedAt: row.cached_at,\n });\n } catch (error) {\n return err(createError('CACHE_ERROR', 'Failed to read from cache', error));\n }\n }\n\n /**\n * Stores a player entry in the cache.\n * @param data - The player data to cache\n * @returns Result indicating success or failure\n */\n set(data: CachedPlayer): Result<void, BundlpError> {\n try {\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO players (\n player_id, code, sig_function, n_function, signature_timestamp, cached_at\n ) VALUES (?, ?, ?, ?, ?, ?)\n `);\n\n stmt.run(\n data.playerId,\n data.code,\n data.sigFunction,\n data.nFunction,\n data.signatureTimestamp,\n data.cachedAt\n );\n\n return ok(undefined);\n } catch (error) {\n return err(createError('CACHE_ERROR', 'Failed to write to cache', error));\n }\n }\n\n /**\n * Deletes a specific player entry from the cache.\n * @param playerId - The player ID to delete\n * @returns Result indicating success or failure\n */\n delete(playerId: string): Result<void, BundlpError> {\n try {\n const stmt = this.db.prepare('DELETE FROM players WHERE player_id = ?');\n stmt.run(playerId);\n return ok(undefined);\n } catch (error) {\n return err(createError('CACHE_ERROR', 'Failed to delete from cache', error));\n }\n }\n\n /**\n * Clears all entries from the cache.\n * @returns Result indicating success or failure\n */\n clear(): Result<void, BundlpError> {\n try {\n this.db.run('DELETE FROM players');\n return ok(undefined);\n } catch (error) {\n return err(createError('CACHE_ERROR', 'Failed to clear cache', error));\n }\n }\n\n /**\n * Retrieves the most recent valid cached player entry.\n * Used to avoid re-downloading player.js when we have valid cache.\n * @returns Result containing the cached player or null if none valid\n */\n getLatest(): Result<CachedPlayer | null, BundlpError> {\n try {\n const stmt = this.db.prepare(`\n SELECT player_id, code, sig_function, n_function, signature_timestamp, cached_at\n FROM players\n ORDER BY cached_at DESC\n LIMIT 1\n `);\n\n const row = stmt.get() as PlayerRow | null;\n\n if (!row) {\n return ok(null);\n }\n\n if (this.isExpired(row.cached_at)) {\n this.delete(row.player_id);\n return ok(null);\n }\n\n return ok({\n playerId: row.player_id,\n code: row.code,\n sigFunction: row.sig_function || '',\n nFunction: row.n_function || '',\n signatureTimestamp: row.signature_timestamp || 0,\n cachedAt: row.cached_at,\n });\n } catch (error) {\n return err(createError('CACHE_ERROR', 'Failed to read latest from cache', error));\n }\n }\n\n /**\n * Closes the database connection.\n */\n close(): void {\n this.db.close();\n }\n\n private isExpired(cachedAt: number): boolean {\n return Date.now() - cachedAt > this.ttlMs;\n }\n}\n","import { parse } from 'meriyah';\nimport { httpClient } from '../http/client';\nimport { ok, err, type Result, isOk } from '../result';\nimport { createError, type BundlpError } from '../types/error.types';\nimport { YOUTUBE_BASE_URL } from '../utils/constants';\nimport { sigMatcher, findNFunctionCandidates, timestampMatcher, walkAst, type ASTNode } from './ast/matchers';\nimport { findFunctionDefinition, extractCodeWithDependencies } from './ast/extractor';\nimport { PlayerCache } from './cache';\nimport { join } from 'node:path';\n\ntype CipherFunction = (input: string) => string;\n\n/**\n * Handles YouTube player.js downloading, parsing, and cipher function extraction.\n * Uses AST-based extraction for robustness against YouTube's obfuscation changes.\n */\nexport class Player {\n private cache: PlayerCache | null = null;\n private playerCode: string = '';\n private sigFunctionCode: string = '';\n private nFunctionCode: string = '';\n private decipherFunc: CipherFunction | null = null;\n private nFunc: CipherFunction | null = null;\n private signatureTimestamp: number = 0;\n private initialized: boolean = false;\n\n constructor(cacheDir?: string) {\n if (cacheDir) {\n const cachePath = join(cacheDir, 'player.db');\n this.cache = new PlayerCache(cachePath);\n }\n }\n\n /**\n * Downloads and parses the YouTube player.js to extract cipher functions.\n * Uses cache-first strategy to minimize network requests.\n * @param playerUrl - Optional direct URL to player.js, auto-detected if not provided\n * @returns Result indicating success or failure\n */\n async initialize(playerUrl?: string): Promise<Result<void, BundlpError>> {\n if (this.initialized) return ok(undefined);\n\n if (this.cache && !playerUrl) {\n const latestResult = this.cache.getLatest();\n if (isOk(latestResult) && latestResult.value) {\n return this.restoreFromCache(latestResult.value);\n }\n }\n\n if (!playerUrl) {\n const htmlResult = await httpClient.get(YOUTUBE_BASE_URL);\n if (!isOk(htmlResult)) return err(htmlResult.error);\n\n const html = await htmlResult.value.text();\n const match = html.match(/\\/s\\/player\\/[a-zA-Z0-9_-]+\\/[a-zA-Z0-9_.-]+\\/[a-zA-Z0-9_.-]+\\/base\\.js/);\n if (!match) {\n return err(createError('PLAYER_FETCH_FAILED', 'Could not determine player URL'));\n }\n playerUrl = YOUTUBE_BASE_URL + match[0];\n }\n\n const playerId = this.extractPlayerId(playerUrl);\n\n if (this.cache && playerId) {\n const cacheResult = this.cache.get(playerId);\n if (isOk(cacheResult) && cacheResult.value) {\n return this.restoreFromCache(cacheResult.value);\n }\n }\n\n const codeResult = await httpClient.get(playerUrl);\n if (!isOk(codeResult)) return err(codeResult.error);\n\n this.playerCode = await codeResult.value.text();\n const processResult = this.processCode(this.playerCode);\n\n if (isOk(processResult)) {\n this.initialized = true;\n\n if (this.cache && playerId) {\n this.cache.set({\n playerId,\n code: this.playerCode,\n sigFunction: this.sigFunctionCode,\n nFunction: this.nFunctionCode,\n signatureTimestamp: this.signatureTimestamp,\n cachedAt: Date.now(),\n });\n }\n }\n\n return processResult;\n }\n\n private extractPlayerId(playerUrl: string): string | null {\n const match = playerUrl.match(/\\/s\\/player\\/([a-zA-Z0-9_-]+)\\//);\n return match ? match[1] : null;\n }\n\n private restoreFromCache(cached: any): Result<void, BundlpError> {\n try {\n this.playerCode = cached.code;\n this.sigFunctionCode = cached.sigFunction;\n this.nFunctionCode = cached.nFunction;\n this.signatureTimestamp = cached.signatureTimestamp;\n\n if (this.sigFunctionCode) {\n this.decipherFunc = new Function('sig', this.sigFunctionCode) as CipherFunction;\n }\n\n if (this.nFunctionCode) {\n this.nFunc = new Function('n', this.nFunctionCode) as CipherFunction;\n }\n\n this.initialized = true;\n return ok(undefined);\n } catch (error) {\n return err(createError('CACHE_ERROR', 'Failed to restore from cache', error));\n }\n }\n\n private processCode(code: string): Result<void, BundlpError> {\n try {\n const ast = parse(code, { ranges: true, next: true }) as unknown as ASTNode;\n\n this.extractSignatureTimestamp(ast);\n this.extractDecipherFunction(ast, code);\n this.extractNFunction(ast, code);\n\n return ok(undefined);\n } catch (error) {\n return err(createError('PARSE_ERROR', 'Failed to parse player.js', error));\n }\n }\n\n private extractSignatureTimestamp(ast: ASTNode): void {\n const stsNode = walkAst(ast, timestampMatcher);\n if (stsNode) {\n const value = (stsNode as ASTNode).value as ASTNode | undefined;\n if (value?.type === 'Literal' && typeof value.value === 'number') {\n this.signatureTimestamp = value.value;\n }\n }\n }\n\n private extractDecipherFunction(ast: ASTNode, code: string): void {\n const sigCall = walkAst(ast, sigMatcher);\n if (!sigCall) return;\n\n const callee = (sigCall as ASTNode).callee as ASTNode | undefined;\n if (callee?.type !== 'Identifier') return;\n\n const funcName = callee.name as string;\n const funcDef = findFunctionDefinition(ast, funcName);\n if (!funcDef) return;\n\n const args = (sigCall as ASTNode).arguments as ASTNode[] | undefined;\n const modeArg = args?.[0];\n const modeValue = modeArg?.type === 'Literal' && typeof modeArg.value === 'number'\n ? modeArg.value\n : 83;\n\n const funcCode = extractCodeWithDependencies(code, funcDef, ast, funcName);\n if (!funcCode) return;\n\n this.sigFunctionCode = `\n ${funcCode}\n function __decipher_wrapper__(input) {\n var result = ${funcName}(${modeValue}, input);\n return Array.isArray(result) ? result.join('') : result;\n }\n return __decipher_wrapper__(sig);\n `;\n\n try {\n this.decipherFunc = new Function('sig', this.sigFunctionCode) as CipherFunction;\n } catch {\n this.decipherFunc = null;\n }\n }\n\n private extractNFunction(ast: ASTNode, code: string): void {\n const candidates = findNFunctionCandidates(ast);\n let bestCandidate: { name: string; code: string; size: number } | null = null;\n\n for (const nFuncName of candidates) {\n const nFuncDef = findFunctionDefinition(ast, nFuncName);\n if (!nFuncDef) continue;\n\n if (nFuncDef.type !== 'FunctionExpression' &&\n nFuncDef.type !== 'ArrowFunctionExpression' &&\n nFuncDef.type !== 'FunctionDeclaration') {\n continue;\n }\n\n const nFuncCode = extractCodeWithDependencies(code, nFuncDef, ast, nFuncName);\n\n if (!bestCandidate || nFuncCode.length > bestCandidate.size) {\n bestCandidate = { name: nFuncName, code: nFuncCode, size: nFuncCode.length };\n }\n }\n\n if (!bestCandidate) return;\n\n this.nFunctionCode = `\n ${bestCandidate.code}\n function __n_wrapper__(input) {\n return ${bestCandidate.name}(input);\n }\n return __n_wrapper__(n);\n `;\n\n try {\n this.nFunc = new Function('n', this.nFunctionCode) as CipherFunction;\n } catch {\n this.nFunc = null;\n }\n }\n\n /**\n * Returns the signature timestamp extracted from player.js.\n * Required for some InnerTube API calls.\n */\n getSignatureTimestamp(): number {\n return this.signatureTimestamp;\n }\n\n /**\n * Deciphers a signature cipher string and constructs the final playback URL.\n * @param baseUrl - The base URL from the format\n * @param signatureCipher - The encoded signature cipher string\n * @returns The deciphered playback URL\n */\n decipher(baseUrl: string, signatureCipher: string): string {\n if (!this.decipherFunc) {\n return baseUrl;\n }\n\n const params = new URLSearchParams(signatureCipher);\n const urlParam = params.get('url');\n const sig = params.get('s');\n const sp = params.get('sp') || 'sig';\n\n if (!sig || !urlParam) return baseUrl;\n\n try {\n const decryptedSig = this.decipherFunc(decodeURIComponent(sig));\n return `${decodeURIComponent(urlParam)}&${sp}=${encodeURIComponent(decryptedSig)}`;\n } catch {\n return baseUrl;\n }\n }\n\n /**\n * Deobfuscates the 'n' parameter to prevent throttling.\n * @param nParam - The obfuscated n parameter value\n * @returns The deobfuscated n parameter value\n */\n deobfuscateN(nParam: string): string {\n if (!this.nFunc) return nParam;\n\n try {\n return this.nFunc(nParam);\n } catch {\n return nParam;\n }\n }\n}\n","/**\n * Retry utilities with exponential backoff.\n * Provides automatic retry logic for transient failures.\n * @module http/retry\n */\n\nimport { RETRY_DEFAULTS } from '../utils/constants';\n\nexport interface RetryOptions {\n retries?: number;\n delay?: number;\n backoff?: number;\n maxDelay?: number;\n shouldRetry?: (error: Error) => boolean;\n onRetry?: (error: Error, attempt: number) => void;\n}\n\nconst NON_RETRYABLE_PATTERNS = ['invalid', 'not found', 'drm', 'private'] as const;\n\n/**\n * Executes a function with automatic retry on failure.\n * @param fn - The async function to execute\n * @param options - Retry configuration options\n * @returns The result of the function if successful\n * @throws The last error if all retries are exhausted\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options: RetryOptions = {}\n): Promise<T> {\n const {\n retries = RETRY_DEFAULTS.RETRIES,\n delay = RETRY_DEFAULTS.DELAY,\n backoff = RETRY_DEFAULTS.BACKOFF,\n maxDelay = RETRY_DEFAULTS.MAX_DELAY,\n shouldRetry = defaultShouldRetry,\n onRetry,\n } = options;\n\n let lastError: Error;\n\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error as Error;\n\n if (attempt < retries && shouldRetry(lastError)) {\n const waitTime = Math.min(delay * Math.pow(backoff, attempt), maxDelay);\n onRetry?.(lastError, attempt + 1);\n await sleep(waitTime);\n }\n }\n }\n\n throw lastError!;\n}\n\nfunction defaultShouldRetry(error: Error): boolean {\n const message = error.message.toLowerCase();\n return !NON_RETRYABLE_PATTERNS.some(pattern => message.includes(pattern));\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import type { Format } from '../types/video.types';\nimport type { RawFormat } from '../validation/schemas';\n\n/**\n * Parses a raw format object from InnerTube response into a typed Format.\n * @param raw - The raw format object from streaming data\n * @param isAdaptive - Whether this is an adaptive format (video-only or audio-only)\n * @returns Parsed Format object\n */\nexport function parseFormat(raw: RawFormat, isAdaptive: boolean): Format {\n return {\n itag: raw.itag,\n url: raw.url || '',\n mimeType: raw.mimeType,\n codecs: extractCodecs(raw.mimeType),\n bitrate: raw.bitrate,\n width: raw.width,\n height: raw.height,\n fps: raw.fps,\n qualityLabel: raw.qualityLabel,\n audioSampleRate: raw.audioSampleRate ? parseInt(raw.audioSampleRate, 10) : undefined,\n audioChannels: raw.audioChannels,\n contentLength: raw.contentLength ? parseInt(raw.contentLength, 10) : undefined,\n hasDrm: !!raw.drmFamilies,\n isAdaptive,\n };\n}\n\n/**\n * Extracts codec strings from a mimeType.\n * @param mimeType - The mimeType string containing codec info\n * @returns Array of codec strings\n */\nfunction extractCodecs(mimeType: string): string[] {\n const match = mimeType.match(/codecs=\"([^\"]+)\"/);\n if (!match) return [];\n return match[1].split(', ');\n}\n\n/**\n * Categorizes formats into combined (progressive), video-only, and audio-only.\n * @param formats - Array of all formats\n * @returns Object with categorized formats\n */\nexport function categorizeFormats(formats: Format[]): {\n combined: Format[];\n video: Format[];\n audio: Format[];\n} {\n const combined: Format[] = [];\n const video: Format[] = [];\n const audio: Format[] = [];\n\n for (const format of formats) {\n if (!format.isAdaptive) {\n combined.push(format);\n } else if (format.mimeType.includes('video')) {\n video.push(format);\n } else if (format.mimeType.includes('audio')) {\n audio.push(format);\n }\n }\n\n return { combined, video, audio };\n}\n","import type { Player } from '../player/player';\nimport type { RawFormat } from '../validation/schemas';\n\n/**\n * Handles deciphering of YouTube format URLs.\n * Processes signature ciphers and n-parameter obfuscation.\n */\nexport class FormatDecipher {\n constructor(private player: Player) {}\n\n /**\n * Deciphers a single format's URL.\n * @param format - The raw format with potentially ciphered URL\n * @returns Format with deciphered URL\n */\n decipher(format: RawFormat): RawFormat {\n // If URL is already present and no cipher needed, return as-is\n if (format.url && !format.signatureCipher && !format.cipher) {\n return format;\n }\n\n let url = format.url || '';\n\n if (format.signatureCipher || format.cipher) {\n url = this.player.decipher(url, format.signatureCipher || format.cipher || '');\n }\n\n if (url && url.includes('n=')) {\n url = this.deobfuscateNParam(url);\n }\n\n return { ...format, url };\n }\n\n /**\n * Deciphers a batch of formats.\n * @param formats - Array of raw formats\n * @returns Array of formats with deciphered URLs\n */\n decipherBatch(formats: RawFormat[]): RawFormat[] {\n return formats.map(format => this.decipher(format));\n }\n\n private deobfuscateNParam(url: string): string {\n try {\n const urlObj = new URL(url);\n const nParam = urlObj.searchParams.get('n');\n if (nParam) {\n const deobfuscatedN = this.player.deobfuscateN(nParam);\n urlObj.searchParams.set('n', deobfuscatedN);\n return urlObj.toString();\n }\n } catch {\n return url;\n }\n return url;\n }\n}\n","export interface HlsPlaylist {\n type: 'master' | 'media';\n version: number;\n variants?: HlsVariant[];\n segments?: HlsSegment[];\n targetDuration?: number;\n}\n\nexport interface HlsVariant {\n url: string;\n bandwidth: number;\n resolution?: string;\n codecs?: string;\n frameRate?: number;\n}\n\nexport interface HlsSegment {\n url: string;\n duration: number;\n byteRange?: { start: number; length: number };\n}\n\nimport { ok, err, type Result } from '../result';\nimport { createError, type BundlpError } from '../types/error.types';\n\n/**\n * Parses an M3U8 playlist.\n * @param content - M3U8 file content\n * @returns Result containing parsed playlist or error\n */\nexport function parseM3u8(content: string): Result<HlsPlaylist, BundlpError> {\n try {\n const lines = content.split('\\n').map(line => line.trim()).filter(line => line);\n\n if (!lines[0]?.startsWith('#EXTM3U')) {\n return err(createError('PARSE_ERROR', 'Invalid M3U8 file: missing #EXTM3U header'));\n }\n\n const version = extractVersion(lines);\n const isMaster = lines.some(line => line.includes('#EXT-X-STREAM-INF'));\n\n if (isMaster) {\n const variants = parseMasterPlaylist(lines);\n return ok({\n type: 'master',\n version,\n variants\n });\n }\n\n const segments = parseMediaPlaylist(lines);\n const targetDuration = extractTargetDuration(lines);\n\n return ok({\n type: 'media',\n version,\n segments,\n targetDuration\n });\n } catch (error) {\n return err(createError('PARSE_ERROR', 'Failed to parse M3U8', error));\n }\n}\n\n/**\n * Extracts version from M3U8 playlist.\n * @param lines - Playlist lines\n * @returns Version number\n */\nfunction extractVersion(lines: string[]): number {\n const versionLine = lines.find(line => line.startsWith('#EXT-X-VERSION:'));\n if (!versionLine) return 3;\n\n const version = parseInt(versionLine.split(':')[1], 10);\n return isNaN(version) ? 3 : version;\n}\n\n/**\n * Extracts target duration from media playlist.\n * @param lines - Playlist lines\n * @returns Target duration in seconds\n */\nfunction extractTargetDuration(lines: string[]): number | undefined {\n const targetLine = lines.find(line => line.startsWith('#EXT-X-TARGETDURATION:'));\n if (!targetLine) return undefined;\n\n const duration = parseInt(targetLine.split(':')[1], 10);\n return isNaN(duration) ? undefined : duration;\n}\n\n/**\n * Parses master playlist variants.\n * @param lines - Playlist lines\n * @returns Array of HLS variants\n */\nfunction parseMasterPlaylist(lines: string[]): HlsVariant[] {\n const variants: HlsVariant[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n\n if (line.startsWith('#EXT-X-STREAM-INF:')) {\n const attributes = parseStreamInf(line);\n const url = lines[i + 1];\n\n if (url && !url.startsWith('#')) {\n variants.push({\n url,\n bandwidth: attributes.bandwidth,\n resolution: attributes.resolution,\n codecs: attributes.codecs,\n frameRate: attributes.frameRate\n });\n }\n }\n }\n\n return variants;\n}\n\n/**\n * Parses #EXT-X-STREAM-INF attributes.\n * @param line - Stream info line\n * @returns Parsed attributes\n */\nfunction parseStreamInf(line: string): {\n bandwidth: number;\n resolution?: string;\n codecs?: string;\n frameRate?: number;\n} {\n const attrs = line.split(':')[1];\n const bandwidth = extractAttribute(attrs, 'BANDWIDTH');\n const resolution = extractAttribute(attrs, 'RESOLUTION');\n const codecs = extractAttribute(attrs, 'CODECS');\n const frameRateStr = extractAttribute(attrs, 'FRAME-RATE');\n\n return {\n bandwidth: parseInt(bandwidth || '0', 10),\n resolution: resolution || undefined,\n codecs: codecs || undefined,\n frameRate: frameRateStr ? parseFloat(frameRateStr) : undefined\n };\n}\n\n/**\n * Parses media playlist segments.\n * @param lines - Playlist lines\n * @returns Array of HLS segments\n */\nfunction parseMediaPlaylist(lines: string[]): HlsSegment[] {\n const segments: HlsSegment[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n\n if (line.startsWith('#EXTINF:')) {\n const duration = parseFloat(line.split(':')[1].split(',')[0]);\n const url = lines[i + 1];\n\n if (url && !url.startsWith('#')) {\n const byteRange = parseByteRange(lines[i - 1]);\n\n segments.push({\n url,\n duration,\n byteRange\n });\n }\n }\n }\n\n return segments;\n}\n\n/**\n * Parses #EXT-X-BYTERANGE directive.\n * @param line - Byte range line\n * @returns Byte range object or undefined\n */\nfunction parseByteRange(line: string): { start: number; length: number } | undefined {\n if (!line?.startsWith('#EXT-X-BYTERANGE:')) return undefined;\n\n const range = line.split(':')[1];\n const parts = range.split('@');\n\n if (parts.length !== 2) return undefined;\n\n const length = parseInt(parts[0], 10);\n const start = parseInt(parts[1], 10);\n\n if (isNaN(length) || isNaN(start)) return undefined;\n\n return { start, length };\n}\n\n/**\n * Extracts attribute value from M3U8 attribute string.\n * @param attrs - Attribute string\n * @param name - Attribute name\n * @returns Attribute value or undefined\n */\nfunction extractAttribute(attrs: string, name: string): string | undefined {\n const regex = new RegExp(`${name}=([^,]+)`);\n const match = attrs.match(regex);\n\n if (!match) return undefined;\n\n let value = match[1].trim();\n if (value.startsWith('\"') && value.endsWith('\"')) {\n value = value.slice(1, -1);\n }\n\n return value;\n}\n","import { err, type Result, isOk } from '../../result';\nimport { createError, type BundlpError } from '../../types/error.types';\nimport { httpClient } from '../../http/client';\nimport { parseM3u8, type HlsPlaylist } from '../../utils/m3u8';\n\n/**\n * Fetches and parses an HLS manifest.\n * @param manifestUrl - URL to HLS manifest\n * @returns Result containing parsed playlist or error\n */\nexport async function fetchHlsManifest(manifestUrl: string): Promise<Result<HlsPlaylist, BundlpError>> {\n const response = await httpClient.get(manifestUrl);\n\n if (!isOk(response)) {\n return err(response.error);\n }\n\n try {\n const content = await response.value.text();\n return parseM3u8(content);\n } catch (error) {\n return err(createError('PARSE_ERROR', 'Failed to fetch HLS manifest', error));\n }\n}\n","export interface XmlNode {\n type: 'element' | 'text';\n name?: string;\n attributes?: Record<string, string>;\n children?: XmlNode[];\n text?: string;\n}\n\n/**\n * Parses XML string into a simple node tree.\n * @param xml - XML string to parse\n * @returns Root XML node\n */\nexport function parseXml(xml: string): XmlNode {\n const root: XmlNode = { type: 'element', name: 'root', children: [] };\n const stack: XmlNode[] = [root];\n\n const tagRegex = /<\\/?([a-zA-Z0-9_-]+)([^>]*)>/g;\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n\n while ((match = tagRegex.exec(xml)) !== null) {\n const textBefore = xml.slice(lastIndex, match.index).trim();\n if (textBefore && stack.length > 0) {\n const parent = stack[stack.length - 1];\n if (parent.children) {\n parent.children.push({ type: 'text', text: textBefore });\n }\n }\n\n const fullTag = match[0];\n const tagName = match[1];\n const attributes = match[2];\n\n if (fullTag.startsWith('</')) {\n stack.pop();\n } else {\n const node: XmlNode = {\n type: 'element',\n name: tagName,\n attributes: parseAttributes(attributes),\n children: []\n };\n\n const parent = stack[stack.length - 1];\n if (parent.children) {\n parent.children.push(node);\n }\n\n if (!fullTag.endsWith('/>')) {\n stack.push(node);\n }\n }\n\n lastIndex = tagRegex.lastIndex;\n }\n\n return root;\n}\n\n/**\n * Parses XML attributes from a string.\n * @param attrString - Attribute string from XML tag\n * @returns Record of attribute name-value pairs\n */\nfunction parseAttributes(attrString: string): Record<string, string> {\n const attrs: Record<string, string> = {};\n const attrRegex = /([a-zA-Z0-9_-]+)=\"([^\"]*)\"/g;\n let match: RegExpExecArray | null;\n\n while ((match = attrRegex.exec(attrString)) !== null) {\n attrs[match[1]] = match[2];\n }\n\n return attrs;\n}\n\n/**\n * Finds all nodes matching a tag name.\n * @param node - Root node to search\n * @param tagName - Tag name to match\n * @returns Array of matching nodes\n */\nexport function findAll(node: XmlNode, tagName: string): XmlNode[] {\n const results: XmlNode[] = [];\n\n if (node.type === 'element' && node.name === tagName) {\n results.push(node);\n }\n\n if (node.children) {\n for (const child of node.children) {\n results.push(...findAll(child, tagName));\n }\n }\n\n return results;\n}\n\n/**\n * Finds the first node matching a tag name.\n * @param node - Root node to search\n * @param tagName - Tag name to match\n * @returns First matching node or undefined\n */\nexport function findFirst(node: XmlNode, tagName: string): XmlNode | undefined {\n if (node.type === 'element' && node.name === tagName) {\n return node;\n }\n\n if (node.children) {\n for (const child of node.children) {\n const found = findFirst(child, tagName);\n if (found) return found;\n }\n }\n\n return undefined;\n}\n\n/**\n * Gets attribute value from a node.\n * @param node - XML node\n * @param attrName - Attribute name\n * @returns Attribute value or undefined\n */\nexport function getAttribute(node: XmlNode, attrName: string): string | undefined {\n return node.attributes?.[attrName];\n}\n\n/**\n * Gets text content from a node.\n * @param node - XML node\n * @returns Text content or empty string\n */\nexport function getTextContent(node: XmlNode): string {\n if (node.type === 'text') {\n return node.text || '';\n }\n\n if (node.children) {\n return node.children\n .map(child => getTextContent(child))\n .join('');\n }\n\n return '';\n}\n","import { ok, err, type Result } from '../../result';\nimport { createError, type BundlpError } from '../../types/error.types';\nimport { parseXml, findAll, findFirst, getAttribute, getTextContent } from '../../utils/xml';\n\nexport interface DashManifest {\n duration: number;\n adaptationSets: DashAdaptationSet[];\n}\n\nexport interface DashAdaptationSet {\n id: string;\n mimeType: string;\n contentType: 'video' | 'audio';\n representations: DashRepresentation[];\n}\n\nexport interface DashRepresentation {\n id: string;\n bandwidth: number;\n codecs: string;\n width?: number;\n height?: number;\n frameRate?: number;\n audioSampleRate?: number;\n baseUrl: string;\n initRange?: { start: number; end: number };\n indexRange?: { start: number; end: number };\n}\n\n/**\n * Parses a DASH manifest XML string.\n * @param xml - DASH manifest XML\n * @returns Result containing parsed manifest or error\n */\nexport function parseDashManifest(xml: string): Result<DashManifest, BundlpError> {\n try {\n const root = parseXml(xml);\n const mpd = findFirst(root, 'MPD');\n\n if (!mpd) {\n return err(createError('PARSE_ERROR', 'Invalid DASH manifest: missing MPD element'));\n }\n\n const duration = parseDuration(getAttribute(mpd, 'mediaPresentationDuration'));\n const periods = findAll(mpd, 'Period');\n\n const adaptationSets: DashAdaptationSet[] = [];\n\n for (const period of periods) {\n const sets = findAll(period, 'AdaptationSet');\n\n for (const set of sets) {\n const parsed = parseAdaptationSet(set);\n if (parsed) {\n adaptationSets.push(parsed);\n }\n }\n }\n\n return ok({\n duration,\n adaptationSets\n });\n } catch (error) {\n return err(createError('PARSE_ERROR', 'Failed to parse DASH manifest', error));\n }\n}\n\n/**\n * Parses an AdaptationSet element.\n * @param node - AdaptationSet XML node\n * @returns Parsed adaptation set or undefined\n */\nfunction parseAdaptationSet(node: any): DashAdaptationSet | undefined {\n const id = getAttribute(node, 'id') || '';\n const mimeType = getAttribute(node, 'mimeType') || '';\n const contentType = mimeType.startsWith('video') ? 'video' : 'audio';\n\n const representations = findAll(node, 'Representation');\n const parsedReps: DashRepresentation[] = [];\n\n for (const rep of representations) {\n const parsed = parseRepresentation(rep);\n if (parsed) {\n parsedReps.push(parsed);\n }\n }\n\n if (parsedReps.length === 0) return undefined;\n\n return {\n id,\n mimeType,\n contentType,\n representations: parsedReps\n };\n}\n\n/**\n * Parses a Representation element.\n * @param node - Representation XML node\n * @returns Parsed representation or undefined\n */\nfunction parseRepresentation(node: any): DashRepresentation | undefined {\n const id = getAttribute(node, 'id') || '';\n const bandwidthStr = getAttribute(node, 'bandwidth');\n const codecs = getAttribute(node, 'codecs') || '';\n\n if (!bandwidthStr) return undefined;\n\n const bandwidth = parseInt(bandwidthStr, 10);\n if (isNaN(bandwidth)) return undefined;\n\n const widthStr = getAttribute(node, 'width');\n const heightStr = getAttribute(node, 'height');\n const frameRateStr = getAttribute(node, 'frameRate');\n const audioSampleRateStr = getAttribute(node, 'audioSampleRate');\n\n const baseUrlNode = findFirst(node, 'BaseURL');\n const baseUrl = baseUrlNode ? getTextContent(baseUrlNode) : '';\n\n const initRange = parseRange(findFirst(node, 'Initialization'));\n const indexRange = parseRange(findFirst(node, 'SegmentBase'));\n\n return {\n id,\n bandwidth,\n codecs,\n width: widthStr ? parseInt(widthStr, 10) : undefined,\n height: heightStr ? parseInt(heightStr, 10) : undefined,\n frameRate: frameRateStr ? parseFloat(frameRateStr) : undefined,\n audioSampleRate: audioSampleRateStr ? parseInt(audioSampleRateStr, 10) : undefined,\n baseUrl,\n initRange,\n indexRange\n };\n}\n\n/**\n * Parses range attribute from a node.\n * @param node - XML node with range attribute\n * @returns Range object or undefined\n */\nfunction parseRange(node: any): { start: number; end: number } | undefined {\n if (!node) return undefined;\n\n const range = getAttribute(node, 'range');\n if (!range) return undefined;\n\n const parts = range.split('-');\n if (parts.length !== 2) return undefined;\n\n const start = parseInt(parts[0], 10);\n const end = parseInt(parts[1], 10);\n\n if (isNaN(start) || isNaN(end)) return undefined;\n\n return { start, end };\n}\n\n/**\n * Parses ISO 8601 duration string.\n * @param duration - ISO 8601 duration string (e.g., \"PT1H2M3S\")\n * @returns Duration in seconds\n */\nfunction parseDuration(duration: string | undefined): number {\n if (!duration) return 0;\n\n const match = duration.match(/PT(?:(\\d+)H)?(?:(\\d+)M)?(?:([\\d.]+)S)?/);\n if (!match) return 0;\n\n const hours = parseInt(match[1] || '0', 10);\n const minutes = parseInt(match[2] || '0', 10);\n const seconds = parseFloat(match[3] || '0');\n\n return hours * 3600 + minutes * 60 + seconds;\n}\n","import type { HlsPlaylist, HlsSegment as M3u8Segment } from '../../utils/m3u8';\n\nexport interface HlsSegmentInfo {\n url: string;\n duration: number;\n sequence: number;\n byteRange?: { start: number; length: number };\n}\n\nexport interface HlsMediaInfo {\n segments: HlsSegmentInfo[];\n totalDuration: number;\n targetDuration: number;\n}\n\n/**\n * Resolves a potentially relative URL against a base URL.\n * @param baseUrl - Base URL from manifest location\n * @param path - Relative or absolute path\n * @returns Resolved absolute URL\n */\nexport function resolveUrl(baseUrl: string, path: string): string {\n if (path.startsWith('http://') || path.startsWith('https://')) {\n return path;\n }\n\n const url = new URL(baseUrl);\n\n if (path.startsWith('/')) {\n return `${url.protocol}//${url.host}${path}`;\n }\n\n const basePath = url.pathname.substring(0, url.pathname.lastIndexOf('/') + 1);\n return `${url.protocol}//${url.host}${basePath}${path}`;\n}\n\n/**\n * Extracts segment information from a parsed HLS media playlist.\n * @param playlist - Parsed HLS playlist (must be media type)\n * @param manifestUrl - Original manifest URL for resolving relative paths\n * @returns Extracted segment information\n */\nexport function extractHlsSegments(\n playlist: HlsPlaylist,\n manifestUrl: string\n): HlsMediaInfo {\n if (playlist.type !== 'media' || !playlist.segments) {\n return {\n segments: [],\n totalDuration: 0,\n targetDuration: playlist.targetDuration || 0\n };\n }\n\n const segments: HlsSegmentInfo[] = [];\n let totalDuration = 0;\n\n playlist.segments.forEach((segment: M3u8Segment, index: number) => {\n const resolvedUrl = resolveUrl(manifestUrl, segment.url);\n\n segments.push({\n url: resolvedUrl,\n duration: segment.duration,\n sequence: index,\n byteRange: segment.byteRange\n });\n\n totalDuration += segment.duration;\n });\n\n return {\n segments,\n totalDuration,\n targetDuration: playlist.targetDuration || 0\n };\n}\n\n/**\n * Resolves all variant URLs in a master playlist.\n * @param playlist - Parsed HLS master playlist\n * @param manifestUrl - Original manifest URL\n * @returns Playlist with resolved variant URLs\n */\nexport function resolveVariantUrls(\n playlist: HlsPlaylist,\n manifestUrl: string\n): HlsPlaylist {\n if (playlist.type !== 'master' || !playlist.variants) {\n return playlist;\n }\n\n return {\n ...playlist,\n variants: playlist.variants.map(variant => ({\n ...variant,\n url: resolveUrl(manifestUrl, variant.url)\n }))\n };\n}\n","import type { DashManifest, DashRepresentation, DashAdaptationSet } from './parser';\n\nexport interface DashSegment {\n url: string;\n duration: number;\n startTime: number;\n byteRange?: string;\n}\n\nexport interface DashStreamInfo {\n representationId: string;\n bandwidth: number;\n mimeType: string;\n codecs: string;\n width?: number;\n height?: number;\n baseUrl: string;\n initRange?: { start: number; end: number };\n indexRange?: { start: number; end: number };\n}\n\nexport interface DashExtractedInfo {\n duration: number;\n videoStreams: DashStreamInfo[];\n audioStreams: DashStreamInfo[];\n}\n\n/**\n * Extracts stream information from a DASH manifest.\n * @param manifest - Parsed DASH manifest\n * @returns Extracted stream information\n */\nexport function extractDashStreams(manifest: DashManifest): DashExtractedInfo {\n const videoStreams: DashStreamInfo[] = [];\n const audioStreams: DashStreamInfo[] = [];\n\n for (const adaptationSet of manifest.adaptationSets) {\n const streams = adaptationSet.contentType === 'video' ? videoStreams : audioStreams;\n\n for (const rep of adaptationSet.representations) {\n streams.push(representationToStreamInfo(rep, adaptationSet));\n }\n }\n\n videoStreams.sort((a, b) => b.bandwidth - a.bandwidth);\n audioStreams.sort((a, b) => b.bandwidth - a.bandwidth);\n\n return {\n duration: manifest.duration,\n videoStreams,\n audioStreams\n };\n}\n\n/**\n * Converts a DASH representation to stream info.\n * @param rep - DASH representation\n * @param adaptationSet - Parent adaptation set\n * @returns Stream info\n */\nfunction representationToStreamInfo(\n rep: DashRepresentation,\n adaptationSet: DashAdaptationSet\n): DashStreamInfo {\n return {\n representationId: rep.id,\n bandwidth: rep.bandwidth,\n mimeType: adaptationSet.mimeType,\n codecs: rep.codecs,\n width: rep.width,\n height: rep.height,\n baseUrl: rep.baseUrl,\n initRange: rep.initRange,\n indexRange: rep.indexRange\n };\n}\n\n/**\n * Finds the best video stream by resolution.\n * @param streams - Available video streams\n * @param maxHeight - Maximum acceptable height (optional)\n * @returns Best matching stream or undefined\n */\nexport function findBestVideoStream(\n streams: DashStreamInfo[],\n maxHeight?: number\n): DashStreamInfo | undefined {\n if (streams.length === 0) return undefined;\n\n if (!maxHeight) {\n return streams[0];\n }\n\n const filtered = streams.filter(s => s.height && s.height <= maxHeight);\n return filtered[0] || streams[streams.length - 1];\n}\n\n/**\n * Finds the best audio stream by bitrate.\n * @param streams - Available audio streams\n * @param maxBitrate - Maximum acceptable bitrate (optional)\n * @returns Best matching stream or undefined\n */\nexport function findBestAudioStream(\n streams: DashStreamInfo[],\n maxBitrate?: number\n): DashStreamInfo | undefined {\n if (streams.length === 0) return undefined;\n\n if (!maxBitrate) {\n return streams[0];\n }\n\n const filtered = streams.filter(s => s.bandwidth <= maxBitrate);\n return filtered[0] || streams[streams.length - 1];\n}\n\n/**\n * Generates segment URLs for a DASH stream using byte ranges.\n * @param streamInfo - Stream information\n * @param segmentDuration - Target segment duration in seconds\n * @param totalDuration - Total stream duration in seconds\n * @returns Array of segment info\n */\nexport function generateDashSegments(\n streamInfo: DashStreamInfo,\n segmentDuration: number,\n totalDuration: number\n): DashSegment[] {\n const segments: DashSegment[] = [];\n const segmentCount = Math.ceil(totalDuration / segmentDuration);\n\n for (let i = 0; i < segmentCount; i++) {\n const startTime = i * segmentDuration;\n const duration = Math.min(segmentDuration, totalDuration - startTime);\n\n segments.push({\n url: streamInfo.baseUrl,\n duration,\n startTime\n });\n }\n\n return segments;\n}\n","import { isOk } from '../result';\nimport type { Player } from '../player/player';\nimport type { FormatCollection, HlsInfo, DashInfo, HlsVariant } from '../types/video.types';\nimport type { StreamingData, RawFormat } from '../validation/schemas';\nimport { parseFormat, categorizeFormats } from './formats';\nimport { FormatDecipher } from './decipher';\nimport { fetchHlsManifest } from './hls/parser';\nimport { parseDashManifest } from './dash/parser';\nimport { resolveVariantUrls } from './hls/segments';\nimport { extractDashStreams } from './dash/segments';\nimport { httpClient } from '../http/client';\n\n/**\n * Processes streaming data from InnerTube API responses.\n * Handles format parsing, deciphering, and categorization.\n */\nexport class StreamingDataProcessor {\n private decipher: FormatDecipher;\n\n constructor(player: Player) {\n this.decipher = new FormatDecipher(player);\n }\n\n /**\n * Processes streaming data into a categorized FormatCollection.\n * @param streamingData - Raw streaming data from player response\n * @returns Categorized format collection with deciphered URLs\n */\n async process(streamingData: StreamingData): Promise<FormatCollection> {\n const rawFormats = (streamingData.formats || []) as RawFormat[];\n const rawAdaptive = (streamingData.adaptiveFormats || []) as RawFormat[];\n\n const decipheredFormats = this.decipher.decipherBatch(rawFormats);\n const decipheredAdaptive = this.decipher.decipherBatch(rawAdaptive);\n\n const formats = decipheredFormats.map(f => parseFormat(f, false));\n const adaptiveFormats = decipheredAdaptive.map(f => parseFormat(f, true));\n\n const allFormats = [...formats, ...adaptiveFormats];\n const categorized = categorizeFormats(allFormats);\n\n const [hls, dash] = await Promise.all([\n this.extractHlsInfo(streamingData),\n this.extractDashInfo(streamingData)\n ]);\n\n return {\n combined: categorized.combined,\n video: categorized.video,\n audio: categorized.audio,\n hls,\n dash,\n };\n }\n\n private async extractHlsInfo(streamingData: StreamingData): Promise<HlsInfo | undefined> {\n if (!streamingData.hlsManifestUrl) return undefined;\n\n const manifestUrl = streamingData.hlsManifestUrl;\n const result = await fetchHlsManifest(manifestUrl);\n\n if (!isOk(result)) {\n return { manifestUrl, variants: [] };\n }\n\n const playlist = result.value;\n\n if (playlist.type !== 'master' || !playlist.variants) {\n return { manifestUrl, variants: [] };\n }\n\n const resolvedPlaylist = resolveVariantUrls(playlist, manifestUrl);\n const variants: HlsVariant[] = (resolvedPlaylist.variants || []).map(v => ({\n url: v.url,\n bandwidth: v.bandwidth,\n resolution: v.resolution,\n codecs: v.codecs\n }));\n\n return { manifestUrl, variants };\n }\n\n private async extractDashInfo(streamingData: StreamingData): Promise<DashInfo | undefined> {\n if (!streamingData.dashManifestUrl) return undefined;\n\n const manifestUrl = streamingData.dashManifestUrl;\n const response = await httpClient.get(manifestUrl);\n\n if (!isOk(response)) {\n return { manifestUrl, duration: 0 };\n }\n\n try {\n const xml = await response.value.text();\n const parseResult = parseDashManifest(xml);\n\n if (!isOk(parseResult)) {\n return { manifestUrl, duration: 0 };\n }\n\n const streams = extractDashStreams(parseResult.value);\n\n return {\n manifestUrl,\n duration: streams.duration\n };\n } catch {\n return { manifestUrl, duration: 0 };\n }\n }\n}\n","import { ok, err, type Result, isErr } from '../result';\nimport { InnerTubeClient } from '../innertube/client';\nimport { Player } from '../player/player';\nimport { withRetry } from '../http/retry';\nimport type { VideoInfo, FormatCollection } from '../types/video.types';\nimport { createError, type BundlpError } from '../types/error.types';\nimport type { ClientName } from '../utils/constants';\nimport { YOUTUBE_BASE_URL, VIDEO_ID_LENGTH, RETRY_DEFAULTS } from '../utils/constants';\nimport type { PlayerResponse, StreamingData } from '../validation/schemas';\nimport { StreamingDataProcessor } from '../streaming/processor';\n\nexport interface ExtractorConfig {\n poToken?: string;\n cacheDir?: string;\n preferredClient?: ClientName;\n}\n\nconst VIDEO_ID_PATTERNS = [\n /(?:youtube\\.com\\/watch\\?v=|youtu\\.be\\/)([a-zA-Z0-9_-]{11})/,\n /youtube\\.com\\/embed\\/([a-zA-Z0-9_-]{11})/,\n /youtube\\.com\\/shorts\\/([a-zA-Z0-9_-]{11})/,\n /youtube\\.com\\/live\\/([a-zA-Z0-9_-]{11})/,\n /youtube\\.com\\/v\\/([a-zA-Z0-9_-]{11})/,\n /youtube-nocookie\\.com\\/embed\\/([a-zA-Z0-9_-]{11})/,\n /m\\.youtube\\.com\\/watch\\?v=([a-zA-Z0-9_-]{11})/,\n /music\\.youtube\\.com\\/watch\\?v=([a-zA-Z0-9_-]{11})/,\n] as const;\n\n/**\n * Main YouTube video extractor class.\n * Handles video information extraction using InnerTube API.\n */\nexport class YouTubeExtractor {\n private client: InnerTubeClient;\n private player: Player;\n private config: ExtractorConfig;\n\n constructor(config: ExtractorConfig = {}) {\n this.config = config;\n this.client = new InnerTubeClient({ initialClient: config.preferredClient });\n this.player = new Player(config.cacheDir);\n }\n\n /**\n * Extracts video information from a YouTube URL or video ID.\n * @param url - YouTube URL or video ID\n * @returns Result containing VideoInfo or BundlpError\n */\n async extract(url: string): Promise<Result<VideoInfo, BundlpError>> {\n const videoIdResult = this.parseVideoId(url);\n if (isErr(videoIdResult)) {\n return videoIdResult;\n }\n\n return withRetry(\n () => this.realExtract(videoIdResult.value),\n {\n retries: RETRY_DEFAULTS.RETRIES,\n delay: RETRY_DEFAULTS.DELAY,\n backoff: RETRY_DEFAULTS.BACKOFF,\n }\n );\n }\n\n private parseVideoId(url: string): Result<string, BundlpError> {\n for (const pattern of VIDEO_ID_PATTERNS) {\n const match = url.match(pattern);\n if (match) return ok(match[1]);\n }\n\n const videoIdPattern = new RegExp(`^[a-zA-Z0-9_-]{${VIDEO_ID_LENGTH}}$`);\n if (videoIdPattern.test(url)) {\n return ok(url);\n }\n\n return err(createError('INVALID_URL', `Could not extract video ID from: ${url}`));\n }\n\n private async realExtract(videoId: string): Promise<Result<VideoInfo, BundlpError>> {\n const playerResult = await this.player.initialize();\n if (isErr(playerResult)) return err(playerResult.error);\n\n const responseResult = await this.client.fetchPlayerWithFallback(videoId, {\n signatureTimestamp: this.player.getSignatureTimestamp(),\n poToken: this.config.poToken\n });\n\n if (isErr(responseResult)) return err(responseResult.error);\n const playerResponse = responseResult.value;\n\n if (playerResponse.playabilityStatus.status === 'ERROR') {\n return err(createError('VIDEO_UNAVAILABLE', playerResponse.playabilityStatus.reason || 'Video unavailable'));\n }\n\n if (!playerResponse.streamingData) {\n return err(createError('VIDEO_UNAVAILABLE', 'No streaming data found'));\n }\n\n const formats = await this.processFormats(playerResponse.streamingData);\n\n return ok(this.assembleVideoInfo(videoId, playerResponse, formats));\n }\n\n private async processFormats(streamingData: StreamingData): Promise<FormatCollection> {\n const processor = new StreamingDataProcessor(this.player);\n return processor.process(streamingData);\n }\n\n private assembleVideoInfo(\n videoId: string,\n playerResponse: PlayerResponse,\n formats: FormatCollection\n ): VideoInfo {\n const details = playerResponse.videoDetails!;\n const microformat = playerResponse.microformat?.playerMicroformatRenderer;\n\n return {\n id: videoId,\n title: details.title,\n description: details.shortDescription,\n duration: parseInt(details.lengthSeconds, 10),\n uploadDate: microformat?.uploadDate,\n channel: {\n id: details.channelId,\n name: details.author,\n url: `${YOUTUBE_BASE_URL}/channel/${details.channelId}`\n },\n viewCount: parseInt(details.viewCount, 10),\n thumbnails: details.thumbnail.thumbnails,\n formats,\n subtitles: new Map(),\n isLive: details.isLiveContent,\n isPrivate: details.isPrivate\n };\n }\n}\n","/**\n * HTTP Headers Utilities for YouTube Downloads\n *\n * Provides headers needed for downloading from deciphered YouTube URLs.\n * These headers are extracted from bundlp's InnerTube client configurations.\n */\n\nimport { INNERTUBE_CLIENTS } from './constants'\n\n/**\n * Get HTTP headers for downloading from deciphered YouTube URLs\n * Based on the client type used for extraction\n *\n * @param clientType - The client type to use (WEB, ANDROID, TV, IOS)\n * @returns Object with required HTTP headers for YouTube CDN requests\n */\nexport function getDownloadHeaders(\n clientType: 'WEB' | 'ANDROID' | 'TV' | 'IOS' = 'ANDROID'\n): Record<string, string> {\n const client = INNERTUBE_CLIENTS[clientType]\n\n return {\n 'User-Agent': client.HEADERS['User-Agent'],\n 'Accept': '*/*',\n 'Accept-Encoding': 'identity', // No compression for direct downloads\n 'Referer': 'https://www.youtube.com/',\n 'Origin': 'https://www.youtube.com',\n 'Sec-Fetch-Mode': 'no-cors'\n }\n}\n\n/**\n * Get minimal headers that work for most YouTube CDN requests\n * Use this as a fallback if full headers cause issues\n *\n * @returns Minimal set of headers needed for YouTube downloads\n */\nexport function getMinimalDownloadHeaders(): Record<string, string> {\n return {\n 'User-Agent': 'Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36',\n 'Referer': 'https://www.youtube.com/'\n }\n}\n","import type { ClientName } from '../utils/constants';\n\nexport type PoTokenRequirement = 'required' | 'recommended' | 'not_required';\n\nexport interface PoTokenPolicy {\n GVS: PoTokenRequirement | {\n HTTPS: PoTokenRequirement;\n DASH: PoTokenRequirement;\n HLS: PoTokenRequirement;\n };\n PLAYER: PoTokenRequirement;\n SUBS: PoTokenRequirement;\n notRequiredForPremium?: boolean;\n}\n\n/**\n * PO Token policies for each InnerTube client.\n * Defines when PO tokens are required for different endpoints.\n */\nexport const PO_TOKEN_POLICIES: Record<ClientName, PoTokenPolicy> = {\n WEB: {\n GVS: { HTTPS: 'required', DASH: 'required', HLS: 'recommended' },\n PLAYER: 'not_required',\n SUBS: 'not_required',\n notRequiredForPremium: true,\n },\n ANDROID_SDKLESS: {\n GVS: 'not_required',\n PLAYER: 'not_required',\n SUBS: 'not_required',\n },\n ANDROID: {\n GVS: 'not_required',\n PLAYER: 'not_required',\n SUBS: 'not_required',\n },\n TV: {\n GVS: 'not_required',\n PLAYER: 'not_required',\n SUBS: 'not_required',\n },\n TV_EMBEDDED: {\n GVS: 'not_required',\n PLAYER: 'not_required',\n SUBS: 'not_required',\n },\n IOS: {\n GVS: { HTTPS: 'required', DASH: 'required', HLS: 'recommended' },\n PLAYER: 'recommended',\n SUBS: 'not_required',\n },\n};\n","import { ok, err, type Result } from '../../result';\nimport { createError, type BundlpError } from '../../types/error.types';\nimport type { DescrambledChallenge } from '../types';\n\nconst WAA_CREATE_ENDPOINT = 'https://jnn-pa.googleapis.com/$rpc/google.internal.waa.v1.Waa/Create';\nconst INNERTUBE_ATT_ENDPOINT = 'https://www.youtube.com/youtubei/v1/att/get';\nconst GOOG_API_KEY = 'AIzaSyDyT5W0Jh49F30Pqqtyfdf7pDLFKLJoAnw';\nconst REQUEST_KEY = 'O43z0dpjhgX20SCx4KAo';\n\nexport interface AttestationResponse {\n visitorData: string;\n challenge: string;\n program: string;\n}\n\nexport interface ChallengeFetcherOptions {\n timeout?: number;\n}\n\nexport class ChallengeFetcher {\n private timeout: number;\n\n constructor(options: ChallengeFetcherOptions = {}) {\n this.timeout = options.timeout ?? 15000;\n }\n\n async fetchAttestation(): Promise<Result<AttestationResponse, BundlpError>> {\n const payload = {\n context: {\n client: {\n clientName: 'WEB',\n clientVersion: '2.20250222.10.00',\n hl: 'en',\n gl: 'US',\n },\n },\n };\n\n try {\n const response = await fetch(INNERTUBE_ATT_ENDPOINT, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',\n 'Origin': 'https://www.youtube.com',\n 'Referer': 'https://www.youtube.com/',\n },\n body: JSON.stringify(payload),\n signal: AbortSignal.timeout(this.timeout),\n });\n\n if (!response.ok) {\n return err(createError(\n 'BOTGUARD_INIT_FAILED',\n `Attestation request failed with status ${response.status}`\n ));\n }\n\n const data = await response.json();\n return this.parseAttestationResponse(data);\n } catch (error) {\n if (error instanceof Error && error.name === 'TimeoutError') {\n return err(createError('BOTGUARD_INIT_FAILED', 'Attestation fetch timeout'));\n }\n return err(createError('BOTGUARD_INIT_FAILED', 'Failed to fetch attestation', error));\n }\n }\n\n private parseAttestationResponse(data: unknown): Result<AttestationResponse, BundlpError> {\n if (!data || typeof data !== 'object') {\n return err(createError('PARSE_ERROR', 'Invalid attestation response'));\n }\n\n const response = data as Record<string, unknown>;\n const responseContext = response.responseContext as Record<string, unknown> | undefined;\n const botguardData = response.botguardData as Record<string, unknown> | undefined;\n const challenge = response.challenge;\n\n if (!responseContext?.visitorData) {\n return err(createError('PARSE_ERROR', 'Missing visitorData in response'));\n }\n\n if (!challenge || typeof challenge !== 'string') {\n return err(createError('PARSE_ERROR', 'Missing challenge in response'));\n }\n\n if (!botguardData?.program) {\n return err(createError('PARSE_ERROR', 'Missing botguardData.program in response'));\n }\n\n return ok({\n visitorData: responseContext.visitorData as string,\n challenge: challenge,\n program: botguardData.program as string,\n });\n }\n\n async fetchWaaChallenge(): Promise<Result<DescrambledChallenge, BundlpError>> {\n try {\n const response = await fetch(WAA_CREATE_ENDPOINT, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json+protobuf',\n 'x-goog-api-key': GOOG_API_KEY,\n },\n body: JSON.stringify([REQUEST_KEY]),\n signal: AbortSignal.timeout(this.timeout),\n });\n\n if (!response.ok) {\n return err(createError(\n 'BOTGUARD_INIT_FAILED',\n `WAA Create request failed with status ${response.status}`\n ));\n }\n\n const json = await response.json() as unknown[];\n const encoded = json[1] as string | undefined;\n\n if (!encoded || typeof encoded !== 'string') {\n return err(createError('PARSE_ERROR', 'Invalid WAA response format'));\n }\n\n return this.descrambleWaaResponse(encoded);\n } catch (error) {\n if (error instanceof Error && error.name === 'TimeoutError') {\n return err(createError('BOTGUARD_INIT_FAILED', 'WAA Create fetch timeout'));\n }\n return err(createError('BOTGUARD_INIT_FAILED', 'Failed to fetch WAA challenge', error));\n }\n }\n\n private descrambleWaaResponse(encoded: string): Result<DescrambledChallenge, BundlpError> {\n try {\n const decoded = atob(encoded);\n const bytes = new Uint8Array(decoded.length);\n\n for (let i = 0; i < decoded.length; i++) {\n bytes[i] = (decoded.charCodeAt(i) + 97) & 0xFF;\n }\n\n const descrambled = new TextDecoder('utf-8').decode(bytes);\n const parsed = JSON.parse(descrambled) as unknown[];\n\n const messageId = parsed[0] as string;\n const interpreterArray = parsed[1] as unknown[];\n const interpreterHash = parsed[3] as string;\n const program = parsed[4] as string;\n const globalName = parsed[5] as string;\n\n if (!program || !globalName) {\n return err(createError('PARSE_ERROR', 'Missing required fields in WAA response'));\n }\n\n let interpreterScript = '';\n if (Array.isArray(interpreterArray) && interpreterArray.length >= 6) {\n interpreterScript = interpreterArray[5] as string;\n }\n\n if (!interpreterScript || typeof interpreterScript !== 'string') {\n return err(createError('PARSE_ERROR', 'Failed to extract interpreter script'));\n }\n\n return ok({\n messageId: messageId || '',\n interpreterScript,\n interpreterHash: interpreterHash || '',\n program,\n globalName,\n });\n } catch (error) {\n return err(createError('PARSE_ERROR', 'Failed to descramble WAA response', error));\n }\n }\n\n async fetchFullChallenge(): Promise<Result<DescrambledChallenge, BundlpError>> {\n return this.fetchWaaChallenge();\n }\n\n async fetch(): Promise<Result<AttestationResponse, BundlpError>> {\n return this.fetchAttestation();\n }\n}\n","import { JSDOM } from 'jsdom';\nimport { ok, err, isOk, type Result } from '../../result';\nimport { createError, type BundlpError } from '../../types/error.types';\nimport type { DescrambledChallenge, BotGuardClientOptions, ContentBinding } from '../types';\n\ninterface VMFunctions {\n asyncSnapshotFunction?: (callback: (result: string) => void, args: unknown[]) => void;\n shutdownFunction?: () => void;\n passEventFunction?: (args: unknown) => void;\n checkCameraFunction?: (args: unknown) => void;\n}\n\nclass DeferredPromise<T> {\n promise: Promise<T>;\n resolve!: (value: T) => void;\n reject!: (reason?: unknown) => void;\n\n constructor() {\n this.promise = new Promise((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n}\n\nexport class BotGuardClient {\n private dom: JSDOM | null = null;\n private vm: Record<string, unknown> | null = null;\n private program: string;\n private globalName: string;\n private deferredVmFunctions = new DeferredPromise<VMFunctions>();\n private syncSnapshotFunction?: (args: unknown[]) => Promise<string>;\n private initTimeout: number;\n private snapshotTimeout: number;\n\n private constructor(challenge: DescrambledChallenge, options: BotGuardClientOptions = {}) {\n this.program = challenge.program;\n this.globalName = challenge.globalName;\n this.initTimeout = options.timeout ?? 10000;\n this.snapshotTimeout = 5000;\n }\n\n static async create(\n challenge: DescrambledChallenge,\n options: BotGuardClientOptions = {}\n ): Promise<Result<BotGuardClient, BundlpError>> {\n const client = new BotGuardClient(challenge, options);\n const loadResult = await client.load(challenge);\n\n if (!isOk(loadResult)) {\n return loadResult as unknown as Result<BotGuardClient, BundlpError>;\n }\n\n return ok(client);\n }\n\n private async load(challenge: DescrambledChallenge): Promise<Result<void, BundlpError>> {\n try {\n this.dom = new JSDOM('<!DOCTYPE html><html><head></head><body></body></html>', {\n url: 'https://www.youtube.com/',\n runScripts: 'dangerously',\n pretendToBeVisual: true,\n });\n\n const window = this.dom.window as unknown as Record<string, unknown>;\n\n window.trustedTypes = {\n createPolicy: (name: string, rules?: Record<string, Function>) => ({\n name,\n createHTML: rules?.createHTML || ((s: string) => s),\n createScript: rules?.createScript || ((s: string) => s),\n createScriptURL: rules?.createScriptURL || ((s: string) => s),\n }),\n };\n window.fetch = globalThis.fetch;\n window.Request = globalThis.Request;\n window.Response = globalThis.Response;\n window.Headers = globalThis.Headers;\n\n const evalFn = window.eval as (code: string) => unknown;\n evalFn(challenge.interpreterScript);\n\n this.vm = window[this.globalName] as Record<string, unknown>;\n\n if (!this.vm) {\n return err(createError('BOTGUARD_INIT_FAILED', `VM not found at globalName: ${this.globalName}`));\n }\n\n if (typeof this.vm.a !== 'function') {\n return err(createError('BOTGUARD_INIT_FAILED', 'VM init function (a) not found'));\n }\n\n const loadResult = await this.loadProgram();\n if (!isOk(loadResult)) {\n return loadResult;\n }\n\n return ok(undefined);\n } catch (error) {\n return err(createError(\n 'BOTGUARD_INIT_FAILED',\n `Failed to load BotGuard: ${(error as Error).message}`,\n error\n ));\n }\n }\n\n private async loadProgram(): Promise<Result<void, BundlpError>> {\n return new Promise((resolve) => {\n const timeoutId = setTimeout(() => {\n resolve(err(createError('BOTGUARD_INIT_FAILED', 'Program load timeout')));\n }, this.initTimeout);\n\n try {\n const vmFunctionsCallback = (\n asyncSnapshotFunction?: VMFunctions['asyncSnapshotFunction'],\n shutdownFunction?: VMFunctions['shutdownFunction'],\n passEventFunction?: VMFunctions['passEventFunction'],\n checkCameraFunction?: VMFunctions['checkCameraFunction']\n ) => {\n this.deferredVmFunctions.resolve({\n asyncSnapshotFunction,\n shutdownFunction,\n passEventFunction,\n checkCameraFunction\n });\n };\n\n const initFn = this.vm!.a as Function;\n const result = initFn(\n this.program,\n vmFunctionsCallback,\n true,\n undefined,\n () => {},\n [[], []]\n );\n\n clearTimeout(timeoutId);\n\n if (Array.isArray(result) && result[0]) {\n this.syncSnapshotFunction = result[0] as (args: unknown[]) => Promise<string>;\n }\n\n resolve(ok(undefined));\n } catch (error) {\n clearTimeout(timeoutId);\n resolve(err(createError(\n 'BOTGUARD_INIT_FAILED',\n `Program load error: ${(error as Error).message}`,\n error\n )));\n }\n });\n }\n\n async snapshot(binding?: ContentBinding): Promise<Result<string, BundlpError>> {\n const webPoSignalOutput: unknown[] = [];\n\n const snapshotArgs = [\n binding,\n Date.now(),\n webPoSignalOutput,\n false,\n ];\n\n try {\n let result: string;\n\n if (this.syncSnapshotFunction) {\n result = await this.syncSnapshotFunction(snapshotArgs);\n } else {\n const vmFunctions = await Promise.race([\n this.deferredVmFunctions.promise,\n new Promise<VMFunctions>((_, reject) =>\n setTimeout(() => reject(new Error('Timeout waiting for VM functions')), this.snapshotTimeout)\n )\n ]);\n\n if (!vmFunctions.asyncSnapshotFunction) {\n return err(createError('BOTGUARD_SNAPSHOT_FAILED', 'No snapshot function available'));\n }\n\n result = await new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => reject(new Error('Snapshot timeout')), this.snapshotTimeout);\n vmFunctions.asyncSnapshotFunction!((response) => {\n clearTimeout(timeout);\n resolve(response);\n }, snapshotArgs);\n });\n }\n\n return ok(result);\n } catch (error) {\n return err(createError(\n 'BOTGUARD_SNAPSHOT_FAILED',\n `Snapshot failed: ${(error as Error).message}`,\n error\n ));\n }\n }\n\n async snapshotWithSignalOutput(binding?: ContentBinding): Promise<Result<{ snapshot: string; webPoSignalOutput: unknown[] }, BundlpError>> {\n const webPoSignalOutput: unknown[] = [];\n\n const snapshotArgs = [\n binding,\n Date.now(),\n webPoSignalOutput,\n false,\n ];\n\n try {\n let snapshot: string;\n\n if (this.syncSnapshotFunction) {\n snapshot = await this.syncSnapshotFunction(snapshotArgs);\n } else {\n const vmFunctions = await Promise.race([\n this.deferredVmFunctions.promise,\n new Promise<VMFunctions>((_, reject) =>\n setTimeout(() => reject(new Error('Timeout waiting for VM functions')), this.snapshotTimeout)\n )\n ]);\n\n if (!vmFunctions.asyncSnapshotFunction) {\n return err(createError('BOTGUARD_SNAPSHOT_FAILED', 'No snapshot function available'));\n }\n\n snapshot = await new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => reject(new Error('Snapshot timeout')), this.snapshotTimeout);\n vmFunctions.asyncSnapshotFunction!((response) => {\n clearTimeout(timeout);\n resolve(response);\n }, snapshotArgs);\n });\n }\n\n return ok({ snapshot, webPoSignalOutput });\n } catch (error) {\n return err(createError(\n 'BOTGUARD_SNAPSHOT_FAILED',\n `Snapshot failed: ${(error as Error).message}`,\n error\n ));\n }\n }\n\n shutdown(): void {\n this.deferredVmFunctions.promise.then((vmFunctions) => {\n if (vmFunctions.shutdownFunction) {\n try { vmFunctions.shutdownFunction(); } catch {}\n }\n }).catch(() => {});\n\n if (this.dom) {\n this.dom.window.close();\n this.dom = null;\n }\n }\n}\n\nexport function generateColdStartToken(identifier: string, clientState = 1): string {\n const encodedIdentifier = new TextEncoder().encode(identifier);\n\n if (encodedIdentifier.length > 118) {\n throw new Error('Content binding is too long');\n }\n\n const timestamp = Math.floor(Date.now() / 1000);\n const randomKeys = [Math.floor(Math.random() * 256), Math.floor(Math.random() * 256)];\n\n const header = new Uint8Array([\n randomKeys[0], randomKeys[1],\n 0, clientState,\n (timestamp >> 24) & 0xFF,\n (timestamp >> 16) & 0xFF,\n (timestamp >> 8) & 0xFF,\n timestamp & 0xFF,\n ]);\n\n const packet = new Uint8Array(2 + header.length + encodedIdentifier.length);\n packet[0] = 34;\n packet[1] = header.length + encodedIdentifier.length;\n packet.set(header, 2);\n packet.set(encodedIdentifier, 2 + header.length);\n\n const payload = packet.subarray(2);\n const keyLength = randomKeys.length;\n\n for (let i = keyLength; i < payload.length; i++) {\n payload[i] ^= payload[i % keyLength];\n }\n\n return u8ToBase64Url(packet);\n}\n\nfunction u8ToBase64Url(u8: Uint8Array): string {\n const base64 = btoa(String.fromCharCode(...u8));\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_');\n}\n","import { ok, err, isOk, type Result } from '../../result';\nimport { createError, type BundlpError } from '../../types/error.types';\n\nconst WAA_GENERATE_IT_ENDPOINT = 'https://jnn-pa.googleapis.com/$rpc/google.internal.waa.v1.Waa/GenerateIT';\nconst GOOG_API_KEY = 'AIzaSyDyT5W0Jh49F30Pqqtyfdf7pDLFKLJoAnw';\nconst REQUEST_KEY = 'O43z0dpjhgX20SCx4KAo';\n\nexport interface IntegrityTokenData {\n integrityToken: string;\n estimatedTtlSecs: number;\n mintRefreshThreshold: number;\n websafeFallbackToken?: string;\n}\n\nexport interface WebPoMinterOptions {\n timeout?: number;\n}\n\ntype MintCallback = (identifier: Uint8Array) => Promise<Uint8Array>;\ntype GetMinterFn = (integrityToken: Uint8Array) => Promise<MintCallback>;\n\nexport class WebPoMinter {\n private mintCallback: MintCallback;\n\n private constructor(mintCallback: MintCallback) {\n this.mintCallback = mintCallback;\n }\n\n static async create(\n integrityTokenData: IntegrityTokenData,\n webPoSignalOutput: unknown[]\n ): Promise<Result<WebPoMinter, BundlpError>> {\n const getMinter = webPoSignalOutput[0] as GetMinterFn | undefined;\n\n if (!getMinter || typeof getMinter !== 'function') {\n return err(createError('INTEGRITY_TOKEN_FAILED', 'Minter function not found in webPoSignalOutput'));\n }\n\n if (!integrityTokenData.integrityToken) {\n return err(createError('INTEGRITY_TOKEN_FAILED', 'No integrity token provided'));\n }\n\n try {\n const integrityTokenBytes = base64ToU8(integrityTokenData.integrityToken);\n const mintCallback = await getMinter(integrityTokenBytes);\n\n if (typeof mintCallback !== 'function') {\n return err(createError('INTEGRITY_TOKEN_FAILED', 'Invalid mint callback returned'));\n }\n\n return ok(new WebPoMinter(mintCallback));\n } catch (error) {\n return err(createError(\n 'INTEGRITY_TOKEN_FAILED',\n `Failed to create minter: ${(error as Error).message}`,\n error\n ));\n }\n }\n\n async mint(identifier: string): Promise<Result<Uint8Array, BundlpError>> {\n try {\n const identifierBytes = new TextEncoder().encode(identifier);\n const result = await this.mintCallback(identifierBytes);\n\n if (!result) {\n return err(createError('INTEGRITY_TOKEN_FAILED', 'Mint returned undefined'));\n }\n\n if (result instanceof Uint8Array) {\n return ok(result);\n }\n\n if (ArrayBuffer.isView(result)) {\n return ok(new Uint8Array((result as ArrayBufferView).buffer));\n }\n\n if (Array.isArray(result)) {\n return ok(new Uint8Array(result));\n }\n\n return err(createError('INTEGRITY_TOKEN_FAILED', `Mint returned invalid type: ${typeof result}`));\n } catch (error) {\n return err(createError(\n 'INTEGRITY_TOKEN_FAILED',\n `Mint failed: ${(error as Error).message}`,\n error\n ));\n }\n }\n\n async mintAsWebsafeString(identifier: string): Promise<Result<string, BundlpError>> {\n const mintResult = await this.mint(identifier);\n\n if (!isOk(mintResult)) {\n return mintResult as unknown as Result<string, BundlpError>;\n }\n\n return ok(u8ToBase64Url(mintResult.value));\n }\n}\n\nexport async function fetchIntegrityToken(\n botguardResponse: string,\n options: WebPoMinterOptions = {}\n): Promise<Result<IntegrityTokenData, BundlpError>> {\n const timeout = options.timeout ?? 10000;\n\n try {\n const response = await fetch(WAA_GENERATE_IT_ENDPOINT, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json+protobuf',\n 'x-goog-api-key': GOOG_API_KEY,\n },\n body: JSON.stringify([REQUEST_KEY, botguardResponse]),\n signal: AbortSignal.timeout(timeout),\n });\n\n if (!response.ok) {\n return err(createError(\n 'INTEGRITY_TOKEN_FAILED',\n `GenerateIT request failed with status ${response.status}`\n ));\n }\n\n const json = await response.json() as unknown[];\n\n const integrityToken = json[0] as string;\n const estimatedTtlSecs = json[1] as number;\n const mintRefreshThreshold = json[2] as number;\n const websafeFallbackToken = json[3] as string | undefined;\n\n if (!integrityToken) {\n return err(createError('INTEGRITY_TOKEN_FAILED', 'No integrity token in response'));\n }\n\n return ok({\n integrityToken,\n estimatedTtlSecs: estimatedTtlSecs ?? 3600,\n mintRefreshThreshold: mintRefreshThreshold ?? 300,\n websafeFallbackToken,\n });\n } catch (error) {\n if (error instanceof Error && error.name === 'TimeoutError') {\n return err(createError('INTEGRITY_TOKEN_FAILED', 'GenerateIT request timeout'));\n }\n return err(createError('INTEGRITY_TOKEN_FAILED', 'Failed to fetch integrity token', error));\n }\n}\n\nfunction base64ToU8(base64: string): Uint8Array {\n const base64Normalized = base64\n .replace(/-/g, '+')\n .replace(/_/g, '/')\n .replace(/\\./g, '=');\n\n const binary = atob(base64Normalized);\n const bytes = new Uint8Array(binary.length);\n\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n\n return bytes;\n}\n\nfunction u8ToBase64Url(u8: Uint8Array): string {\n const base64 = btoa(String.fromCharCode(...u8));\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_');\n}\n","import { ok, err, isOk, type Result } from '../../result';\nimport { createError, type BundlpError } from '../../types/error.types';\nimport type { PoTokenData, ContentBinding, DescrambledChallenge } from '../types';\nimport type { PoTokenProvider, PoTokenProviderOptions } from './provider.interface';\nimport { ChallengeFetcher, type AttestationResponse } from '../botguard/challenge';\nimport { BotGuardClient } from '../botguard/client';\nimport { WebPoMinter, fetchIntegrityToken, type IntegrityTokenData } from '../minter/web-minter';\n\nconst REFRESH_MARGIN_MS = 10 * 60 * 1000;\n\nexport class LocalBotGuardProvider implements PoTokenProvider {\n readonly name = 'local-botguard';\n readonly priority = 100;\n\n private options: PoTokenProviderOptions;\n private challengeFetcher: ChallengeFetcher;\n private client: BotGuardClient | null = null;\n private challenge: DescrambledChallenge | null = null;\n private attestation: AttestationResponse | null = null;\n private integrityData: IntegrityTokenData | null = null;\n private minter: WebPoMinter | null = null;\n private initPromise: Promise<Result<void, BundlpError>> | null = null;\n private createdAt: number = 0;\n\n constructor(options: PoTokenProviderOptions = {}) {\n this.options = options;\n this.challengeFetcher = new ChallengeFetcher({ timeout: options.timeout });\n }\n\n async isAvailable(): Promise<boolean> {\n try {\n await import('jsdom');\n return true;\n } catch {\n return false;\n }\n }\n\n async generate(identifier: string, _binding?: ContentBinding): Promise<Result<PoTokenData, BundlpError>> {\n const initResult = await this.ensureInitialized();\n if (!isOk(initResult)) {\n return initResult as unknown as Result<PoTokenData, BundlpError>;\n }\n\n if (!this.minter || !this.integrityData) {\n return err(createError('BOTGUARD_INIT_FAILED', 'Minter not initialized'));\n }\n\n const tokenResult = await this.minter.mintAsWebsafeString(identifier);\n if (!isOk(tokenResult)) {\n return tokenResult as unknown as Result<PoTokenData, BundlpError>;\n }\n\n const now = Date.now();\n const ttlMs = (this.integrityData.estimatedTtlSecs ?? 43200) * 1000;\n\n return ok({\n token: tokenResult.value,\n createdAt: now,\n expiresAt: now + ttlMs,\n refreshAt: now + ttlMs - REFRESH_MARGIN_MS,\n bindingType: 'session',\n bindingValue: identifier,\n client: 'WEB',\n context: 'GVS',\n });\n }\n\n private async ensureInitialized(): Promise<Result<void, BundlpError>> {\n if (this.minter && this.integrityData) {\n const now = Date.now();\n const refreshThresholdMs = (this.integrityData.mintRefreshThreshold ?? 100) * 1000;\n const tokenAge = now - this.createdAt;\n\n if (tokenAge < refreshThresholdMs * 1000) {\n return ok(undefined);\n }\n\n this.reset();\n }\n\n if (this.initPromise) {\n return this.initPromise;\n }\n\n this.initPromise = this.initialize();\n const result = await this.initPromise;\n this.initPromise = null;\n\n return result;\n }\n\n private async initialize(): Promise<Result<void, BundlpError>> {\n const challengeResult = await this.challengeFetcher.fetchFullChallenge();\n if (!isOk(challengeResult)) {\n return challengeResult as unknown as Result<void, BundlpError>;\n }\n this.challenge = challengeResult.value;\n\n const attResult = await this.challengeFetcher.fetchAttestation();\n if (!isOk(attResult)) {\n return attResult as unknown as Result<void, BundlpError>;\n }\n this.attestation = attResult.value;\n\n const clientResult = await BotGuardClient.create(this.challenge, { timeout: this.options.timeout });\n if (!isOk(clientResult)) {\n return clientResult as unknown as Result<void, BundlpError>;\n }\n this.client = clientResult.value;\n\n const snapshotResult = await this.client.snapshotWithSignalOutput();\n if (!isOk(snapshotResult)) {\n return snapshotResult as unknown as Result<void, BundlpError>;\n }\n\n const { snapshot, webPoSignalOutput } = snapshotResult.value;\n\n const integrityResult = await fetchIntegrityToken(snapshot, { timeout: this.options.timeout });\n if (!isOk(integrityResult)) {\n return integrityResult as unknown as Result<void, BundlpError>;\n }\n this.integrityData = integrityResult.value;\n this.createdAt = Date.now();\n\n const minterResult = await WebPoMinter.create(this.integrityData, webPoSignalOutput);\n if (!isOk(minterResult)) {\n return minterResult as unknown as Result<void, BundlpError>;\n }\n this.minter = minterResult.value;\n\n return ok(undefined);\n }\n\n private reset(): void {\n if (this.client) {\n this.client.shutdown();\n this.client = null;\n }\n this.challenge = null;\n this.attestation = null;\n this.integrityData = null;\n this.minter = null;\n }\n\n shutdown(): void {\n this.reset();\n }\n\n getVisitorData(): string | undefined {\n return this.attestation?.visitorData;\n }\n}\n","import { Database } from 'bun:sqlite';\nimport { ok, err, type Result } from '../../result';\nimport { createError, type BundlpError } from '../../types/error.types';\nimport type { PoTokenData, PoTokenContext, CachedToken } from '../types';\nimport type { ClientName } from '../../utils/constants';\nimport { mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\n\nexport class TokenCache {\n private db: Database;\n\n constructor(cachePath: string) {\n const dir = dirname(cachePath);\n mkdirSync(dir, { recursive: true });\n\n this.db = new Database(cachePath);\n this.initializeSchema();\n }\n\n private initializeSchema(): void {\n this.db.run(`\n CREATE TABLE IF NOT EXISTS tokens (\n id TEXT PRIMARY KEY,\n token TEXT NOT NULL,\n integrity_token TEXT,\n binding_type TEXT NOT NULL,\n binding_value TEXT NOT NULL,\n client TEXT NOT NULL,\n context TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n expires_at INTEGER NOT NULL,\n refresh_at INTEGER NOT NULL\n )\n `);\n\n this.db.run(`\n CREATE INDEX IF NOT EXISTS idx_tokens_lookup\n ON tokens(binding_value, client, context)\n `);\n\n this.db.run(`\n CREATE INDEX IF NOT EXISTS idx_tokens_expires\n ON tokens(expires_at)\n `);\n\n this.db.run(`\n CREATE INDEX IF NOT EXISTS idx_tokens_refresh\n ON tokens(refresh_at)\n `);\n }\n\n get(\n bindingValue: string,\n client: ClientName,\n context: PoTokenContext\n ): Result<PoTokenData | null, BundlpError> {\n try {\n const stmt = this.db.prepare(`\n SELECT * FROM tokens\n WHERE binding_value = ? AND client = ? AND context = ?\n AND expires_at > ?\n ORDER BY created_at DESC\n LIMIT 1\n `);\n\n const row = stmt.get(bindingValue, client, context, Date.now()) as CachedToken | null;\n\n if (!row) {\n return ok(null);\n }\n\n return ok(this.rowToTokenData(row));\n } catch (error) {\n return err(createError('CACHE_ERROR', 'Failed to read token from cache', error));\n }\n }\n\n getByClient(client: ClientName): Result<PoTokenData[], BundlpError> {\n try {\n const stmt = this.db.prepare(`\n SELECT * FROM tokens\n WHERE client = ? AND expires_at > ?\n ORDER BY created_at DESC\n `);\n\n const rows = stmt.all(client, Date.now()) as CachedToken[];\n return ok(rows.map(this.rowToTokenData));\n } catch (error) {\n return err(createError('CACHE_ERROR', 'Failed to get tokens by client', error));\n }\n }\n\n getExpiringSoon(marginMs: number): Result<PoTokenData[], BundlpError> {\n try {\n const refreshThreshold = Date.now() + marginMs;\n const stmt = this.db.prepare(`\n SELECT * FROM tokens\n WHERE refresh_at <= ? AND expires_at > ?\n ORDER BY refresh_at ASC\n `);\n\n const rows = stmt.all(refreshThreshold, Date.now()) as CachedToken[];\n return ok(rows.map(this.rowToTokenData));\n } catch (error) {\n return err(createError('CACHE_ERROR', 'Failed to get expiring tokens', error));\n }\n }\n\n set(data: PoTokenData): Result<void, BundlpError> {\n try {\n const id = `${data.bindingValue}:${data.client}:${data.context}`;\n\n const stmt = this.db.prepare(`\n INSERT OR REPLACE INTO tokens (\n id, token, integrity_token, binding_type, binding_value,\n client, context, created_at, expires_at, refresh_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n stmt.run(\n id,\n data.token,\n data.integrityToken ?? null,\n data.bindingType,\n data.bindingValue,\n data.client,\n data.context,\n data.createdAt,\n data.expiresAt,\n data.refreshAt\n );\n\n return ok(undefined);\n } catch (error) {\n return err(createError('CACHE_ERROR', 'Failed to write token to cache', error));\n }\n }\n\n delete(\n bindingValue: string,\n client: ClientName,\n context: PoTokenContext\n ): Result<void, BundlpError> {\n try {\n const id = `${bindingValue}:${client}:${context}`;\n const stmt = this.db.prepare('DELETE FROM tokens WHERE id = ?');\n stmt.run(id);\n return ok(undefined);\n } catch (error) {\n return err(createError('CACHE_ERROR', 'Failed to delete token', error));\n }\n }\n\n deleteExpired(): Result<number, BundlpError> {\n try {\n const stmt = this.db.prepare('DELETE FROM tokens WHERE expires_at <= ?');\n const result = stmt.run(Date.now());\n return ok(result.changes);\n } catch (error) {\n return err(createError('CACHE_ERROR', 'Failed to delete expired tokens', error));\n }\n }\n\n clear(): Result<void, BundlpError> {\n try {\n this.db.run('DELETE FROM tokens');\n return ok(undefined);\n } catch (error) {\n return err(createError('CACHE_ERROR', 'Failed to clear token cache', error));\n }\n }\n\n getStats(): Result<{ total: number; expired: number; valid: number }, BundlpError> {\n try {\n const now = Date.now();\n\n const totalStmt = this.db.prepare('SELECT COUNT(*) as count FROM tokens');\n const total = (totalStmt.get() as { count: number }).count;\n\n const validStmt = this.db.prepare('SELECT COUNT(*) as count FROM tokens WHERE expires_at > ?');\n const valid = (validStmt.get(now) as { count: number }).count;\n\n return ok({\n total,\n valid,\n expired: total - valid,\n });\n } catch (error) {\n return err(createError('CACHE_ERROR', 'Failed to get cache stats', error));\n }\n }\n\n close(): void {\n this.db.close();\n }\n\n private rowToTokenData(row: CachedToken): PoTokenData {\n return {\n token: row.token,\n integrityToken: row.integrity_token ?? undefined,\n bindingType: row.binding_type as 'session' | 'content',\n bindingValue: row.binding_value,\n client: row.client as ClientName,\n context: row.context as PoTokenContext,\n createdAt: row.created_at,\n expiresAt: row.expires_at,\n refreshAt: row.refresh_at,\n };\n }\n}\n","import { ok, err, isOk, type Result } from '../result';\nimport { createError, type BundlpError } from '../types/error.types';\nimport type { ClientName } from '../utils/constants';\nimport { PO_TOKEN_POLICIES, type PoTokenPolicy } from './policies';\nimport type { PoTokenData, ContentBinding, PoTokenContext } from './types';\nimport type { PoTokenProvider } from './providers/provider.interface';\nimport { LocalBotGuardProvider } from './providers/local.provider';\nimport { TokenCache } from './cache/token-cache';\nimport { generateColdStartToken } from './botguard/client';\n\nexport interface PoTokenManagerConfig {\n token?: string;\n cacheEnabled?: boolean;\n cachePath?: string;\n timeout?: number;\n providers?: PoTokenProvider[];\n}\n\nexport class PoTokenManager {\n private staticToken?: string;\n private policies: Record<ClientName, PoTokenPolicy>;\n private providers: PoTokenProvider[];\n private cache: TokenCache | null = null;\n\n constructor(config: PoTokenManagerConfig = {}) {\n this.staticToken = config.token;\n this.policies = PO_TOKEN_POLICIES;\n\n if (config.providers) {\n this.providers = [...config.providers].sort((a, b) => b.priority - a.priority);\n } else {\n this.providers = [new LocalBotGuardProvider({ timeout: config.timeout })];\n }\n\n if (config.cacheEnabled !== false && config.cachePath) {\n this.cache = new TokenCache(config.cachePath);\n }\n }\n\n async getToken(\n identifier: string,\n client: ClientName = 'WEB',\n binding?: ContentBinding\n ): Promise<Result<string, BundlpError>> {\n if (this.staticToken) {\n return ok(this.staticToken);\n }\n\n if (!this.isRequired(client)) {\n return ok('');\n }\n\n const context: PoTokenContext = binding ? 'GVS' : 'GVS';\n\n if (this.cache) {\n const cachedResult = this.cache.get(identifier, client, context);\n if (isOk(cachedResult) && cachedResult.value && cachedResult.value.expiresAt > Date.now()) {\n return ok(cachedResult.value.token);\n }\n }\n\n for (const provider of this.providers) {\n const available = await provider.isAvailable();\n if (!available) continue;\n\n const result = await provider.generate(identifier, binding);\n if (isOk(result)) {\n if (this.cache) {\n this.cache.set(result.value);\n }\n return ok(result.value.token);\n }\n }\n\n const coldToken = generateColdStartToken(identifier);\n return ok(coldToken);\n }\n\n async getTokenData(\n identifier: string,\n client: ClientName = 'WEB',\n binding?: ContentBinding\n ): Promise<Result<PoTokenData, BundlpError>> {\n if (this.staticToken) {\n return ok({\n token: this.staticToken,\n createdAt: Date.now(),\n expiresAt: Date.now() + 3600000,\n refreshAt: Date.now() + 3000000,\n bindingType: 'session',\n bindingValue: identifier,\n client,\n context: 'GVS',\n });\n }\n\n if (!this.isRequired(client)) {\n return err(createError('PO_TOKEN_EXPIRED', `PO Token not required for client ${client}`));\n }\n\n const context: PoTokenContext = binding ? 'GVS' : 'GVS';\n\n if (this.cache) {\n const cachedResult = this.cache.get(identifier, client, context);\n if (isOk(cachedResult) && cachedResult.value && cachedResult.value.expiresAt > Date.now()) {\n return ok(cachedResult.value);\n }\n }\n\n for (const provider of this.providers) {\n const available = await provider.isAvailable();\n if (!available) continue;\n\n const result = await provider.generate(identifier, binding);\n if (isOk(result)) {\n if (this.cache) {\n this.cache.set(result.value);\n }\n return result;\n }\n }\n\n return err(createError('ALL_PROVIDERS_FAILED', 'All PO Token providers failed'));\n }\n\n getColdStartToken(identifier: string): string {\n return generateColdStartToken(identifier);\n }\n\n isRequired(client: ClientName): boolean {\n const policy = this.policies[client];\n if (!policy) return false;\n\n if (typeof policy.GVS === 'string') {\n return policy.GVS === 'required';\n }\n\n return policy.GVS.HTTPS === 'required' || policy.GVS.DASH === 'required';\n }\n\n needsTokenForGvs(client: ClientName): boolean {\n const policy = this.policies[client];\n if (!policy) return false;\n\n if (typeof policy.GVS === 'string') {\n return policy.GVS !== 'not_required';\n }\n\n return (\n policy.GVS.HTTPS !== 'not_required' ||\n policy.GVS.DASH !== 'not_required' ||\n policy.GVS.HLS !== 'not_required'\n );\n }\n\n getPolicy(client: ClientName): PoTokenPolicy | undefined {\n return this.policies[client];\n }\n\n getVisitorData(): string | undefined {\n for (const provider of this.providers) {\n if (provider instanceof LocalBotGuardProvider) {\n return provider.getVisitorData();\n }\n }\n return undefined;\n }\n\n shutdown(): void {\n for (const provider of this.providers) {\n provider.shutdown();\n }\n\n if (this.cache) {\n this.cache.deleteExpired();\n }\n }\n\n getCacheStats(): { total: number; expired: number; valid: number } | null {\n if (!this.cache) return null;\n const result = this.cache.getStats();\n if (isOk(result)) {\n return result.value;\n }\n return null;\n }\n}\n","import logger from '@mks2508/better-logger';\n\n// Configure for CLI tool - cyberpunk theme for terminal\nlogger.preset('cyberpunk');\nlogger.showTimestamp();\nlogger.showLocation();\n\n// Register Error serializer for better error output\nlogger.addSerializer(Error, (err) => ({\n name: err.name,\n message: err.message,\n stack: err.stack?.split('\\n').slice(0, 5).join('\\n')\n}));\n\n// Core loggers\nexport const bundlpLogger = logger.scope('Bundlp');\n\n// Component loggers for specific modules\nexport const extractorLogger = logger.component('Extractor');\nexport const cipherLogger = logger.component('Cipher');\nexport const decoderLogger = logger.component('Decoder');\n\n// API loggers for external services\nexport const innertubeLogger = logger.api('InnerTube');\nexport const httpLogger = logger.api('HTTP');\n\n// Scoped loggers for internal modules\nexport const playerLogger = logger.scope('Bundlp:Player');\nexport const streamingLogger = logger.scope('Bundlp:Streaming');\nexport const poTokenLogger = logger.scope('Bundlp:PoToken');\nexport const cacheLogger = logger.scope('Bundlp:Cache');\n\n// Generic logging functions (convenience exports)\nexport const logInfo = (message: string, data?: unknown) => bundlpLogger.info(message, data);\nexport const logSuccess = (message: string, data?: unknown) => bundlpLogger.success(message, data);\nexport const logWarning = (message: string, data?: unknown) => bundlpLogger.warn(message, data);\nexport const logError = (message: string, error?: unknown) => bundlpLogger.error(message, error);\nexport const logDebug = (message: string, data?: unknown) => bundlpLogger.debug(message, data);\n\nexport default logger;\n","/**\n * bundlp - Bun-native YouTube video/music resolver\n *\n * @example\n * ```typescript\n * import { YouTubeExtractor, isOk } from 'bundlp';\n *\n * const extractor = new YouTubeExtractor();\n * const result = await extractor.extract('https://youtube.com/watch?v=dQw4w9WgXcQ');\n *\n * if (isOk(result)) {\n * console.log(result.value.title);\n * console.log(result.value.formats.video);\n * }\n * ```\n */\n\n// Result Pattern\nexport {\n type Result,\n type ResultOk,\n type ResultErr,\n ok,\n err,\n isOk,\n isErr,\n match,\n map,\n mapErr,\n andThen,\n unwrapOr,\n unwrap,\n tryCatch,\n tryCatchAsync,\n} from './result';\n\n// Types\nexport type {\n // Video\n VideoInfo,\n ChannelInfo,\n Thumbnail,\n FormatCollection,\n Format,\n AudioFormat,\n VideoFormat,\n HlsInfo,\n HlsVariant,\n DashInfo,\n Subtitle,\n Chapter,\n Storyboard,\n // Error\n ErrorCode,\n BundlpError,\n // InnerTube\n ClientName,\n ClientConfig,\n InnerTubeContext,\n PlayerResponse,\n StreamingData,\n // Player\n PlayerInfo,\n SignatureCipher,\n} from './types';\n\n// Core\nexport { YouTubeExtractor, type ExtractorConfig } from './core/extractor';\n\n// Headers\nexport { getDownloadHeaders, getMinimalDownloadHeaders } from './utils/headers';\n\n// PO Token\nexport { PoTokenManager, type PoTokenManagerConfig } from './po-token';\nexport { LocalBotGuardProvider } from './po-token';\n\n// Logger (no exports, internal only)\nexport { bundlpLogger, extractorLogger } from './utils/logger';\n\n/**\n * Appends po_token to a download URL\n */\nexport function appendPoToken(url: string, poToken: string): string {\n if (!url || !poToken) return url;\n const separator = url.includes('?') ? '&' : '?';\n return `${url}${separator}pot=${encodeURIComponent(poToken)}`;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mks2508/bundlp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Bun-native YouTube video/music resolver library",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"main": "dist/index.
|
|
8
|
-
"module": "dist/index.
|
|
9
|
-
"types": "dist/index.d.
|
|
7
|
+
"main": "dist/index.mjs",
|
|
8
|
+
"module": "dist/index.mjs",
|
|
9
|
+
"types": "dist/index.d.mts",
|
|
10
10
|
"exports": {
|
|
11
11
|
".": {
|
|
12
|
-
"import": "./dist/index.
|
|
13
|
-
"types": "./dist/index.d.
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"types": "./dist/index.d.mts"
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
"README.md"
|
|
19
19
|
],
|
|
20
20
|
"scripts": {
|
|
21
|
-
"build": "
|
|
21
|
+
"build": "tsdown",
|
|
22
|
+
"build:watch": "tsdown --watch",
|
|
23
|
+
"build:legacy": "bun build ./src/index.ts --outdir ./dist --target bun",
|
|
22
24
|
"build:types": "tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
23
25
|
"dev": "bun --watch src/index.ts",
|
|
24
26
|
"test": "bun test",
|
|
@@ -30,9 +32,16 @@
|
|
|
30
32
|
"lint": "bunx @biomejs/biome check src/",
|
|
31
33
|
"lint:fix": "bunx @biomejs/biome check --write src/",
|
|
32
34
|
"clean": "rm -rf dist",
|
|
33
|
-
"cli": "bun cli/index.ts"
|
|
35
|
+
"cli": "bun cli/index.ts",
|
|
36
|
+
"tmux:dev": "run-in-session bundlp 'bun run dev'",
|
|
37
|
+
"tmux:attach": "cxa bundlp",
|
|
38
|
+
"tmux:kill": "cxk bundlp",
|
|
39
|
+
"link": "bun link",
|
|
40
|
+
"unlink": "bun unlink",
|
|
41
|
+
"link:use": "bun link @mks2508/bundlp"
|
|
34
42
|
},
|
|
35
43
|
"dependencies": {
|
|
44
|
+
"@mks2508/better-logger": "3.0.0",
|
|
36
45
|
"@types/figlet": "^1.7.0",
|
|
37
46
|
"arktype": "^2.0.0",
|
|
38
47
|
"boxen": "^8.0.1",
|
|
@@ -51,6 +60,7 @@
|
|
|
51
60
|
"@types/jsdom": "^27.0.0",
|
|
52
61
|
"happy-dom": "^20.0.11",
|
|
53
62
|
"linkedom": "^0.18.12",
|
|
63
|
+
"tsdown": "^0.18.3",
|
|
54
64
|
"typescript": "^5.7.2"
|
|
55
65
|
},
|
|
56
66
|
"keywords": [
|
package/dist/core/extractor.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { type Result } from '../result';
|
|
2
|
-
import type { VideoInfo } from '../types/video.types';
|
|
3
|
-
import { type BundlpError } from '../types/error.types';
|
|
4
|
-
import type { ClientName } from '../utils/constants';
|
|
5
|
-
export interface ExtractorConfig {
|
|
6
|
-
poToken?: string;
|
|
7
|
-
cacheDir?: string;
|
|
8
|
-
preferredClient?: ClientName;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Main YouTube video extractor class.
|
|
12
|
-
* Handles video information extraction using InnerTube API.
|
|
13
|
-
*/
|
|
14
|
-
export declare class YouTubeExtractor {
|
|
15
|
-
private client;
|
|
16
|
-
private player;
|
|
17
|
-
private config;
|
|
18
|
-
constructor(config?: ExtractorConfig);
|
|
19
|
-
/**
|
|
20
|
-
* Extracts video information from a YouTube URL or video ID.
|
|
21
|
-
* @param url - YouTube URL or video ID
|
|
22
|
-
* @returns Result containing VideoInfo or BundlpError
|
|
23
|
-
*/
|
|
24
|
-
extract(url: string): Promise<Result<VideoInfo, BundlpError>>;
|
|
25
|
-
private parseVideoId;
|
|
26
|
-
private realExtract;
|
|
27
|
-
private processFormats;
|
|
28
|
-
private assembleVideoInfo;
|
|
29
|
-
}
|
|
30
|
-
//# sourceMappingURL=extractor.d.ts.map
|