@mks2508/bundlp 0.1.6 → 0.1.8

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.mjs CHANGED
@@ -1,5 +1,6 @@
1
- import { type } from "arktype";
1
+ import { detectFormat, filterByDomain, filterByDomain as filterByDomain$1, filterExpired, parseCookies, parseCookies as parseCookies$1, parseJSON, parseNetscape, toCookieHeader, toJSONFormat, toNetscapeFormat } from "@mks2508/binary-cookies-parser";
2
2
  import logger from "@mks2508/better-logger";
3
+ import { type } from "arktype";
3
4
  import { parse } from "meriyah";
4
5
  import { Database } from "bun:sqlite";
5
6
  import { mkdirSync } from "node:fs";
@@ -205,7 +206,8 @@ function isRecoverable(code) {
205
206
 
206
207
  //#endregion
207
208
  //#region src/http/client.ts
208
- function parseCookies(setCookieHeaders) {
209
+ const log$7 = logger.scope("HttpClient");
210
+ function parseCookies$2(setCookieHeaders) {
209
211
  return setCookieHeaders.map((header) => {
210
212
  const [nameValue, ...attributes] = header.split(";").map((p) => p.trim());
211
213
  const [name, value] = nameValue.split("=");
@@ -267,7 +269,7 @@ var HttpClient = class {
267
269
  signal: timeout ? AbortSignal.timeout(timeout) : void 0
268
270
  });
269
271
  const setCookies = response.headers.getSetCookie?.() || [];
270
- for (const cookie of parseCookies(setCookies)) this.cookies.set(cookie.name, cookie);
272
+ for (const cookie of parseCookies$2(setCookies)) this.cookies.set(cookie.name, cookie);
271
273
  if (response.status >= 300 && response.status < 400) {
272
274
  const location = response.headers.get("location");
273
275
  if (!location) return ok(response);
@@ -289,6 +291,55 @@ var HttpClient = class {
289
291
  return new Map(this.cookies);
290
292
  }
291
293
  /**
294
+ * Set a single cookie in the jar.
295
+ * @param cookie - Cookie to add
296
+ */
297
+ setCookie(cookie) {
298
+ const key = `${cookie.name}@${cookie.domain || "default"}`;
299
+ this.cookies.set(key, cookie);
300
+ }
301
+ /**
302
+ * Set multiple cookies in the jar.
303
+ * @param cookies - Array of cookies to add
304
+ */
305
+ setCookies(cookies) {
306
+ for (const cookie of cookies) this.setCookie(cookie);
307
+ }
308
+ /**
309
+ * Load cookies from a string (auto-detects Netscape, JSON, or binary format).
310
+ * Filters cookies by the specified domain.
311
+ * @param content - Cookie file content as string
312
+ * @param domain - Domain to filter cookies for (default: '.youtube.com')
313
+ * @returns Result with number of cookies loaded or error
314
+ */
315
+ loadCookiesFromString(content, domain = ".youtube.com") {
316
+ try {
317
+ const { format, cookies } = parseCookies$1(content);
318
+ const filteredCookies = filterByDomain$1(cookies, domain);
319
+ log$7.info(`Parsed ${cookies.length} cookies (format: ${format}), ${filteredCookies.length} match domain ${domain}`);
320
+ for (const c of filteredCookies) this.setCookie({
321
+ name: c.name,
322
+ value: c.value,
323
+ domain: c.domain,
324
+ path: c.path,
325
+ secure: c.secure,
326
+ httpOnly: c.httpOnly,
327
+ expires: c.expires
328
+ });
329
+ log$7.success(`Loaded ${filteredCookies.length} cookies for ${domain}`);
330
+ return ok(filteredCookies.length);
331
+ } catch (error) {
332
+ log$7.error("Failed to parse cookies:", error);
333
+ return err(createError("COOKIE_PARSE_ERROR", `Failed to parse cookies: ${error.message}`, error));
334
+ }
335
+ }
336
+ /**
337
+ * Get the number of cookies currently in the jar.
338
+ */
339
+ getCookieCount() {
340
+ return this.cookies.size;
341
+ }
342
+ /**
292
343
  * Performs a GET request.
293
344
  * @param url - The URL to fetch
294
345
  * @param options - Optional fetch options
@@ -457,7 +508,7 @@ function isDrmOnly(formats) {
457
508
 
458
509
  //#endregion
459
510
  //#region src/innertube/client.ts
460
- const log = logger.scope("InnerTube");
511
+ const log$6 = logger.scope("InnerTube");
461
512
  /**
462
513
  * Client for interacting with YouTube's InnerTube API.
463
514
  */
@@ -521,7 +572,7 @@ var InnerTubeClient = class {
521
572
  */
522
573
  async fetchPlayer(videoId, options = {}) {
523
574
  const config = INNERTUBE_CLIENTS[this.currentClient];
524
- log.debug(`Fetching player for ${videoId} with client ${this.currentClient}`);
575
+ log$6.debug(`Fetching player for ${videoId} with client ${this.currentClient}`);
525
576
  const payload = {
526
577
  context: this.buildContext(),
527
578
  videoId,
@@ -532,45 +583,45 @@ var InnerTubeClient = class {
532
583
  if (options.poToken) {
533
584
  if (!payload.serviceIntegrityDimensions) payload.serviceIntegrityDimensions = {};
534
585
  payload.serviceIntegrityDimensions.poToken = options.poToken;
535
- log.debug(`Using po_token (length: ${options.poToken.length})`);
586
+ log$6.debug(`Using po_token (length: ${options.poToken.length})`);
536
587
  }
537
588
  const url = `${INNER_TUBE_API_URL}/player?key=${config.API_KEY || ""}`;
538
589
  const responseResult = await httpClient.post(url, payload, { headers: this.getHeaders() });
539
590
  if (isErr(responseResult)) {
540
- log.error(`HTTP request failed for client ${this.currentClient}:`, responseResult.error.message);
591
+ log$6.error(`HTTP request failed for client ${this.currentClient}:`, responseResult.error.message);
541
592
  return responseResult;
542
593
  }
543
594
  const response = responseResult.value;
544
595
  if (!response.ok) {
545
- log.error(`Player request failed for ${this.currentClient}: HTTP ${response.status}`);
596
+ log$6.error(`Player request failed for ${this.currentClient}: HTTP ${response.status}`);
546
597
  return err(createError("INNERTUBE_ERROR", `Player request failed with status ${response.status}`));
547
598
  }
548
599
  try {
549
600
  const validated = PlayerResponseSchema(await response.json());
550
601
  if (validated instanceof type.errors) {
551
- log.error(`Parse error for ${this.currentClient}:`, validated.summary);
602
+ log$6.error(`Parse error for ${this.currentClient}:`, validated.summary);
552
603
  return err(createError("PARSE_ERROR", `Invalid player response: ${validated.summary}`));
553
604
  }
554
605
  const status = validated.playabilityStatus.status;
555
606
  const reason = validated.playabilityStatus.reason || "No reason";
556
- log.debug(`Client ${this.currentClient} response: status=${status}, reason=${reason}`);
607
+ log$6.debug(`Client ${this.currentClient} response: status=${status}, reason=${reason}`);
557
608
  if (status === "ERROR") {
558
- log.warn(`Client ${this.currentClient} returned ERROR: ${reason}`);
609
+ log$6.warn(`Client ${this.currentClient} returned ERROR: ${reason}`);
559
610
  return err(createError("VIDEO_UNAVAILABLE", reason));
560
611
  }
561
612
  if (status === "LOGIN_REQUIRED") {
562
- log.warn(`Client ${this.currentClient} requires login: ${reason}`);
613
+ log$6.warn(`Client ${this.currentClient} requires login: ${reason}`);
563
614
  return err(createError("VIDEO_UNAVAILABLE", `Login required: ${reason}`));
564
615
  }
565
616
  if (status === "UNPLAYABLE") {
566
- log.warn(`Client ${this.currentClient} unplayable: ${reason}`);
617
+ log$6.warn(`Client ${this.currentClient} unplayable: ${reason}`);
567
618
  return err(createError("VIDEO_UNAVAILABLE", `Unplayable: ${reason}`));
568
619
  }
569
620
  const formatsCount = (validated.streamingData?.formats?.length || 0) + (validated.streamingData?.adaptiveFormats?.length || 0);
570
- log.info(`Client ${this.currentClient} success: ${formatsCount} formats`);
621
+ log$6.info(`Client ${this.currentClient} success: ${formatsCount} formats`);
571
622
  return ok(validated);
572
623
  } catch (error) {
573
- log.error(`Parse exception for ${this.currentClient}:`, error);
624
+ log$6.error(`Parse exception for ${this.currentClient}:`, error);
574
625
  return err(createError("PARSE_ERROR", "Failed to parse InnerTube response", error));
575
626
  }
576
627
  }
@@ -583,35 +634,35 @@ var InnerTubeClient = class {
583
634
  */
584
635
  async fetchPlayerWithFallback(videoId, options = {}) {
585
636
  const errors = [];
586
- log.info(`Starting fallback extraction for ${videoId}`);
587
- log.info(`Fallback order: ${this.FALLBACK_ORDER.join(" → ")}`);
637
+ log$6.info(`Starting fallback extraction for ${videoId}`);
638
+ log$6.info(`Fallback order: ${this.FALLBACK_ORDER.join(" → ")}`);
588
639
  for (const clientName of this.FALLBACK_ORDER) {
589
- log.info(`Trying client: ${clientName}`);
640
+ log$6.info(`Trying client: ${clientName}`);
590
641
  if (isErr(this.setClient(clientName))) {
591
- log.warn(`Failed to set client ${clientName}`);
642
+ log$6.warn(`Failed to set client ${clientName}`);
592
643
  continue;
593
644
  }
594
645
  const result = await this.fetchPlayer(videoId, options);
595
646
  if (isOk(result)) {
596
647
  const validationResult = this.isValidResponse(result.value);
597
648
  if (validationResult.valid) {
598
- log.success(`Client ${clientName} returned valid response`);
649
+ log$6.success(`Client ${clientName} returned valid response`);
599
650
  return result;
600
651
  }
601
- log.warn(`Client ${clientName} response invalid: ${validationResult.reason}`);
652
+ log$6.warn(`Client ${clientName} response invalid: ${validationResult.reason}`);
602
653
  errors.push({
603
654
  client: clientName,
604
655
  error: createError("VIDEO_UNAVAILABLE", validationResult.reason)
605
656
  });
606
657
  } else {
607
- log.warn(`Client ${clientName} failed: ${result.error.message}`);
658
+ log$6.warn(`Client ${clientName} failed: ${result.error.message}`);
608
659
  errors.push({
609
660
  client: clientName,
610
661
  error: result.error
611
662
  });
612
663
  }
613
664
  }
614
- log.error(`All clients failed for ${videoId}. Errors:`, errors.map((e) => ({
665
+ log$6.error(`All clients failed for ${videoId}. Errors:`, errors.map((e) => ({
615
666
  client: e.client,
616
667
  error: e.error.message
617
668
  })));
@@ -2210,6 +2261,7 @@ var StreamingDataProcessor = class {
2210
2261
 
2211
2262
  //#endregion
2212
2263
  //#region src/core/extractor.ts
2264
+ const log$5 = logger.scope("Extractor");
2213
2265
  const VIDEO_ID_PATTERNS = [
2214
2266
  /(?:youtube\.com\/watch\?v=|youtu\.be\/)([a-zA-Z0-9_-]{11})/,
2215
2267
  /youtube\.com\/embed\/([a-zA-Z0-9_-]{11})/,
@@ -2232,6 +2284,11 @@ var YouTubeExtractor = class {
2232
2284
  this.config = config;
2233
2285
  this.client = new InnerTubeClient({ initialClient: config.preferredClient });
2234
2286
  this.player = new Player(config.cacheDir);
2287
+ if (config.cookiesString) {
2288
+ const result = httpClient.loadCookiesFromString(config.cookiesString);
2289
+ if (isOk(result)) log$5.success(`Loaded ${result.value} YouTube cookies`);
2290
+ else log$5.warn("Failed to load cookies:", result.error.message);
2291
+ }
2235
2292
  }
2236
2293
  /**
2237
2294
  * Extracts video information from a YouTube URL or video ID.
@@ -2385,6 +2442,7 @@ const PO_TOKEN_POLICIES = {
2385
2442
 
2386
2443
  //#endregion
2387
2444
  //#region src/po-token/botguard/challenge.ts
2445
+ const log$4 = logger.scope("ChallengeFetcher");
2388
2446
  const WAA_CREATE_ENDPOINT = "https://jnn-pa.googleapis.com/$rpc/google.internal.waa.v1.Waa/Create";
2389
2447
  const INNERTUBE_ATT_ENDPOINT = "https://www.youtube.com/youtubei/v1/att/get";
2390
2448
  const GOOG_API_KEY$1 = "AIzaSyDyT5W0Jh49F30Pqqtyfdf7pDLFKLJoAnw";
@@ -2395,6 +2453,7 @@ var ChallengeFetcher = class {
2395
2453
  this.timeout = options.timeout ?? 15e3;
2396
2454
  }
2397
2455
  async fetchAttestation() {
2456
+ log$4.info(`Fetching attestation from ${INNERTUBE_ATT_ENDPOINT}`);
2398
2457
  const payload = { context: { client: {
2399
2458
  clientName: "WEB",
2400
2459
  clientVersion: "2.20250222.10.00",
@@ -2402,6 +2461,7 @@ var ChallengeFetcher = class {
2402
2461
  gl: "US"
2403
2462
  } } };
2404
2463
  try {
2464
+ log$4.debug("Sending POST request...");
2405
2465
  const response = await fetch(INNERTUBE_ATT_ENDPOINT, {
2406
2466
  method: "POST",
2407
2467
  headers: {
@@ -2413,11 +2473,22 @@ var ChallengeFetcher = class {
2413
2473
  body: JSON.stringify(payload),
2414
2474
  signal: AbortSignal.timeout(this.timeout)
2415
2475
  });
2416
- if (!response.ok) return err(createError("BOTGUARD_INIT_FAILED", `Attestation request failed with status ${response.status}`));
2476
+ log$4.debug(`Response status: ${response.status}`);
2477
+ if (!response.ok) {
2478
+ log$4.error(`Attestation request failed with status ${response.status}`);
2479
+ return err(createError("BOTGUARD_INIT_FAILED", `Attestation request failed with status ${response.status}`));
2480
+ }
2417
2481
  const data = await response.json();
2418
- return this.parseAttestationResponse(data);
2482
+ log$4.debug("Parsing attestation response...");
2483
+ const result = this.parseAttestationResponse(data);
2484
+ if (result.ok) log$4.success(`Attestation fetched successfully (visitorData length: ${result.value.visitorData.length})`);
2485
+ return result;
2419
2486
  } catch (error) {
2420
- if (error instanceof Error && error.name === "TimeoutError") return err(createError("BOTGUARD_INIT_FAILED", "Attestation fetch timeout"));
2487
+ if (error instanceof Error && error.name === "TimeoutError") {
2488
+ log$4.error(`Attestation fetch timeout after ${this.timeout}ms`);
2489
+ return err(createError("BOTGUARD_INIT_FAILED", "Attestation fetch timeout"));
2490
+ }
2491
+ log$4.error("Failed to fetch attestation", error);
2421
2492
  return err(createError("BOTGUARD_INIT_FAILED", "Failed to fetch attestation", error));
2422
2493
  }
2423
2494
  }
@@ -2437,7 +2508,9 @@ var ChallengeFetcher = class {
2437
2508
  });
2438
2509
  }
2439
2510
  async fetchWaaChallenge() {
2511
+ log$4.info(`Fetching WAA challenge from ${WAA_CREATE_ENDPOINT}`);
2440
2512
  try {
2513
+ log$4.debug("Sending POST request with API key...");
2441
2514
  const response = await fetch(WAA_CREATE_ENDPOINT, {
2442
2515
  method: "POST",
2443
2516
  headers: {
@@ -2447,12 +2520,26 @@ var ChallengeFetcher = class {
2447
2520
  body: JSON.stringify([REQUEST_KEY$1]),
2448
2521
  signal: AbortSignal.timeout(this.timeout)
2449
2522
  });
2450
- if (!response.ok) return err(createError("BOTGUARD_INIT_FAILED", `WAA Create request failed with status ${response.status}`));
2523
+ log$4.debug(`Response status: ${response.status}`);
2524
+ if (!response.ok) {
2525
+ log$4.error(`WAA Create request failed with status ${response.status}`);
2526
+ return err(createError("BOTGUARD_INIT_FAILED", `WAA Create request failed with status ${response.status}`));
2527
+ }
2451
2528
  const encoded = (await response.json())[1];
2452
- if (!encoded || typeof encoded !== "string") return err(createError("PARSE_ERROR", "Invalid WAA response format"));
2453
- return this.descrambleWaaResponse(encoded);
2529
+ if (!encoded || typeof encoded !== "string") {
2530
+ log$4.error("Invalid WAA response format - missing encoded data");
2531
+ return err(createError("PARSE_ERROR", "Invalid WAA response format"));
2532
+ }
2533
+ log$4.debug(`Descrambling WAA response (encoded length: ${encoded.length})...`);
2534
+ const result = this.descrambleWaaResponse(encoded);
2535
+ if (result.ok) log$4.success(`WAA challenge descrambled (program: ${result.value.program.length} bytes, globalName: ${result.value.globalName})`);
2536
+ return result;
2454
2537
  } catch (error) {
2455
- if (error instanceof Error && error.name === "TimeoutError") return err(createError("BOTGUARD_INIT_FAILED", "WAA Create fetch timeout"));
2538
+ if (error instanceof Error && error.name === "TimeoutError") {
2539
+ log$4.error(`WAA Create fetch timeout after ${this.timeout}ms`);
2540
+ return err(createError("BOTGUARD_INIT_FAILED", "WAA Create fetch timeout"));
2541
+ }
2542
+ log$4.error("Failed to fetch WAA challenge", error);
2456
2543
  return err(createError("BOTGUARD_INIT_FAILED", "Failed to fetch WAA challenge", error));
2457
2544
  }
2458
2545
  }
@@ -2493,6 +2580,7 @@ var ChallengeFetcher = class {
2493
2580
 
2494
2581
  //#endregion
2495
2582
  //#region src/po-token/botguard/client.ts
2583
+ const log$3 = logger.scope("BotGuardClient");
2496
2584
  var DeferredPromise = class {
2497
2585
  promise;
2498
2586
  resolve;
@@ -2520,13 +2608,21 @@ var BotGuardClient = class BotGuardClient {
2520
2608
  this.snapshotTimeout = 5e3;
2521
2609
  }
2522
2610
  static async create(challenge, options = {}) {
2611
+ log$3.info("Creating BotGuard client...");
2612
+ log$3.debug(`Options: timeout=${options.timeout || "default"}`);
2523
2613
  const client = new BotGuardClient(challenge, options);
2524
2614
  const loadResult = await client.load(challenge);
2525
- if (!isOk(loadResult)) return loadResult;
2615
+ if (!isOk(loadResult)) {
2616
+ log$3.error("Client creation failed", loadResult.error);
2617
+ return loadResult;
2618
+ }
2619
+ log$3.success("BotGuard client created successfully");
2526
2620
  return ok(client);
2527
2621
  }
2528
2622
  async load(challenge) {
2623
+ log$3.debug("Loading BotGuard VM environment...");
2529
2624
  try {
2625
+ log$3.debug("Creating JSDOM instance with YouTube context");
2530
2626
  this.dom = new JSDOM("<!DOCTYPE html><html><head></head><body></body></html>", {
2531
2627
  url: "https://www.youtube.com/",
2532
2628
  runScripts: "dangerously",
@@ -2543,15 +2639,25 @@ var BotGuardClient = class BotGuardClient {
2543
2639
  window.Request = globalThis.Request;
2544
2640
  window.Response = globalThis.Response;
2545
2641
  window.Headers = globalThis.Headers;
2642
+ log$3.debug(`Evaluating interpreter script (${challenge.interpreterScript.length} bytes)...`);
2546
2643
  const evalFn = window.eval;
2547
2644
  evalFn(challenge.interpreterScript);
2548
2645
  this.vm = window[this.globalName];
2549
- if (!this.vm) return err(createError("BOTGUARD_INIT_FAILED", `VM not found at globalName: ${this.globalName}`));
2550
- if (typeof this.vm.a !== "function") return err(createError("BOTGUARD_INIT_FAILED", "VM init function (a) not found"));
2646
+ if (!this.vm) {
2647
+ log$3.error(`VM not found at globalName: ${this.globalName}`);
2648
+ return err(createError("BOTGUARD_INIT_FAILED", `VM not found at globalName: ${this.globalName}`));
2649
+ }
2650
+ if (typeof this.vm.a !== "function") {
2651
+ log$3.error("VM init function (a) not found");
2652
+ return err(createError("BOTGUARD_INIT_FAILED", "VM init function (a) not found"));
2653
+ }
2654
+ log$3.debug("Loading BotGuard program...");
2551
2655
  const loadResult = await this.loadProgram();
2552
2656
  if (!isOk(loadResult)) return loadResult;
2657
+ log$3.success("BotGuard VM loaded successfully");
2553
2658
  return ok(void 0);
2554
2659
  } catch (error) {
2660
+ log$3.error("Failed to load BotGuard", error);
2555
2661
  return err(createError("BOTGUARD_INIT_FAILED", `Failed to load BotGuard: ${error.message}`, error));
2556
2662
  }
2557
2663
  }
@@ -2607,6 +2713,7 @@ var BotGuardClient = class BotGuardClient {
2607
2713
  }
2608
2714
  }
2609
2715
  async snapshotWithSignalOutput(binding) {
2716
+ log$3.info("Generating snapshot with signal output...");
2610
2717
  const webPoSignalOutput = [];
2611
2718
  const snapshotArgs = [
2612
2719
  binding,
@@ -2616,10 +2723,17 @@ var BotGuardClient = class BotGuardClient {
2616
2723
  ];
2617
2724
  try {
2618
2725
  let snapshot;
2619
- if (this.syncSnapshotFunction) snapshot = await this.syncSnapshotFunction(snapshotArgs);
2620
- else {
2726
+ if (this.syncSnapshotFunction) {
2727
+ log$3.debug("Using sync snapshot function");
2728
+ snapshot = await this.syncSnapshotFunction(snapshotArgs);
2729
+ } else {
2730
+ log$3.debug("Using async snapshot function, waiting for VM functions...");
2621
2731
  const vmFunctions = await Promise.race([this.deferredVmFunctions.promise, new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error("Timeout waiting for VM functions")), this.snapshotTimeout))]);
2622
- if (!vmFunctions.asyncSnapshotFunction) return err(createError("BOTGUARD_SNAPSHOT_FAILED", "No snapshot function available"));
2732
+ if (!vmFunctions.asyncSnapshotFunction) {
2733
+ log$3.error("No snapshot function available in VM");
2734
+ return err(createError("BOTGUARD_SNAPSHOT_FAILED", "No snapshot function available"));
2735
+ }
2736
+ log$3.debug("Executing async snapshot...");
2623
2737
  snapshot = await new Promise((resolve, reject) => {
2624
2738
  const timeout = setTimeout(() => reject(/* @__PURE__ */ new Error("Snapshot timeout")), this.snapshotTimeout);
2625
2739
  vmFunctions.asyncSnapshotFunction((response) => {
@@ -2628,11 +2742,13 @@ var BotGuardClient = class BotGuardClient {
2628
2742
  }, snapshotArgs);
2629
2743
  });
2630
2744
  }
2745
+ log$3.success(`Snapshot generated (length: ${snapshot.length}, signals: ${webPoSignalOutput.length})`);
2631
2746
  return ok({
2632
2747
  snapshot,
2633
2748
  webPoSignalOutput
2634
2749
  });
2635
2750
  } catch (error) {
2751
+ log$3.error("Snapshot generation failed", error);
2636
2752
  return err(createError("BOTGUARD_SNAPSHOT_FAILED", `Snapshot failed: ${error.message}`, error));
2637
2753
  }
2638
2754
  }
@@ -2679,6 +2795,7 @@ function u8ToBase64Url$1(u8) {
2679
2795
 
2680
2796
  //#endregion
2681
2797
  //#region src/po-token/minter/web-minter.ts
2798
+ const log$2 = logger.scope("WebPoMinter");
2682
2799
  const WAA_GENERATE_IT_ENDPOINT = "https://jnn-pa.googleapis.com/$rpc/google.internal.waa.v1.Waa/GenerateIT";
2683
2800
  const GOOG_API_KEY = "AIzaSyDyT5W0Jh49F30Pqqtyfdf7pDLFKLJoAnw";
2684
2801
  const REQUEST_KEY = "O43z0dpjhgX20SCx4KAo";
@@ -2688,38 +2805,73 @@ var WebPoMinter = class WebPoMinter {
2688
2805
  this.mintCallback = mintCallback;
2689
2806
  }
2690
2807
  static async create(integrityTokenData, webPoSignalOutput) {
2808
+ log$2.info("Creating WebPoMinter...");
2691
2809
  const getMinter = webPoSignalOutput[0];
2692
- if (!getMinter || typeof getMinter !== "function") return err(createError("INTEGRITY_TOKEN_FAILED", "Minter function not found in webPoSignalOutput"));
2693
- if (!integrityTokenData.integrityToken) return err(createError("INTEGRITY_TOKEN_FAILED", "No integrity token provided"));
2810
+ if (!getMinter || typeof getMinter !== "function") {
2811
+ log$2.error("Minter function not found in webPoSignalOutput");
2812
+ return err(createError("INTEGRITY_TOKEN_FAILED", "Minter function not found in webPoSignalOutput"));
2813
+ }
2814
+ if (!integrityTokenData.integrityToken) {
2815
+ log$2.error("No integrity token provided");
2816
+ return err(createError("INTEGRITY_TOKEN_FAILED", "No integrity token provided"));
2817
+ }
2694
2818
  try {
2695
- const mintCallback = await getMinter(base64ToU8(integrityTokenData.integrityToken));
2696
- if (typeof mintCallback !== "function") return err(createError("INTEGRITY_TOKEN_FAILED", "Invalid mint callback returned"));
2819
+ log$2.debug(`Decoding integrity token (length: ${integrityTokenData.integrityToken.length})...`);
2820
+ const integrityTokenBytes = base64ToU8(integrityTokenData.integrityToken);
2821
+ log$2.debug("Calling getMinter with integrity token bytes...");
2822
+ const mintCallback = await getMinter(integrityTokenBytes);
2823
+ if (typeof mintCallback !== "function") {
2824
+ log$2.error("Invalid mint callback returned (not a function)");
2825
+ return err(createError("INTEGRITY_TOKEN_FAILED", "Invalid mint callback returned"));
2826
+ }
2827
+ log$2.success("WebPoMinter created successfully");
2697
2828
  return ok(new WebPoMinter(mintCallback));
2698
2829
  } catch (error) {
2830
+ log$2.error("Failed to create minter", error);
2699
2831
  return err(createError("INTEGRITY_TOKEN_FAILED", `Failed to create minter: ${error.message}`, error));
2700
2832
  }
2701
2833
  }
2702
2834
  async mint(identifier) {
2835
+ log$2.debug(`Minting for identifier: ${identifier.substring(0, 30)}...`);
2703
2836
  try {
2704
2837
  const identifierBytes = new TextEncoder().encode(identifier);
2705
2838
  const result = await this.mintCallback(identifierBytes);
2706
- if (!result) return err(createError("INTEGRITY_TOKEN_FAILED", "Mint returned undefined"));
2707
- if (result instanceof Uint8Array) return ok(result);
2708
- if (ArrayBuffer.isView(result)) return ok(new Uint8Array(result.buffer));
2709
- if (Array.isArray(result)) return ok(new Uint8Array(result));
2839
+ if (!result) {
2840
+ log$2.error("Mint returned undefined");
2841
+ return err(createError("INTEGRITY_TOKEN_FAILED", "Mint returned undefined"));
2842
+ }
2843
+ if (result instanceof Uint8Array) {
2844
+ log$2.debug(`Mint successful (Uint8Array, ${result.length} bytes)`);
2845
+ return ok(result);
2846
+ }
2847
+ if (ArrayBuffer.isView(result)) {
2848
+ log$2.debug(`Mint successful (ArrayBufferView, ${result.buffer.byteLength} bytes)`);
2849
+ return ok(new Uint8Array(result.buffer));
2850
+ }
2851
+ if (Array.isArray(result)) {
2852
+ log$2.debug(`Mint successful (Array, ${result.length} bytes)`);
2853
+ return ok(new Uint8Array(result));
2854
+ }
2855
+ log$2.error(`Mint returned invalid type: ${typeof result}`);
2710
2856
  return err(createError("INTEGRITY_TOKEN_FAILED", `Mint returned invalid type: ${typeof result}`));
2711
2857
  } catch (error) {
2858
+ log$2.error("Mint failed", error);
2712
2859
  return err(createError("INTEGRITY_TOKEN_FAILED", `Mint failed: ${error.message}`, error));
2713
2860
  }
2714
2861
  }
2715
2862
  async mintAsWebsafeString(identifier) {
2863
+ log$2.info(`Minting as websafe string for: ${identifier.substring(0, 30)}...`);
2716
2864
  const mintResult = await this.mint(identifier);
2717
2865
  if (!isOk(mintResult)) return mintResult;
2718
- return ok(u8ToBase64Url(mintResult.value));
2866
+ const token = u8ToBase64Url(mintResult.value);
2867
+ log$2.success(`Websafe token generated (length: ${token.length})`);
2868
+ return ok(token);
2719
2869
  }
2720
2870
  };
2721
2871
  async function fetchIntegrityToken(botguardResponse, options = {}) {
2722
2872
  const timeout = options.timeout ?? 1e4;
2873
+ log$2.info("Fetching integrity token from GenerateIT...");
2874
+ log$2.debug(`BotGuard response length: ${botguardResponse.length}, timeout: ${timeout}ms`);
2723
2875
  try {
2724
2876
  const response = await fetch(WAA_GENERATE_IT_ENDPOINT, {
2725
2877
  method: "POST",
@@ -2730,13 +2882,21 @@ async function fetchIntegrityToken(botguardResponse, options = {}) {
2730
2882
  body: JSON.stringify([REQUEST_KEY, botguardResponse]),
2731
2883
  signal: AbortSignal.timeout(timeout)
2732
2884
  });
2733
- if (!response.ok) return err(createError("INTEGRITY_TOKEN_FAILED", `GenerateIT request failed with status ${response.status}`));
2885
+ log$2.debug(`GenerateIT response status: ${response.status}`);
2886
+ if (!response.ok) {
2887
+ log$2.error(`GenerateIT request failed with status ${response.status}`);
2888
+ return err(createError("INTEGRITY_TOKEN_FAILED", `GenerateIT request failed with status ${response.status}`));
2889
+ }
2734
2890
  const json = await response.json();
2735
2891
  const integrityToken = json[0];
2736
2892
  const estimatedTtlSecs = json[1];
2737
2893
  const mintRefreshThreshold = json[2];
2738
2894
  const websafeFallbackToken = json[3];
2739
- if (!integrityToken) return err(createError("INTEGRITY_TOKEN_FAILED", "No integrity token in response"));
2895
+ if (!integrityToken) {
2896
+ log$2.error("No integrity token in GenerateIT response");
2897
+ return err(createError("INTEGRITY_TOKEN_FAILED", "No integrity token in response"));
2898
+ }
2899
+ log$2.success(`Integrity token received (length: ${integrityToken.length}, TTL: ${estimatedTtlSecs}s, threshold: ${mintRefreshThreshold})`);
2740
2900
  return ok({
2741
2901
  integrityToken,
2742
2902
  estimatedTtlSecs: estimatedTtlSecs ?? 3600,
@@ -2744,7 +2904,11 @@ async function fetchIntegrityToken(botguardResponse, options = {}) {
2744
2904
  websafeFallbackToken
2745
2905
  });
2746
2906
  } catch (error) {
2747
- if (error instanceof Error && error.name === "TimeoutError") return err(createError("INTEGRITY_TOKEN_FAILED", "GenerateIT request timeout"));
2907
+ if (error instanceof Error && error.name === "TimeoutError") {
2908
+ log$2.error(`GenerateIT request timeout after ${timeout}ms`);
2909
+ return err(createError("INTEGRITY_TOKEN_FAILED", "GenerateIT request timeout"));
2910
+ }
2911
+ log$2.error("Failed to fetch integrity token", error);
2748
2912
  return err(createError("INTEGRITY_TOKEN_FAILED", "Failed to fetch integrity token", error));
2749
2913
  }
2750
2914
  }
@@ -2761,6 +2925,7 @@ function u8ToBase64Url(u8) {
2761
2925
 
2762
2926
  //#endregion
2763
2927
  //#region src/po-token/providers/local.provider.ts
2928
+ const log$1 = logger.scope("LocalBotGuard");
2764
2929
  const REFRESH_MARGIN_MS = 600 * 1e3;
2765
2930
  var LocalBotGuardProvider = class {
2766
2931
  name = "local-botguard";
@@ -2781,19 +2946,33 @@ var LocalBotGuardProvider = class {
2781
2946
  async isAvailable() {
2782
2947
  try {
2783
2948
  await import("jsdom");
2949
+ log$1.debug("jsdom available - provider is ready");
2784
2950
  return true;
2785
- } catch {
2951
+ } catch (e) {
2952
+ log$1.warn("jsdom not available - provider disabled", e);
2786
2953
  return false;
2787
2954
  }
2788
2955
  }
2789
2956
  async generate(identifier, _binding) {
2957
+ log$1.info(`generate() called for identifier: ${identifier.substring(0, 30)}...`);
2790
2958
  const initResult = await this.ensureInitialized();
2791
- if (!isOk(initResult)) return initResult;
2792
- if (!this.minter || !this.integrityData) return err(createError("BOTGUARD_INIT_FAILED", "Minter not initialized"));
2959
+ if (!isOk(initResult)) {
2960
+ log$1.error("Initialization failed", initResult.error);
2961
+ return initResult;
2962
+ }
2963
+ if (!this.minter || !this.integrityData) {
2964
+ log$1.error("Minter or integrityData is null after initialization");
2965
+ return err(createError("BOTGUARD_INIT_FAILED", "Minter not initialized"));
2966
+ }
2967
+ log$1.info("Minting po_token...");
2793
2968
  const tokenResult = await this.minter.mintAsWebsafeString(identifier);
2794
- if (!isOk(tokenResult)) return tokenResult;
2969
+ if (!isOk(tokenResult)) {
2970
+ log$1.error("Minting failed", tokenResult.error);
2971
+ return tokenResult;
2972
+ }
2795
2973
  const now = Date.now();
2796
2974
  const ttlMs = (this.integrityData.estimatedTtlSecs ?? 43200) * 1e3;
2975
+ log$1.success(`Token minted successfully (length: ${tokenResult.value.length}, TTL: ${Math.round(ttlMs / 1e3)}s)`);
2797
2976
  return ok({
2798
2977
  token: tokenResult.value,
2799
2978
  createdAt: now,
@@ -2819,25 +2998,71 @@ var LocalBotGuardProvider = class {
2819
2998
  return result;
2820
2999
  }
2821
3000
  async initialize() {
3001
+ log$1.info("=== Starting BotGuard initialization ===");
3002
+ log$1.time("botguard-init");
3003
+ log$1.info("[1/6] Fetching WAA challenge...");
3004
+ log$1.time("waa-challenge");
2822
3005
  const challengeResult = await this.challengeFetcher.fetchFullChallenge();
2823
- if (!isOk(challengeResult)) return challengeResult;
3006
+ log$1.timeEnd("waa-challenge");
3007
+ if (!isOk(challengeResult)) {
3008
+ log$1.error("[1/6] FAILED: Could not fetch WAA challenge", challengeResult.error);
3009
+ return challengeResult;
3010
+ }
2824
3011
  this.challenge = challengeResult.value;
3012
+ log$1.success(`[1/6] Challenge received (program: ${this.challenge.program.length} bytes, globalName: ${this.challenge.globalName})`);
3013
+ log$1.info("[2/6] Fetching attestation...");
3014
+ log$1.time("attestation");
2825
3015
  const attResult = await this.challengeFetcher.fetchAttestation();
2826
- if (!isOk(attResult)) return attResult;
3016
+ log$1.timeEnd("attestation");
3017
+ if (!isOk(attResult)) {
3018
+ log$1.error("[2/6] FAILED: Could not fetch attestation", attResult.error);
3019
+ return attResult;
3020
+ }
2827
3021
  this.attestation = attResult.value;
3022
+ log$1.success(`[2/6] Attestation received (visitorData: ${this.attestation.visitorData.substring(0, 30)}...)`);
3023
+ log$1.info("[3/6] Creating BotGuard client (JSDOM VM)...");
3024
+ log$1.time("botguard-client");
2828
3025
  const clientResult = await BotGuardClient.create(this.challenge, { timeout: this.options.timeout });
2829
- if (!isOk(clientResult)) return clientResult;
3026
+ log$1.timeEnd("botguard-client");
3027
+ if (!isOk(clientResult)) {
3028
+ log$1.error("[3/6] FAILED: Could not create BotGuard client", clientResult.error);
3029
+ return clientResult;
3030
+ }
2830
3031
  this.client = clientResult.value;
3032
+ log$1.success("[3/6] BotGuard client created");
3033
+ log$1.info("[4/6] Generating BotGuard snapshot...");
3034
+ log$1.time("snapshot");
2831
3035
  const snapshotResult = await this.client.snapshotWithSignalOutput();
2832
- if (!isOk(snapshotResult)) return snapshotResult;
3036
+ log$1.timeEnd("snapshot");
3037
+ if (!isOk(snapshotResult)) {
3038
+ log$1.error("[4/6] FAILED: Could not generate snapshot", snapshotResult.error);
3039
+ return snapshotResult;
3040
+ }
2833
3041
  const { snapshot, webPoSignalOutput } = snapshotResult.value;
3042
+ log$1.success(`[4/6] Snapshot generated (length: ${snapshot.length}, signals: ${webPoSignalOutput.length})`);
3043
+ log$1.info("[5/6] Fetching integrity token from GenerateIT...");
3044
+ log$1.time("integrity-token");
2834
3045
  const integrityResult = await fetchIntegrityToken(snapshot, { timeout: this.options.timeout });
2835
- if (!isOk(integrityResult)) return integrityResult;
3046
+ log$1.timeEnd("integrity-token");
3047
+ if (!isOk(integrityResult)) {
3048
+ log$1.error("[5/6] FAILED: Could not fetch integrity token", integrityResult.error);
3049
+ return integrityResult;
3050
+ }
2836
3051
  this.integrityData = integrityResult.value;
2837
3052
  this.createdAt = Date.now();
3053
+ log$1.success(`[5/6] Integrity token received (TTL: ${this.integrityData.estimatedTtlSecs}s, refreshThreshold: ${this.integrityData.mintRefreshThreshold})`);
3054
+ log$1.info("[6/6] Creating WebPoMinter...");
3055
+ log$1.time("minter-create");
2838
3056
  const minterResult = await WebPoMinter.create(this.integrityData, webPoSignalOutput);
2839
- if (!isOk(minterResult)) return minterResult;
3057
+ log$1.timeEnd("minter-create");
3058
+ if (!isOk(minterResult)) {
3059
+ log$1.error("[6/6] FAILED: Could not create WebPoMinter", minterResult.error);
3060
+ return minterResult;
3061
+ }
2840
3062
  this.minter = minterResult.value;
3063
+ log$1.success("[6/6] WebPoMinter created");
3064
+ log$1.timeEnd("botguard-init");
3065
+ log$1.success("=== BotGuard initialization COMPLETE ===");
2841
3066
  return ok(void 0);
2842
3067
  }
2843
3068
  reset() {
@@ -3005,6 +3230,7 @@ var TokenCache = class {
3005
3230
 
3006
3231
  //#endregion
3007
3232
  //#region src/po-token/manager.ts
3233
+ const log = logger.scope("PoTokenManager");
3008
3234
  var PoTokenManager = class {
3009
3235
  staticToken;
3010
3236
  policies;
@@ -3018,22 +3244,53 @@ var PoTokenManager = class {
3018
3244
  if (config.cacheEnabled !== false && config.cachePath) this.cache = new TokenCache(config.cachePath);
3019
3245
  }
3020
3246
  async getToken(identifier, client = "WEB", binding) {
3021
- if (this.staticToken) return ok(this.staticToken);
3022
- if (!this.isRequired(client)) return ok("");
3247
+ log.info(`getToken called`, {
3248
+ identifier: identifier.substring(0, 20) + "...",
3249
+ client,
3250
+ hasBinding: !!binding
3251
+ });
3252
+ if (this.staticToken) {
3253
+ log.debug(`Using static token (length: ${this.staticToken.length})`);
3254
+ return ok(this.staticToken);
3255
+ }
3256
+ if (!this.isRequired(client)) {
3257
+ log.debug(`Token not required for client ${client}`);
3258
+ return ok("");
3259
+ }
3023
3260
  const context = binding ? "GVS" : "GVS";
3024
3261
  if (this.cache) {
3025
3262
  const cachedResult = this.cache.get(identifier, client, context);
3026
- if (isOk(cachedResult) && cachedResult.value && cachedResult.value.expiresAt > Date.now()) return ok(cachedResult.value.token);
3027
- }
3028
- for (const provider of this.providers) {
3029
- if (!await provider.isAvailable()) continue;
3263
+ if (isOk(cachedResult) && cachedResult.value && cachedResult.value.expiresAt > Date.now()) {
3264
+ log.success(`Cache HIT - using cached token (expires in ${Math.round((cachedResult.value.expiresAt - Date.now()) / 1e3)}s)`);
3265
+ return ok(cachedResult.value.token);
3266
+ }
3267
+ log.debug(`Cache MISS - need to generate new token`);
3268
+ }
3269
+ log.info(`Trying ${this.providers.length} provider(s) to generate token`);
3270
+ for (let i = 0; i < this.providers.length; i++) {
3271
+ const provider = this.providers[i];
3272
+ const providerName = provider.constructor.name;
3273
+ log.debug(`Checking provider ${i + 1}/${this.providers.length}: ${providerName}`);
3274
+ if (!await provider.isAvailable()) {
3275
+ log.warn(`Provider ${providerName} not available, skipping`);
3276
+ continue;
3277
+ }
3278
+ log.info(`Provider ${providerName} available, generating token...`);
3030
3279
  const result = await provider.generate(identifier, binding);
3031
3280
  if (isOk(result)) {
3032
- if (this.cache) this.cache.set(result.value);
3281
+ log.success(`Provider ${providerName} generated token successfully (length: ${result.value.token.length})`);
3282
+ if (this.cache) {
3283
+ this.cache.set(result.value);
3284
+ log.debug(`Token cached`);
3285
+ }
3033
3286
  return ok(result.value.token);
3034
3287
  }
3288
+ log.warn(`Provider ${providerName} failed to generate token`);
3035
3289
  }
3036
- return ok(generateColdStartToken(identifier));
3290
+ log.warn(`All providers failed, generating cold start token`);
3291
+ const coldToken = generateColdStartToken(identifier);
3292
+ log.info(`Cold start token generated (length: ${coldToken.length})`);
3293
+ return ok(coldToken);
3037
3294
  }
3038
3295
  async getTokenData(identifier, client = "WEB", binding) {
3039
3296
  if (this.staticToken) return ok({
@@ -3127,5 +3384,5 @@ function appendPoToken(url, poToken) {
3127
3384
  }
3128
3385
 
3129
3386
  //#endregion
3130
- export { LocalBotGuardProvider, PoTokenManager, YouTubeExtractor, andThen, appendPoToken, bundlpLogger, err, extractorLogger, getDownloadHeaders, getMinimalDownloadHeaders, isErr, isOk, map, mapErr, match, ok, tryCatch, tryCatchAsync, unwrap, unwrapOr };
3387
+ export { LocalBotGuardProvider, PoTokenManager, YouTubeExtractor, andThen, appendPoToken, bundlpLogger, detectFormat, err, extractorLogger, filterByDomain, filterExpired, getDownloadHeaders, getMinimalDownloadHeaders, httpClient, isErr, isOk, map, mapErr, match, ok, parseCookies, parseJSON, parseNetscape, toCookieHeader, toJSONFormat, toNetscapeFormat, tryCatch, tryCatchAsync, unwrap, unwrapOr };
3131
3388
  //# sourceMappingURL=index.mjs.map