@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.d.mts +77 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +324 -67
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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")
|
|
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
|
-
|
|
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")
|
|
2453
|
-
|
|
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")
|
|
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))
|
|
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)
|
|
2550
|
-
|
|
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)
|
|
2620
|
-
|
|
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)
|
|
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")
|
|
2693
|
-
|
|
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
|
-
|
|
2696
|
-
|
|
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)
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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)
|
|
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")
|
|
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))
|
|
2792
|
-
|
|
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))
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3022
|
-
|
|
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())
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|