valyu-js 2.5.8 → 2.6.0

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.js CHANGED
@@ -30,10 +30,49 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
- Valyu: () => Valyu
33
+ Valyu: () => Valyu,
34
+ verifyContentsWebhookSignature: () => verifyContentsWebhookSignature
34
35
  });
35
36
  module.exports = __toCommonJS(index_exports);
37
+ var import_crypto = require("crypto");
36
38
  var import_axios = __toESM(require("axios"));
39
+ function normalizeContentsJobResponse(api) {
40
+ return {
41
+ success: api.success ?? true,
42
+ jobId: api.job_id ?? api.jobId,
43
+ status: api.status ?? "pending",
44
+ urlsTotal: api.urls_total ?? api.urlsTotal ?? 0,
45
+ urlsProcessed: api.urls_processed ?? api.urlsProcessed ?? 0,
46
+ urlsFailed: api.urls_failed ?? api.urlsFailed ?? 0,
47
+ createdAt: api.created_at ?? api.createdAt ?? 0,
48
+ updatedAt: api.updated_at ?? api.updatedAt ?? 0,
49
+ currentBatch: api.current_batch ?? api.currentBatch,
50
+ totalBatches: api.total_batches ?? api.totalBatches,
51
+ results: api.results,
52
+ actualCostDollars: api.actual_cost_dollars ?? api.actualCostDollars,
53
+ error: api.error,
54
+ webhookSecret: api.webhook_secret ?? api.webhookSecret
55
+ };
56
+ }
57
+ function normalizeContentsAsyncJobResponse(api) {
58
+ return {
59
+ success: api.success ?? true,
60
+ jobId: api.job_id ?? api.jobId,
61
+ status: "pending",
62
+ urlsTotal: api.urls_total ?? api.urlsTotal ?? 0,
63
+ webhookSecret: api.webhook_secret ?? api.webhookSecret,
64
+ txId: api.tx_id ?? api.txId ?? ""
65
+ };
66
+ }
67
+ function verifyContentsWebhookSignature(payload, signature, timestamp, secret) {
68
+ const expected = (0, import_crypto.createHmac)("sha256", secret).update(`${timestamp}.${payload}`).digest("hex");
69
+ const expectedSignature = `sha256=${expected}`;
70
+ if (signature.length !== expectedSignature.length) return false;
71
+ return (0, import_crypto.timingSafeEqual)(
72
+ Buffer.from(signature, "utf8"),
73
+ Buffer.from(expectedSignature, "utf8")
74
+ );
75
+ }
37
76
  var Valyu = class {
38
77
  constructor(apiKey, baseUrl = "https://api.valyu.ai/v1") {
39
78
  if (!apiKey) {
@@ -299,6 +338,9 @@ var Valyu = class {
299
338
  if (options.excludeSources !== void 0) {
300
339
  payload.exclude_sources = options.excludeSources;
301
340
  }
341
+ if (options.sourceBiases !== void 0) {
342
+ payload.source_biases = options.sourceBiases;
343
+ }
302
344
  if (options.category !== void 0) {
303
345
  payload.category = options.category;
304
346
  }
@@ -351,14 +393,16 @@ var Valyu = class {
351
393
  }
352
394
  /**
353
395
  * Extract content from URLs with optional AI processing
354
- * @param urls - Array of URLs to process (max 10)
396
+ * @param urls - Array of URLs to process (max 10 sync, max 50 with async: true)
355
397
  * @param options - Content extraction configuration options
356
398
  * @param options.summary - AI summary configuration: false (raw), true (auto), string (custom), or JSON schema
357
399
  * @param options.extractEffort - Extraction thoroughness: "normal", "high", or "auto"
358
400
  * @param options.responseLength - Content length per URL
359
401
  * @param options.maxPriceDollars - Maximum cost limit in USD
360
402
  * @param options.screenshot - Request page screenshots (default: false)
361
- * @returns Promise resolving to content extraction results
403
+ * @param options.async - Force async processing (required for >10 URLs)
404
+ * @param options.webhookUrl - HTTPS URL for completion notification (async only)
405
+ * @returns Promise resolving to sync results or async job (when async: true or >10 URLs)
362
406
  */
363
407
  async contents(urls, options = {}) {
364
408
  try {
@@ -386,10 +430,23 @@ var Valyu = class {
386
430
  total_characters: 0
387
431
  };
388
432
  }
389
- if (urls.length > 10) {
433
+ const isAsync = options.async === true || urls.length > 10;
434
+ if (urls.length > 10 && !options.async) {
435
+ return {
436
+ success: false,
437
+ error: "Requests with more than 10 URLs require async processing. Add async: true to the request.",
438
+ urls_requested: urls.length,
439
+ urls_processed: 0,
440
+ urls_failed: urls.length,
441
+ results: [],
442
+ total_cost_dollars: 0,
443
+ total_characters: 0
444
+ };
445
+ }
446
+ if (urls.length > 50) {
390
447
  return {
391
448
  success: false,
392
- error: "Maximum 10 URLs allowed per request",
449
+ error: "Maximum 50 URLs allowed per request",
393
450
  urls_requested: urls.length,
394
451
  urls_processed: 0,
395
452
  urls_failed: urls.length,
@@ -455,6 +512,12 @@ var Valyu = class {
455
512
  if (options.screenshot !== void 0) {
456
513
  payload.screenshot = options.screenshot;
457
514
  }
515
+ if (isAsync) {
516
+ payload.async = true;
517
+ }
518
+ if (options.webhookUrl !== void 0) {
519
+ payload.webhook_url = options.webhookUrl;
520
+ }
458
521
  const response = await import_axios.default.post(`${this.baseUrl}/contents`, payload, {
459
522
  headers: this.headers
460
523
  });
@@ -470,6 +533,9 @@ var Valyu = class {
470
533
  total_characters: 0
471
534
  };
472
535
  }
536
+ if (response.status === 202) {
537
+ return normalizeContentsAsyncJobResponse(response.data);
538
+ }
473
539
  return response.data;
474
540
  } catch (e) {
475
541
  return {
@@ -484,6 +550,61 @@ var Valyu = class {
484
550
  };
485
551
  }
486
552
  }
553
+ /**
554
+ * Get async Contents job status and results
555
+ * @param jobId - Job ID from contents() async response
556
+ * @returns Promise resolving to job status
557
+ */
558
+ async getContentsJob(jobId) {
559
+ try {
560
+ const response = await import_axios.default.get(
561
+ `${this.baseUrl}/contents/jobs/${jobId}`,
562
+ { headers: this.headers }
563
+ );
564
+ return normalizeContentsJobResponse(response.data);
565
+ } catch (e) {
566
+ const errData = e.response?.data;
567
+ const status = e.response?.status;
568
+ return {
569
+ success: false,
570
+ jobId,
571
+ status: "failed",
572
+ urlsTotal: 0,
573
+ urlsProcessed: 0,
574
+ urlsFailed: 0,
575
+ createdAt: 0,
576
+ updatedAt: 0,
577
+ error: errData?.error || (status === 403 ? "Forbidden - you do not have access to this job" : status === 404 ? `Job ${jobId} not found` : e.message)
578
+ };
579
+ }
580
+ }
581
+ /**
582
+ * Wait for async Contents job completion (polls until terminal state)
583
+ * @param jobId - Job ID from contents() async response
584
+ * @param options - Wait configuration (pollInterval, maxWaitTime, onProgress)
585
+ * @returns Promise resolving to final job status with results
586
+ */
587
+ async waitForJob(jobId, options = {}) {
588
+ const pollInterval = options.pollInterval ?? 5e3;
589
+ const maxWaitTime = options.maxWaitTime ?? 72e5;
590
+ const startTime = Date.now();
591
+ while (true) {
592
+ const status = await this.getContentsJob(jobId);
593
+ if (!status.success && status.error) {
594
+ throw new Error(status.error);
595
+ }
596
+ if (options.onProgress) {
597
+ options.onProgress(status);
598
+ }
599
+ if (status.status === "completed" || status.status === "partial" || status.status === "failed") {
600
+ return status;
601
+ }
602
+ if (Date.now() - startTime > maxWaitTime) {
603
+ throw new Error("Maximum wait time exceeded");
604
+ }
605
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
606
+ }
607
+ }
487
608
  /**
488
609
  * DeepResearch: Create a new research task
489
610
  * @param options.search - Search configuration options
@@ -512,6 +633,10 @@ var Valyu = class {
512
633
  code_execution: options.codeExecution !== false
513
634
  };
514
635
  if (options.strategy) payload.strategy = options.strategy;
636
+ if (options.researchStrategy)
637
+ payload.research_strategy = options.researchStrategy;
638
+ if (options.reportFormat)
639
+ payload.report_format = options.reportFormat;
515
640
  if (options.search) {
516
641
  payload.search = {};
517
642
  if (options.search.searchType) {
@@ -523,6 +648,9 @@ var Valyu = class {
523
648
  if (options.search.excludedSources) {
524
649
  payload.search.excluded_sources = options.search.excludedSources;
525
650
  }
651
+ if (options.search.sourceBiases) {
652
+ payload.search.source_biases = options.search.sourceBiases;
653
+ }
526
654
  if (options.search.startDate) {
527
655
  payload.search.start_date = options.search.startDate;
528
656
  }
@@ -819,6 +947,9 @@ var Valyu = class {
819
947
  if (options.search.excludedSources) {
820
948
  payload.search.excluded_sources = options.search.excludedSources;
821
949
  }
950
+ if (options.search.sourceBiases) {
951
+ payload.search.source_biases = options.search.sourceBiases;
952
+ }
822
953
  if (options.search.startDate) {
823
954
  payload.search.start_date = options.search.startDate;
824
955
  }
@@ -906,6 +1037,10 @@ var Valyu = class {
906
1037
  }
907
1038
  if (task.id) taskPayload.id = task.id;
908
1039
  if (task.strategy) taskPayload.strategy = task.strategy;
1040
+ if (task.researchStrategy)
1041
+ taskPayload.research_strategy = task.researchStrategy;
1042
+ if (task.reportFormat)
1043
+ taskPayload.report_format = task.reportFormat;
909
1044
  if (task.urls) taskPayload.urls = task.urls;
910
1045
  if (task.metadata) taskPayload.metadata = task.metadata;
911
1046
  return taskPayload;
@@ -1377,6 +1512,7 @@ var Valyu = class {
1377
1512
  };
1378
1513
  // Annotate the CommonJS export names for ESM import in node:
1379
1514
  0 && (module.exports = {
1380
- Valyu
1515
+ Valyu,
1516
+ verifyContentsWebhookSignature
1381
1517
  });
1382
1518
  //# sourceMappingURL=index.js.map