@mks2508/bundlp 0.1.6 → 0.1.7
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.map +1 -1
- package/dist/index.mjs +263 -63
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -457,7 +457,7 @@ function isDrmOnly(formats) {
|
|
|
457
457
|
|
|
458
458
|
//#endregion
|
|
459
459
|
//#region src/innertube/client.ts
|
|
460
|
-
const log = logger.scope("InnerTube");
|
|
460
|
+
const log$5 = logger.scope("InnerTube");
|
|
461
461
|
/**
|
|
462
462
|
* Client for interacting with YouTube's InnerTube API.
|
|
463
463
|
*/
|
|
@@ -521,7 +521,7 @@ var InnerTubeClient = class {
|
|
|
521
521
|
*/
|
|
522
522
|
async fetchPlayer(videoId, options = {}) {
|
|
523
523
|
const config = INNERTUBE_CLIENTS[this.currentClient];
|
|
524
|
-
log.debug(`Fetching player for ${videoId} with client ${this.currentClient}`);
|
|
524
|
+
log$5.debug(`Fetching player for ${videoId} with client ${this.currentClient}`);
|
|
525
525
|
const payload = {
|
|
526
526
|
context: this.buildContext(),
|
|
527
527
|
videoId,
|
|
@@ -532,45 +532,45 @@ var InnerTubeClient = class {
|
|
|
532
532
|
if (options.poToken) {
|
|
533
533
|
if (!payload.serviceIntegrityDimensions) payload.serviceIntegrityDimensions = {};
|
|
534
534
|
payload.serviceIntegrityDimensions.poToken = options.poToken;
|
|
535
|
-
log.debug(`Using po_token (length: ${options.poToken.length})`);
|
|
535
|
+
log$5.debug(`Using po_token (length: ${options.poToken.length})`);
|
|
536
536
|
}
|
|
537
537
|
const url = `${INNER_TUBE_API_URL}/player?key=${config.API_KEY || ""}`;
|
|
538
538
|
const responseResult = await httpClient.post(url, payload, { headers: this.getHeaders() });
|
|
539
539
|
if (isErr(responseResult)) {
|
|
540
|
-
log.error(`HTTP request failed for client ${this.currentClient}:`, responseResult.error.message);
|
|
540
|
+
log$5.error(`HTTP request failed for client ${this.currentClient}:`, responseResult.error.message);
|
|
541
541
|
return responseResult;
|
|
542
542
|
}
|
|
543
543
|
const response = responseResult.value;
|
|
544
544
|
if (!response.ok) {
|
|
545
|
-
log.error(`Player request failed for ${this.currentClient}: HTTP ${response.status}`);
|
|
545
|
+
log$5.error(`Player request failed for ${this.currentClient}: HTTP ${response.status}`);
|
|
546
546
|
return err(createError("INNERTUBE_ERROR", `Player request failed with status ${response.status}`));
|
|
547
547
|
}
|
|
548
548
|
try {
|
|
549
549
|
const validated = PlayerResponseSchema(await response.json());
|
|
550
550
|
if (validated instanceof type.errors) {
|
|
551
|
-
log.error(`Parse error for ${this.currentClient}:`, validated.summary);
|
|
551
|
+
log$5.error(`Parse error for ${this.currentClient}:`, validated.summary);
|
|
552
552
|
return err(createError("PARSE_ERROR", `Invalid player response: ${validated.summary}`));
|
|
553
553
|
}
|
|
554
554
|
const status = validated.playabilityStatus.status;
|
|
555
555
|
const reason = validated.playabilityStatus.reason || "No reason";
|
|
556
|
-
log.debug(`Client ${this.currentClient} response: status=${status}, reason=${reason}`);
|
|
556
|
+
log$5.debug(`Client ${this.currentClient} response: status=${status}, reason=${reason}`);
|
|
557
557
|
if (status === "ERROR") {
|
|
558
|
-
log.warn(`Client ${this.currentClient} returned ERROR: ${reason}`);
|
|
558
|
+
log$5.warn(`Client ${this.currentClient} returned ERROR: ${reason}`);
|
|
559
559
|
return err(createError("VIDEO_UNAVAILABLE", reason));
|
|
560
560
|
}
|
|
561
561
|
if (status === "LOGIN_REQUIRED") {
|
|
562
|
-
log.warn(`Client ${this.currentClient} requires login: ${reason}`);
|
|
562
|
+
log$5.warn(`Client ${this.currentClient} requires login: ${reason}`);
|
|
563
563
|
return err(createError("VIDEO_UNAVAILABLE", `Login required: ${reason}`));
|
|
564
564
|
}
|
|
565
565
|
if (status === "UNPLAYABLE") {
|
|
566
|
-
log.warn(`Client ${this.currentClient} unplayable: ${reason}`);
|
|
566
|
+
log$5.warn(`Client ${this.currentClient} unplayable: ${reason}`);
|
|
567
567
|
return err(createError("VIDEO_UNAVAILABLE", `Unplayable: ${reason}`));
|
|
568
568
|
}
|
|
569
569
|
const formatsCount = (validated.streamingData?.formats?.length || 0) + (validated.streamingData?.adaptiveFormats?.length || 0);
|
|
570
|
-
log.info(`Client ${this.currentClient} success: ${formatsCount} formats`);
|
|
570
|
+
log$5.info(`Client ${this.currentClient} success: ${formatsCount} formats`);
|
|
571
571
|
return ok(validated);
|
|
572
572
|
} catch (error) {
|
|
573
|
-
log.error(`Parse exception for ${this.currentClient}:`, error);
|
|
573
|
+
log$5.error(`Parse exception for ${this.currentClient}:`, error);
|
|
574
574
|
return err(createError("PARSE_ERROR", "Failed to parse InnerTube response", error));
|
|
575
575
|
}
|
|
576
576
|
}
|
|
@@ -583,35 +583,35 @@ var InnerTubeClient = class {
|
|
|
583
583
|
*/
|
|
584
584
|
async fetchPlayerWithFallback(videoId, options = {}) {
|
|
585
585
|
const errors = [];
|
|
586
|
-
log.info(`Starting fallback extraction for ${videoId}`);
|
|
587
|
-
log.info(`Fallback order: ${this.FALLBACK_ORDER.join(" → ")}`);
|
|
586
|
+
log$5.info(`Starting fallback extraction for ${videoId}`);
|
|
587
|
+
log$5.info(`Fallback order: ${this.FALLBACK_ORDER.join(" → ")}`);
|
|
588
588
|
for (const clientName of this.FALLBACK_ORDER) {
|
|
589
|
-
log.info(`Trying client: ${clientName}`);
|
|
589
|
+
log$5.info(`Trying client: ${clientName}`);
|
|
590
590
|
if (isErr(this.setClient(clientName))) {
|
|
591
|
-
log.warn(`Failed to set client ${clientName}`);
|
|
591
|
+
log$5.warn(`Failed to set client ${clientName}`);
|
|
592
592
|
continue;
|
|
593
593
|
}
|
|
594
594
|
const result = await this.fetchPlayer(videoId, options);
|
|
595
595
|
if (isOk(result)) {
|
|
596
596
|
const validationResult = this.isValidResponse(result.value);
|
|
597
597
|
if (validationResult.valid) {
|
|
598
|
-
log.success(`Client ${clientName} returned valid response`);
|
|
598
|
+
log$5.success(`Client ${clientName} returned valid response`);
|
|
599
599
|
return result;
|
|
600
600
|
}
|
|
601
|
-
log.warn(`Client ${clientName} response invalid: ${validationResult.reason}`);
|
|
601
|
+
log$5.warn(`Client ${clientName} response invalid: ${validationResult.reason}`);
|
|
602
602
|
errors.push({
|
|
603
603
|
client: clientName,
|
|
604
604
|
error: createError("VIDEO_UNAVAILABLE", validationResult.reason)
|
|
605
605
|
});
|
|
606
606
|
} else {
|
|
607
|
-
log.warn(`Client ${clientName} failed: ${result.error.message}`);
|
|
607
|
+
log$5.warn(`Client ${clientName} failed: ${result.error.message}`);
|
|
608
608
|
errors.push({
|
|
609
609
|
client: clientName,
|
|
610
610
|
error: result.error
|
|
611
611
|
});
|
|
612
612
|
}
|
|
613
613
|
}
|
|
614
|
-
log.error(`All clients failed for ${videoId}. Errors:`, errors.map((e) => ({
|
|
614
|
+
log$5.error(`All clients failed for ${videoId}. Errors:`, errors.map((e) => ({
|
|
615
615
|
client: e.client,
|
|
616
616
|
error: e.error.message
|
|
617
617
|
})));
|
|
@@ -2385,6 +2385,7 @@ const PO_TOKEN_POLICIES = {
|
|
|
2385
2385
|
|
|
2386
2386
|
//#endregion
|
|
2387
2387
|
//#region src/po-token/botguard/challenge.ts
|
|
2388
|
+
const log$4 = logger.scope("ChallengeFetcher");
|
|
2388
2389
|
const WAA_CREATE_ENDPOINT = "https://jnn-pa.googleapis.com/$rpc/google.internal.waa.v1.Waa/Create";
|
|
2389
2390
|
const INNERTUBE_ATT_ENDPOINT = "https://www.youtube.com/youtubei/v1/att/get";
|
|
2390
2391
|
const GOOG_API_KEY$1 = "AIzaSyDyT5W0Jh49F30Pqqtyfdf7pDLFKLJoAnw";
|
|
@@ -2395,6 +2396,7 @@ var ChallengeFetcher = class {
|
|
|
2395
2396
|
this.timeout = options.timeout ?? 15e3;
|
|
2396
2397
|
}
|
|
2397
2398
|
async fetchAttestation() {
|
|
2399
|
+
log$4.info(`Fetching attestation from ${INNERTUBE_ATT_ENDPOINT}`);
|
|
2398
2400
|
const payload = { context: { client: {
|
|
2399
2401
|
clientName: "WEB",
|
|
2400
2402
|
clientVersion: "2.20250222.10.00",
|
|
@@ -2402,6 +2404,7 @@ var ChallengeFetcher = class {
|
|
|
2402
2404
|
gl: "US"
|
|
2403
2405
|
} } };
|
|
2404
2406
|
try {
|
|
2407
|
+
log$4.debug("Sending POST request...");
|
|
2405
2408
|
const response = await fetch(INNERTUBE_ATT_ENDPOINT, {
|
|
2406
2409
|
method: "POST",
|
|
2407
2410
|
headers: {
|
|
@@ -2413,11 +2416,22 @@ var ChallengeFetcher = class {
|
|
|
2413
2416
|
body: JSON.stringify(payload),
|
|
2414
2417
|
signal: AbortSignal.timeout(this.timeout)
|
|
2415
2418
|
});
|
|
2416
|
-
|
|
2419
|
+
log$4.debug(`Response status: ${response.status}`);
|
|
2420
|
+
if (!response.ok) {
|
|
2421
|
+
log$4.error(`Attestation request failed with status ${response.status}`);
|
|
2422
|
+
return err(createError("BOTGUARD_INIT_FAILED", `Attestation request failed with status ${response.status}`));
|
|
2423
|
+
}
|
|
2417
2424
|
const data = await response.json();
|
|
2418
|
-
|
|
2425
|
+
log$4.debug("Parsing attestation response...");
|
|
2426
|
+
const result = this.parseAttestationResponse(data);
|
|
2427
|
+
if (result.ok) log$4.success(`Attestation fetched successfully (visitorData length: ${result.value.visitorData.length})`);
|
|
2428
|
+
return result;
|
|
2419
2429
|
} catch (error) {
|
|
2420
|
-
if (error instanceof Error && error.name === "TimeoutError")
|
|
2430
|
+
if (error instanceof Error && error.name === "TimeoutError") {
|
|
2431
|
+
log$4.error(`Attestation fetch timeout after ${this.timeout}ms`);
|
|
2432
|
+
return err(createError("BOTGUARD_INIT_FAILED", "Attestation fetch timeout"));
|
|
2433
|
+
}
|
|
2434
|
+
log$4.error("Failed to fetch attestation", error);
|
|
2421
2435
|
return err(createError("BOTGUARD_INIT_FAILED", "Failed to fetch attestation", error));
|
|
2422
2436
|
}
|
|
2423
2437
|
}
|
|
@@ -2437,7 +2451,9 @@ var ChallengeFetcher = class {
|
|
|
2437
2451
|
});
|
|
2438
2452
|
}
|
|
2439
2453
|
async fetchWaaChallenge() {
|
|
2454
|
+
log$4.info(`Fetching WAA challenge from ${WAA_CREATE_ENDPOINT}`);
|
|
2440
2455
|
try {
|
|
2456
|
+
log$4.debug("Sending POST request with API key...");
|
|
2441
2457
|
const response = await fetch(WAA_CREATE_ENDPOINT, {
|
|
2442
2458
|
method: "POST",
|
|
2443
2459
|
headers: {
|
|
@@ -2447,12 +2463,26 @@ var ChallengeFetcher = class {
|
|
|
2447
2463
|
body: JSON.stringify([REQUEST_KEY$1]),
|
|
2448
2464
|
signal: AbortSignal.timeout(this.timeout)
|
|
2449
2465
|
});
|
|
2450
|
-
|
|
2466
|
+
log$4.debug(`Response status: ${response.status}`);
|
|
2467
|
+
if (!response.ok) {
|
|
2468
|
+
log$4.error(`WAA Create request failed with status ${response.status}`);
|
|
2469
|
+
return err(createError("BOTGUARD_INIT_FAILED", `WAA Create request failed with status ${response.status}`));
|
|
2470
|
+
}
|
|
2451
2471
|
const encoded = (await response.json())[1];
|
|
2452
|
-
if (!encoded || typeof encoded !== "string")
|
|
2453
|
-
|
|
2472
|
+
if (!encoded || typeof encoded !== "string") {
|
|
2473
|
+
log$4.error("Invalid WAA response format - missing encoded data");
|
|
2474
|
+
return err(createError("PARSE_ERROR", "Invalid WAA response format"));
|
|
2475
|
+
}
|
|
2476
|
+
log$4.debug(`Descrambling WAA response (encoded length: ${encoded.length})...`);
|
|
2477
|
+
const result = this.descrambleWaaResponse(encoded);
|
|
2478
|
+
if (result.ok) log$4.success(`WAA challenge descrambled (program: ${result.value.program.length} bytes, globalName: ${result.value.globalName})`);
|
|
2479
|
+
return result;
|
|
2454
2480
|
} catch (error) {
|
|
2455
|
-
if (error instanceof Error && error.name === "TimeoutError")
|
|
2481
|
+
if (error instanceof Error && error.name === "TimeoutError") {
|
|
2482
|
+
log$4.error(`WAA Create fetch timeout after ${this.timeout}ms`);
|
|
2483
|
+
return err(createError("BOTGUARD_INIT_FAILED", "WAA Create fetch timeout"));
|
|
2484
|
+
}
|
|
2485
|
+
log$4.error("Failed to fetch WAA challenge", error);
|
|
2456
2486
|
return err(createError("BOTGUARD_INIT_FAILED", "Failed to fetch WAA challenge", error));
|
|
2457
2487
|
}
|
|
2458
2488
|
}
|
|
@@ -2493,6 +2523,7 @@ var ChallengeFetcher = class {
|
|
|
2493
2523
|
|
|
2494
2524
|
//#endregion
|
|
2495
2525
|
//#region src/po-token/botguard/client.ts
|
|
2526
|
+
const log$3 = logger.scope("BotGuardClient");
|
|
2496
2527
|
var DeferredPromise = class {
|
|
2497
2528
|
promise;
|
|
2498
2529
|
resolve;
|
|
@@ -2520,13 +2551,21 @@ var BotGuardClient = class BotGuardClient {
|
|
|
2520
2551
|
this.snapshotTimeout = 5e3;
|
|
2521
2552
|
}
|
|
2522
2553
|
static async create(challenge, options = {}) {
|
|
2554
|
+
log$3.info("Creating BotGuard client...");
|
|
2555
|
+
log$3.debug(`Options: timeout=${options.timeout || "default"}`);
|
|
2523
2556
|
const client = new BotGuardClient(challenge, options);
|
|
2524
2557
|
const loadResult = await client.load(challenge);
|
|
2525
|
-
if (!isOk(loadResult))
|
|
2558
|
+
if (!isOk(loadResult)) {
|
|
2559
|
+
log$3.error("Client creation failed", loadResult.error);
|
|
2560
|
+
return loadResult;
|
|
2561
|
+
}
|
|
2562
|
+
log$3.success("BotGuard client created successfully");
|
|
2526
2563
|
return ok(client);
|
|
2527
2564
|
}
|
|
2528
2565
|
async load(challenge) {
|
|
2566
|
+
log$3.debug("Loading BotGuard VM environment...");
|
|
2529
2567
|
try {
|
|
2568
|
+
log$3.debug("Creating JSDOM instance with YouTube context");
|
|
2530
2569
|
this.dom = new JSDOM("<!DOCTYPE html><html><head></head><body></body></html>", {
|
|
2531
2570
|
url: "https://www.youtube.com/",
|
|
2532
2571
|
runScripts: "dangerously",
|
|
@@ -2543,15 +2582,25 @@ var BotGuardClient = class BotGuardClient {
|
|
|
2543
2582
|
window.Request = globalThis.Request;
|
|
2544
2583
|
window.Response = globalThis.Response;
|
|
2545
2584
|
window.Headers = globalThis.Headers;
|
|
2585
|
+
log$3.debug(`Evaluating interpreter script (${challenge.interpreterScript.length} bytes)...`);
|
|
2546
2586
|
const evalFn = window.eval;
|
|
2547
2587
|
evalFn(challenge.interpreterScript);
|
|
2548
2588
|
this.vm = window[this.globalName];
|
|
2549
|
-
if (!this.vm)
|
|
2550
|
-
|
|
2589
|
+
if (!this.vm) {
|
|
2590
|
+
log$3.error(`VM not found at globalName: ${this.globalName}`);
|
|
2591
|
+
return err(createError("BOTGUARD_INIT_FAILED", `VM not found at globalName: ${this.globalName}`));
|
|
2592
|
+
}
|
|
2593
|
+
if (typeof this.vm.a !== "function") {
|
|
2594
|
+
log$3.error("VM init function (a) not found");
|
|
2595
|
+
return err(createError("BOTGUARD_INIT_FAILED", "VM init function (a) not found"));
|
|
2596
|
+
}
|
|
2597
|
+
log$3.debug("Loading BotGuard program...");
|
|
2551
2598
|
const loadResult = await this.loadProgram();
|
|
2552
2599
|
if (!isOk(loadResult)) return loadResult;
|
|
2600
|
+
log$3.success("BotGuard VM loaded successfully");
|
|
2553
2601
|
return ok(void 0);
|
|
2554
2602
|
} catch (error) {
|
|
2603
|
+
log$3.error("Failed to load BotGuard", error);
|
|
2555
2604
|
return err(createError("BOTGUARD_INIT_FAILED", `Failed to load BotGuard: ${error.message}`, error));
|
|
2556
2605
|
}
|
|
2557
2606
|
}
|
|
@@ -2607,6 +2656,7 @@ var BotGuardClient = class BotGuardClient {
|
|
|
2607
2656
|
}
|
|
2608
2657
|
}
|
|
2609
2658
|
async snapshotWithSignalOutput(binding) {
|
|
2659
|
+
log$3.info("Generating snapshot with signal output...");
|
|
2610
2660
|
const webPoSignalOutput = [];
|
|
2611
2661
|
const snapshotArgs = [
|
|
2612
2662
|
binding,
|
|
@@ -2616,10 +2666,17 @@ var BotGuardClient = class BotGuardClient {
|
|
|
2616
2666
|
];
|
|
2617
2667
|
try {
|
|
2618
2668
|
let snapshot;
|
|
2619
|
-
if (this.syncSnapshotFunction)
|
|
2620
|
-
|
|
2669
|
+
if (this.syncSnapshotFunction) {
|
|
2670
|
+
log$3.debug("Using sync snapshot function");
|
|
2671
|
+
snapshot = await this.syncSnapshotFunction(snapshotArgs);
|
|
2672
|
+
} else {
|
|
2673
|
+
log$3.debug("Using async snapshot function, waiting for VM functions...");
|
|
2621
2674
|
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)
|
|
2675
|
+
if (!vmFunctions.asyncSnapshotFunction) {
|
|
2676
|
+
log$3.error("No snapshot function available in VM");
|
|
2677
|
+
return err(createError("BOTGUARD_SNAPSHOT_FAILED", "No snapshot function available"));
|
|
2678
|
+
}
|
|
2679
|
+
log$3.debug("Executing async snapshot...");
|
|
2623
2680
|
snapshot = await new Promise((resolve, reject) => {
|
|
2624
2681
|
const timeout = setTimeout(() => reject(/* @__PURE__ */ new Error("Snapshot timeout")), this.snapshotTimeout);
|
|
2625
2682
|
vmFunctions.asyncSnapshotFunction((response) => {
|
|
@@ -2628,11 +2685,13 @@ var BotGuardClient = class BotGuardClient {
|
|
|
2628
2685
|
}, snapshotArgs);
|
|
2629
2686
|
});
|
|
2630
2687
|
}
|
|
2688
|
+
log$3.success(`Snapshot generated (length: ${snapshot.length}, signals: ${webPoSignalOutput.length})`);
|
|
2631
2689
|
return ok({
|
|
2632
2690
|
snapshot,
|
|
2633
2691
|
webPoSignalOutput
|
|
2634
2692
|
});
|
|
2635
2693
|
} catch (error) {
|
|
2694
|
+
log$3.error("Snapshot generation failed", error);
|
|
2636
2695
|
return err(createError("BOTGUARD_SNAPSHOT_FAILED", `Snapshot failed: ${error.message}`, error));
|
|
2637
2696
|
}
|
|
2638
2697
|
}
|
|
@@ -2679,6 +2738,7 @@ function u8ToBase64Url$1(u8) {
|
|
|
2679
2738
|
|
|
2680
2739
|
//#endregion
|
|
2681
2740
|
//#region src/po-token/minter/web-minter.ts
|
|
2741
|
+
const log$2 = logger.scope("WebPoMinter");
|
|
2682
2742
|
const WAA_GENERATE_IT_ENDPOINT = "https://jnn-pa.googleapis.com/$rpc/google.internal.waa.v1.Waa/GenerateIT";
|
|
2683
2743
|
const GOOG_API_KEY = "AIzaSyDyT5W0Jh49F30Pqqtyfdf7pDLFKLJoAnw";
|
|
2684
2744
|
const REQUEST_KEY = "O43z0dpjhgX20SCx4KAo";
|
|
@@ -2688,38 +2748,73 @@ var WebPoMinter = class WebPoMinter {
|
|
|
2688
2748
|
this.mintCallback = mintCallback;
|
|
2689
2749
|
}
|
|
2690
2750
|
static async create(integrityTokenData, webPoSignalOutput) {
|
|
2751
|
+
log$2.info("Creating WebPoMinter...");
|
|
2691
2752
|
const getMinter = webPoSignalOutput[0];
|
|
2692
|
-
if (!getMinter || typeof getMinter !== "function")
|
|
2693
|
-
|
|
2753
|
+
if (!getMinter || typeof getMinter !== "function") {
|
|
2754
|
+
log$2.error("Minter function not found in webPoSignalOutput");
|
|
2755
|
+
return err(createError("INTEGRITY_TOKEN_FAILED", "Minter function not found in webPoSignalOutput"));
|
|
2756
|
+
}
|
|
2757
|
+
if (!integrityTokenData.integrityToken) {
|
|
2758
|
+
log$2.error("No integrity token provided");
|
|
2759
|
+
return err(createError("INTEGRITY_TOKEN_FAILED", "No integrity token provided"));
|
|
2760
|
+
}
|
|
2694
2761
|
try {
|
|
2695
|
-
|
|
2696
|
-
|
|
2762
|
+
log$2.debug(`Decoding integrity token (length: ${integrityTokenData.integrityToken.length})...`);
|
|
2763
|
+
const integrityTokenBytes = base64ToU8(integrityTokenData.integrityToken);
|
|
2764
|
+
log$2.debug("Calling getMinter with integrity token bytes...");
|
|
2765
|
+
const mintCallback = await getMinter(integrityTokenBytes);
|
|
2766
|
+
if (typeof mintCallback !== "function") {
|
|
2767
|
+
log$2.error("Invalid mint callback returned (not a function)");
|
|
2768
|
+
return err(createError("INTEGRITY_TOKEN_FAILED", "Invalid mint callback returned"));
|
|
2769
|
+
}
|
|
2770
|
+
log$2.success("WebPoMinter created successfully");
|
|
2697
2771
|
return ok(new WebPoMinter(mintCallback));
|
|
2698
2772
|
} catch (error) {
|
|
2773
|
+
log$2.error("Failed to create minter", error);
|
|
2699
2774
|
return err(createError("INTEGRITY_TOKEN_FAILED", `Failed to create minter: ${error.message}`, error));
|
|
2700
2775
|
}
|
|
2701
2776
|
}
|
|
2702
2777
|
async mint(identifier) {
|
|
2778
|
+
log$2.debug(`Minting for identifier: ${identifier.substring(0, 30)}...`);
|
|
2703
2779
|
try {
|
|
2704
2780
|
const identifierBytes = new TextEncoder().encode(identifier);
|
|
2705
2781
|
const result = await this.mintCallback(identifierBytes);
|
|
2706
|
-
if (!result)
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2782
|
+
if (!result) {
|
|
2783
|
+
log$2.error("Mint returned undefined");
|
|
2784
|
+
return err(createError("INTEGRITY_TOKEN_FAILED", "Mint returned undefined"));
|
|
2785
|
+
}
|
|
2786
|
+
if (result instanceof Uint8Array) {
|
|
2787
|
+
log$2.debug(`Mint successful (Uint8Array, ${result.length} bytes)`);
|
|
2788
|
+
return ok(result);
|
|
2789
|
+
}
|
|
2790
|
+
if (ArrayBuffer.isView(result)) {
|
|
2791
|
+
log$2.debug(`Mint successful (ArrayBufferView, ${result.buffer.byteLength} bytes)`);
|
|
2792
|
+
return ok(new Uint8Array(result.buffer));
|
|
2793
|
+
}
|
|
2794
|
+
if (Array.isArray(result)) {
|
|
2795
|
+
log$2.debug(`Mint successful (Array, ${result.length} bytes)`);
|
|
2796
|
+
return ok(new Uint8Array(result));
|
|
2797
|
+
}
|
|
2798
|
+
log$2.error(`Mint returned invalid type: ${typeof result}`);
|
|
2710
2799
|
return err(createError("INTEGRITY_TOKEN_FAILED", `Mint returned invalid type: ${typeof result}`));
|
|
2711
2800
|
} catch (error) {
|
|
2801
|
+
log$2.error("Mint failed", error);
|
|
2712
2802
|
return err(createError("INTEGRITY_TOKEN_FAILED", `Mint failed: ${error.message}`, error));
|
|
2713
2803
|
}
|
|
2714
2804
|
}
|
|
2715
2805
|
async mintAsWebsafeString(identifier) {
|
|
2806
|
+
log$2.info(`Minting as websafe string for: ${identifier.substring(0, 30)}...`);
|
|
2716
2807
|
const mintResult = await this.mint(identifier);
|
|
2717
2808
|
if (!isOk(mintResult)) return mintResult;
|
|
2718
|
-
|
|
2809
|
+
const token = u8ToBase64Url(mintResult.value);
|
|
2810
|
+
log$2.success(`Websafe token generated (length: ${token.length})`);
|
|
2811
|
+
return ok(token);
|
|
2719
2812
|
}
|
|
2720
2813
|
};
|
|
2721
2814
|
async function fetchIntegrityToken(botguardResponse, options = {}) {
|
|
2722
2815
|
const timeout = options.timeout ?? 1e4;
|
|
2816
|
+
log$2.info("Fetching integrity token from GenerateIT...");
|
|
2817
|
+
log$2.debug(`BotGuard response length: ${botguardResponse.length}, timeout: ${timeout}ms`);
|
|
2723
2818
|
try {
|
|
2724
2819
|
const response = await fetch(WAA_GENERATE_IT_ENDPOINT, {
|
|
2725
2820
|
method: "POST",
|
|
@@ -2730,13 +2825,21 @@ async function fetchIntegrityToken(botguardResponse, options = {}) {
|
|
|
2730
2825
|
body: JSON.stringify([REQUEST_KEY, botguardResponse]),
|
|
2731
2826
|
signal: AbortSignal.timeout(timeout)
|
|
2732
2827
|
});
|
|
2733
|
-
|
|
2828
|
+
log$2.debug(`GenerateIT response status: ${response.status}`);
|
|
2829
|
+
if (!response.ok) {
|
|
2830
|
+
log$2.error(`GenerateIT request failed with status ${response.status}`);
|
|
2831
|
+
return err(createError("INTEGRITY_TOKEN_FAILED", `GenerateIT request failed with status ${response.status}`));
|
|
2832
|
+
}
|
|
2734
2833
|
const json = await response.json();
|
|
2735
2834
|
const integrityToken = json[0];
|
|
2736
2835
|
const estimatedTtlSecs = json[1];
|
|
2737
2836
|
const mintRefreshThreshold = json[2];
|
|
2738
2837
|
const websafeFallbackToken = json[3];
|
|
2739
|
-
if (!integrityToken)
|
|
2838
|
+
if (!integrityToken) {
|
|
2839
|
+
log$2.error("No integrity token in GenerateIT response");
|
|
2840
|
+
return err(createError("INTEGRITY_TOKEN_FAILED", "No integrity token in response"));
|
|
2841
|
+
}
|
|
2842
|
+
log$2.success(`Integrity token received (length: ${integrityToken.length}, TTL: ${estimatedTtlSecs}s, threshold: ${mintRefreshThreshold})`);
|
|
2740
2843
|
return ok({
|
|
2741
2844
|
integrityToken,
|
|
2742
2845
|
estimatedTtlSecs: estimatedTtlSecs ?? 3600,
|
|
@@ -2744,7 +2847,11 @@ async function fetchIntegrityToken(botguardResponse, options = {}) {
|
|
|
2744
2847
|
websafeFallbackToken
|
|
2745
2848
|
});
|
|
2746
2849
|
} catch (error) {
|
|
2747
|
-
if (error instanceof Error && error.name === "TimeoutError")
|
|
2850
|
+
if (error instanceof Error && error.name === "TimeoutError") {
|
|
2851
|
+
log$2.error(`GenerateIT request timeout after ${timeout}ms`);
|
|
2852
|
+
return err(createError("INTEGRITY_TOKEN_FAILED", "GenerateIT request timeout"));
|
|
2853
|
+
}
|
|
2854
|
+
log$2.error("Failed to fetch integrity token", error);
|
|
2748
2855
|
return err(createError("INTEGRITY_TOKEN_FAILED", "Failed to fetch integrity token", error));
|
|
2749
2856
|
}
|
|
2750
2857
|
}
|
|
@@ -2761,6 +2868,7 @@ function u8ToBase64Url(u8) {
|
|
|
2761
2868
|
|
|
2762
2869
|
//#endregion
|
|
2763
2870
|
//#region src/po-token/providers/local.provider.ts
|
|
2871
|
+
const log$1 = logger.scope("LocalBotGuard");
|
|
2764
2872
|
const REFRESH_MARGIN_MS = 600 * 1e3;
|
|
2765
2873
|
var LocalBotGuardProvider = class {
|
|
2766
2874
|
name = "local-botguard";
|
|
@@ -2781,19 +2889,33 @@ var LocalBotGuardProvider = class {
|
|
|
2781
2889
|
async isAvailable() {
|
|
2782
2890
|
try {
|
|
2783
2891
|
await import("jsdom");
|
|
2892
|
+
log$1.debug("jsdom available - provider is ready");
|
|
2784
2893
|
return true;
|
|
2785
|
-
} catch {
|
|
2894
|
+
} catch (e) {
|
|
2895
|
+
log$1.warn("jsdom not available - provider disabled", e);
|
|
2786
2896
|
return false;
|
|
2787
2897
|
}
|
|
2788
2898
|
}
|
|
2789
2899
|
async generate(identifier, _binding) {
|
|
2900
|
+
log$1.info(`generate() called for identifier: ${identifier.substring(0, 30)}...`);
|
|
2790
2901
|
const initResult = await this.ensureInitialized();
|
|
2791
|
-
if (!isOk(initResult))
|
|
2792
|
-
|
|
2902
|
+
if (!isOk(initResult)) {
|
|
2903
|
+
log$1.error("Initialization failed", initResult.error);
|
|
2904
|
+
return initResult;
|
|
2905
|
+
}
|
|
2906
|
+
if (!this.minter || !this.integrityData) {
|
|
2907
|
+
log$1.error("Minter or integrityData is null after initialization");
|
|
2908
|
+
return err(createError("BOTGUARD_INIT_FAILED", "Minter not initialized"));
|
|
2909
|
+
}
|
|
2910
|
+
log$1.info("Minting po_token...");
|
|
2793
2911
|
const tokenResult = await this.minter.mintAsWebsafeString(identifier);
|
|
2794
|
-
if (!isOk(tokenResult))
|
|
2912
|
+
if (!isOk(tokenResult)) {
|
|
2913
|
+
log$1.error("Minting failed", tokenResult.error);
|
|
2914
|
+
return tokenResult;
|
|
2915
|
+
}
|
|
2795
2916
|
const now = Date.now();
|
|
2796
2917
|
const ttlMs = (this.integrityData.estimatedTtlSecs ?? 43200) * 1e3;
|
|
2918
|
+
log$1.success(`Token minted successfully (length: ${tokenResult.value.length}, TTL: ${Math.round(ttlMs / 1e3)}s)`);
|
|
2797
2919
|
return ok({
|
|
2798
2920
|
token: tokenResult.value,
|
|
2799
2921
|
createdAt: now,
|
|
@@ -2819,25 +2941,71 @@ var LocalBotGuardProvider = class {
|
|
|
2819
2941
|
return result;
|
|
2820
2942
|
}
|
|
2821
2943
|
async initialize() {
|
|
2944
|
+
log$1.info("=== Starting BotGuard initialization ===");
|
|
2945
|
+
log$1.time("botguard-init");
|
|
2946
|
+
log$1.info("[1/6] Fetching WAA challenge...");
|
|
2947
|
+
log$1.time("waa-challenge");
|
|
2822
2948
|
const challengeResult = await this.challengeFetcher.fetchFullChallenge();
|
|
2823
|
-
|
|
2949
|
+
log$1.timeEnd("waa-challenge");
|
|
2950
|
+
if (!isOk(challengeResult)) {
|
|
2951
|
+
log$1.error("[1/6] FAILED: Could not fetch WAA challenge", challengeResult.error);
|
|
2952
|
+
return challengeResult;
|
|
2953
|
+
}
|
|
2824
2954
|
this.challenge = challengeResult.value;
|
|
2955
|
+
log$1.success(`[1/6] Challenge received (program: ${this.challenge.program.length} bytes, globalName: ${this.challenge.globalName})`);
|
|
2956
|
+
log$1.info("[2/6] Fetching attestation...");
|
|
2957
|
+
log$1.time("attestation");
|
|
2825
2958
|
const attResult = await this.challengeFetcher.fetchAttestation();
|
|
2826
|
-
|
|
2959
|
+
log$1.timeEnd("attestation");
|
|
2960
|
+
if (!isOk(attResult)) {
|
|
2961
|
+
log$1.error("[2/6] FAILED: Could not fetch attestation", attResult.error);
|
|
2962
|
+
return attResult;
|
|
2963
|
+
}
|
|
2827
2964
|
this.attestation = attResult.value;
|
|
2965
|
+
log$1.success(`[2/6] Attestation received (visitorData: ${this.attestation.visitorData.substring(0, 30)}...)`);
|
|
2966
|
+
log$1.info("[3/6] Creating BotGuard client (JSDOM VM)...");
|
|
2967
|
+
log$1.time("botguard-client");
|
|
2828
2968
|
const clientResult = await BotGuardClient.create(this.challenge, { timeout: this.options.timeout });
|
|
2829
|
-
|
|
2969
|
+
log$1.timeEnd("botguard-client");
|
|
2970
|
+
if (!isOk(clientResult)) {
|
|
2971
|
+
log$1.error("[3/6] FAILED: Could not create BotGuard client", clientResult.error);
|
|
2972
|
+
return clientResult;
|
|
2973
|
+
}
|
|
2830
2974
|
this.client = clientResult.value;
|
|
2975
|
+
log$1.success("[3/6] BotGuard client created");
|
|
2976
|
+
log$1.info("[4/6] Generating BotGuard snapshot...");
|
|
2977
|
+
log$1.time("snapshot");
|
|
2831
2978
|
const snapshotResult = await this.client.snapshotWithSignalOutput();
|
|
2832
|
-
|
|
2979
|
+
log$1.timeEnd("snapshot");
|
|
2980
|
+
if (!isOk(snapshotResult)) {
|
|
2981
|
+
log$1.error("[4/6] FAILED: Could not generate snapshot", snapshotResult.error);
|
|
2982
|
+
return snapshotResult;
|
|
2983
|
+
}
|
|
2833
2984
|
const { snapshot, webPoSignalOutput } = snapshotResult.value;
|
|
2985
|
+
log$1.success(`[4/6] Snapshot generated (length: ${snapshot.length}, signals: ${webPoSignalOutput.length})`);
|
|
2986
|
+
log$1.info("[5/6] Fetching integrity token from GenerateIT...");
|
|
2987
|
+
log$1.time("integrity-token");
|
|
2834
2988
|
const integrityResult = await fetchIntegrityToken(snapshot, { timeout: this.options.timeout });
|
|
2835
|
-
|
|
2989
|
+
log$1.timeEnd("integrity-token");
|
|
2990
|
+
if (!isOk(integrityResult)) {
|
|
2991
|
+
log$1.error("[5/6] FAILED: Could not fetch integrity token", integrityResult.error);
|
|
2992
|
+
return integrityResult;
|
|
2993
|
+
}
|
|
2836
2994
|
this.integrityData = integrityResult.value;
|
|
2837
2995
|
this.createdAt = Date.now();
|
|
2996
|
+
log$1.success(`[5/6] Integrity token received (TTL: ${this.integrityData.estimatedTtlSecs}s, refreshThreshold: ${this.integrityData.mintRefreshThreshold})`);
|
|
2997
|
+
log$1.info("[6/6] Creating WebPoMinter...");
|
|
2998
|
+
log$1.time("minter-create");
|
|
2838
2999
|
const minterResult = await WebPoMinter.create(this.integrityData, webPoSignalOutput);
|
|
2839
|
-
|
|
3000
|
+
log$1.timeEnd("minter-create");
|
|
3001
|
+
if (!isOk(minterResult)) {
|
|
3002
|
+
log$1.error("[6/6] FAILED: Could not create WebPoMinter", minterResult.error);
|
|
3003
|
+
return minterResult;
|
|
3004
|
+
}
|
|
2840
3005
|
this.minter = minterResult.value;
|
|
3006
|
+
log$1.success("[6/6] WebPoMinter created");
|
|
3007
|
+
log$1.timeEnd("botguard-init");
|
|
3008
|
+
log$1.success("=== BotGuard initialization COMPLETE ===");
|
|
2841
3009
|
return ok(void 0);
|
|
2842
3010
|
}
|
|
2843
3011
|
reset() {
|
|
@@ -3005,6 +3173,7 @@ var TokenCache = class {
|
|
|
3005
3173
|
|
|
3006
3174
|
//#endregion
|
|
3007
3175
|
//#region src/po-token/manager.ts
|
|
3176
|
+
const log = logger.scope("PoTokenManager");
|
|
3008
3177
|
var PoTokenManager = class {
|
|
3009
3178
|
staticToken;
|
|
3010
3179
|
policies;
|
|
@@ -3018,22 +3187,53 @@ var PoTokenManager = class {
|
|
|
3018
3187
|
if (config.cacheEnabled !== false && config.cachePath) this.cache = new TokenCache(config.cachePath);
|
|
3019
3188
|
}
|
|
3020
3189
|
async getToken(identifier, client = "WEB", binding) {
|
|
3021
|
-
|
|
3022
|
-
|
|
3190
|
+
log.info(`getToken called`, {
|
|
3191
|
+
identifier: identifier.substring(0, 20) + "...",
|
|
3192
|
+
client,
|
|
3193
|
+
hasBinding: !!binding
|
|
3194
|
+
});
|
|
3195
|
+
if (this.staticToken) {
|
|
3196
|
+
log.debug(`Using static token (length: ${this.staticToken.length})`);
|
|
3197
|
+
return ok(this.staticToken);
|
|
3198
|
+
}
|
|
3199
|
+
if (!this.isRequired(client)) {
|
|
3200
|
+
log.debug(`Token not required for client ${client}`);
|
|
3201
|
+
return ok("");
|
|
3202
|
+
}
|
|
3023
3203
|
const context = binding ? "GVS" : "GVS";
|
|
3024
3204
|
if (this.cache) {
|
|
3025
3205
|
const cachedResult = this.cache.get(identifier, client, context);
|
|
3026
|
-
if (isOk(cachedResult) && cachedResult.value && cachedResult.value.expiresAt > Date.now())
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3206
|
+
if (isOk(cachedResult) && cachedResult.value && cachedResult.value.expiresAt > Date.now()) {
|
|
3207
|
+
log.success(`Cache HIT - using cached token (expires in ${Math.round((cachedResult.value.expiresAt - Date.now()) / 1e3)}s)`);
|
|
3208
|
+
return ok(cachedResult.value.token);
|
|
3209
|
+
}
|
|
3210
|
+
log.debug(`Cache MISS - need to generate new token`);
|
|
3211
|
+
}
|
|
3212
|
+
log.info(`Trying ${this.providers.length} provider(s) to generate token`);
|
|
3213
|
+
for (let i = 0; i < this.providers.length; i++) {
|
|
3214
|
+
const provider = this.providers[i];
|
|
3215
|
+
const providerName = provider.constructor.name;
|
|
3216
|
+
log.debug(`Checking provider ${i + 1}/${this.providers.length}: ${providerName}`);
|
|
3217
|
+
if (!await provider.isAvailable()) {
|
|
3218
|
+
log.warn(`Provider ${providerName} not available, skipping`);
|
|
3219
|
+
continue;
|
|
3220
|
+
}
|
|
3221
|
+
log.info(`Provider ${providerName} available, generating token...`);
|
|
3030
3222
|
const result = await provider.generate(identifier, binding);
|
|
3031
3223
|
if (isOk(result)) {
|
|
3032
|
-
|
|
3224
|
+
log.success(`Provider ${providerName} generated token successfully (length: ${result.value.token.length})`);
|
|
3225
|
+
if (this.cache) {
|
|
3226
|
+
this.cache.set(result.value);
|
|
3227
|
+
log.debug(`Token cached`);
|
|
3228
|
+
}
|
|
3033
3229
|
return ok(result.value.token);
|
|
3034
3230
|
}
|
|
3231
|
+
log.warn(`Provider ${providerName} failed to generate token`);
|
|
3035
3232
|
}
|
|
3036
|
-
|
|
3233
|
+
log.warn(`All providers failed, generating cold start token`);
|
|
3234
|
+
const coldToken = generateColdStartToken(identifier);
|
|
3235
|
+
log.info(`Cold start token generated (length: ${coldToken.length})`);
|
|
3236
|
+
return ok(coldToken);
|
|
3037
3237
|
}
|
|
3038
3238
|
async getTokenData(identifier, client = "WEB", binding) {
|
|
3039
3239
|
if (this.staticToken) return ok({
|