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.mjs CHANGED
@@ -1,5 +1,43 @@
1
1
  // src/index.ts
2
+ import { createHmac, timingSafeEqual } from "crypto";
2
3
  import axios from "axios";
4
+ function normalizeContentsJobResponse(api) {
5
+ return {
6
+ success: api.success ?? true,
7
+ jobId: api.job_id ?? api.jobId,
8
+ status: api.status ?? "pending",
9
+ urlsTotal: api.urls_total ?? api.urlsTotal ?? 0,
10
+ urlsProcessed: api.urls_processed ?? api.urlsProcessed ?? 0,
11
+ urlsFailed: api.urls_failed ?? api.urlsFailed ?? 0,
12
+ createdAt: api.created_at ?? api.createdAt ?? 0,
13
+ updatedAt: api.updated_at ?? api.updatedAt ?? 0,
14
+ currentBatch: api.current_batch ?? api.currentBatch,
15
+ totalBatches: api.total_batches ?? api.totalBatches,
16
+ results: api.results,
17
+ actualCostDollars: api.actual_cost_dollars ?? api.actualCostDollars,
18
+ error: api.error,
19
+ webhookSecret: api.webhook_secret ?? api.webhookSecret
20
+ };
21
+ }
22
+ function normalizeContentsAsyncJobResponse(api) {
23
+ return {
24
+ success: api.success ?? true,
25
+ jobId: api.job_id ?? api.jobId,
26
+ status: "pending",
27
+ urlsTotal: api.urls_total ?? api.urlsTotal ?? 0,
28
+ webhookSecret: api.webhook_secret ?? api.webhookSecret,
29
+ txId: api.tx_id ?? api.txId ?? ""
30
+ };
31
+ }
32
+ function verifyContentsWebhookSignature(payload, signature, timestamp, secret) {
33
+ const expected = createHmac("sha256", secret).update(`${timestamp}.${payload}`).digest("hex");
34
+ const expectedSignature = `sha256=${expected}`;
35
+ if (signature.length !== expectedSignature.length) return false;
36
+ return timingSafeEqual(
37
+ Buffer.from(signature, "utf8"),
38
+ Buffer.from(expectedSignature, "utf8")
39
+ );
40
+ }
3
41
  var Valyu = class {
4
42
  constructor(apiKey, baseUrl = "https://api.valyu.ai/v1") {
5
43
  if (!apiKey) {
@@ -265,6 +303,9 @@ var Valyu = class {
265
303
  if (options.excludeSources !== void 0) {
266
304
  payload.exclude_sources = options.excludeSources;
267
305
  }
306
+ if (options.sourceBiases !== void 0) {
307
+ payload.source_biases = options.sourceBiases;
308
+ }
268
309
  if (options.category !== void 0) {
269
310
  payload.category = options.category;
270
311
  }
@@ -317,14 +358,16 @@ var Valyu = class {
317
358
  }
318
359
  /**
319
360
  * Extract content from URLs with optional AI processing
320
- * @param urls - Array of URLs to process (max 10)
361
+ * @param urls - Array of URLs to process (max 10 sync, max 50 with async: true)
321
362
  * @param options - Content extraction configuration options
322
363
  * @param options.summary - AI summary configuration: false (raw), true (auto), string (custom), or JSON schema
323
364
  * @param options.extractEffort - Extraction thoroughness: "normal", "high", or "auto"
324
365
  * @param options.responseLength - Content length per URL
325
366
  * @param options.maxPriceDollars - Maximum cost limit in USD
326
367
  * @param options.screenshot - Request page screenshots (default: false)
327
- * @returns Promise resolving to content extraction results
368
+ * @param options.async - Force async processing (required for >10 URLs)
369
+ * @param options.webhookUrl - HTTPS URL for completion notification (async only)
370
+ * @returns Promise resolving to sync results or async job (when async: true or >10 URLs)
328
371
  */
329
372
  async contents(urls, options = {}) {
330
373
  try {
@@ -352,10 +395,23 @@ var Valyu = class {
352
395
  total_characters: 0
353
396
  };
354
397
  }
355
- if (urls.length > 10) {
398
+ const isAsync = options.async === true || urls.length > 10;
399
+ if (urls.length > 10 && !options.async) {
400
+ return {
401
+ success: false,
402
+ error: "Requests with more than 10 URLs require async processing. Add async: true to the request.",
403
+ urls_requested: urls.length,
404
+ urls_processed: 0,
405
+ urls_failed: urls.length,
406
+ results: [],
407
+ total_cost_dollars: 0,
408
+ total_characters: 0
409
+ };
410
+ }
411
+ if (urls.length > 50) {
356
412
  return {
357
413
  success: false,
358
- error: "Maximum 10 URLs allowed per request",
414
+ error: "Maximum 50 URLs allowed per request",
359
415
  urls_requested: urls.length,
360
416
  urls_processed: 0,
361
417
  urls_failed: urls.length,
@@ -421,6 +477,12 @@ var Valyu = class {
421
477
  if (options.screenshot !== void 0) {
422
478
  payload.screenshot = options.screenshot;
423
479
  }
480
+ if (isAsync) {
481
+ payload.async = true;
482
+ }
483
+ if (options.webhookUrl !== void 0) {
484
+ payload.webhook_url = options.webhookUrl;
485
+ }
424
486
  const response = await axios.post(`${this.baseUrl}/contents`, payload, {
425
487
  headers: this.headers
426
488
  });
@@ -436,6 +498,9 @@ var Valyu = class {
436
498
  total_characters: 0
437
499
  };
438
500
  }
501
+ if (response.status === 202) {
502
+ return normalizeContentsAsyncJobResponse(response.data);
503
+ }
439
504
  return response.data;
440
505
  } catch (e) {
441
506
  return {
@@ -450,6 +515,61 @@ var Valyu = class {
450
515
  };
451
516
  }
452
517
  }
518
+ /**
519
+ * Get async Contents job status and results
520
+ * @param jobId - Job ID from contents() async response
521
+ * @returns Promise resolving to job status
522
+ */
523
+ async getContentsJob(jobId) {
524
+ try {
525
+ const response = await axios.get(
526
+ `${this.baseUrl}/contents/jobs/${jobId}`,
527
+ { headers: this.headers }
528
+ );
529
+ return normalizeContentsJobResponse(response.data);
530
+ } catch (e) {
531
+ const errData = e.response?.data;
532
+ const status = e.response?.status;
533
+ return {
534
+ success: false,
535
+ jobId,
536
+ status: "failed",
537
+ urlsTotal: 0,
538
+ urlsProcessed: 0,
539
+ urlsFailed: 0,
540
+ createdAt: 0,
541
+ updatedAt: 0,
542
+ error: errData?.error || (status === 403 ? "Forbidden - you do not have access to this job" : status === 404 ? `Job ${jobId} not found` : e.message)
543
+ };
544
+ }
545
+ }
546
+ /**
547
+ * Wait for async Contents job completion (polls until terminal state)
548
+ * @param jobId - Job ID from contents() async response
549
+ * @param options - Wait configuration (pollInterval, maxWaitTime, onProgress)
550
+ * @returns Promise resolving to final job status with results
551
+ */
552
+ async waitForJob(jobId, options = {}) {
553
+ const pollInterval = options.pollInterval ?? 5e3;
554
+ const maxWaitTime = options.maxWaitTime ?? 72e5;
555
+ const startTime = Date.now();
556
+ while (true) {
557
+ const status = await this.getContentsJob(jobId);
558
+ if (!status.success && status.error) {
559
+ throw new Error(status.error);
560
+ }
561
+ if (options.onProgress) {
562
+ options.onProgress(status);
563
+ }
564
+ if (status.status === "completed" || status.status === "partial" || status.status === "failed") {
565
+ return status;
566
+ }
567
+ if (Date.now() - startTime > maxWaitTime) {
568
+ throw new Error("Maximum wait time exceeded");
569
+ }
570
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
571
+ }
572
+ }
453
573
  /**
454
574
  * DeepResearch: Create a new research task
455
575
  * @param options.search - Search configuration options
@@ -478,6 +598,10 @@ var Valyu = class {
478
598
  code_execution: options.codeExecution !== false
479
599
  };
480
600
  if (options.strategy) payload.strategy = options.strategy;
601
+ if (options.researchStrategy)
602
+ payload.research_strategy = options.researchStrategy;
603
+ if (options.reportFormat)
604
+ payload.report_format = options.reportFormat;
481
605
  if (options.search) {
482
606
  payload.search = {};
483
607
  if (options.search.searchType) {
@@ -489,6 +613,9 @@ var Valyu = class {
489
613
  if (options.search.excludedSources) {
490
614
  payload.search.excluded_sources = options.search.excludedSources;
491
615
  }
616
+ if (options.search.sourceBiases) {
617
+ payload.search.source_biases = options.search.sourceBiases;
618
+ }
492
619
  if (options.search.startDate) {
493
620
  payload.search.start_date = options.search.startDate;
494
621
  }
@@ -785,6 +912,9 @@ var Valyu = class {
785
912
  if (options.search.excludedSources) {
786
913
  payload.search.excluded_sources = options.search.excludedSources;
787
914
  }
915
+ if (options.search.sourceBiases) {
916
+ payload.search.source_biases = options.search.sourceBiases;
917
+ }
788
918
  if (options.search.startDate) {
789
919
  payload.search.start_date = options.search.startDate;
790
920
  }
@@ -872,6 +1002,10 @@ var Valyu = class {
872
1002
  }
873
1003
  if (task.id) taskPayload.id = task.id;
874
1004
  if (task.strategy) taskPayload.strategy = task.strategy;
1005
+ if (task.researchStrategy)
1006
+ taskPayload.research_strategy = task.researchStrategy;
1007
+ if (task.reportFormat)
1008
+ taskPayload.report_format = task.reportFormat;
875
1009
  if (task.urls) taskPayload.urls = task.urls;
876
1010
  if (task.metadata) taskPayload.metadata = task.metadata;
877
1011
  return taskPayload;
@@ -1342,6 +1476,7 @@ var Valyu = class {
1342
1476
  }
1343
1477
  };
1344
1478
  export {
1345
- Valyu
1479
+ Valyu,
1480
+ verifyContentsWebhookSignature
1346
1481
  };
1347
1482
  //# sourceMappingURL=index.mjs.map