@signaliz/sdk 1.0.29 → 1.0.31

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.
@@ -384,89 +384,51 @@ var Signaliz = class {
384
384
  this.client = new HttpClient(config);
385
385
  }
386
386
  async findEmail(params) {
387
- const data = await this.client.post("api/v1/find-email", compact({
388
- company_domain: params.companyDomain,
389
- full_name: params.fullName,
390
- first_name: params.firstName,
391
- last_name: params.lastName,
392
- linkedin_url: params.linkedinUrl,
393
- company_name: params.companyName,
394
- skip_cache: params.skipCache
395
- }));
396
- const email = typeof data.email === "string" && data.email.trim() ? data.email.trim() : null;
397
- const found = Boolean(email) && data.found !== false;
398
- const verificationStatus = data.verification_status ?? data.status ?? "unknown";
399
- const rawFreshness = String(data.verification_freshness ?? "").toLowerCase();
400
- const verificationFreshness = rawFreshness === "fresh" || rawFreshness === "stale" ? rawFreshness : "unknown";
401
- const needsReverification = data.needs_reverification === true || verificationFreshness === "stale";
402
- const explicitlyNotSendSafe = data.verified_for_sending === false || needsReverification;
403
- const verified = !explicitlyNotSendSafe && (data.email_verified === true || data.verified_for_sending === true || ["valid", "deliverable"].includes(String(verificationStatus).toLowerCase()));
404
- const verificationAgeDays = typeof data.verification_age_days === "number" && Number.isFinite(data.verification_age_days) ? data.verification_age_days : null;
405
- return {
406
- success: data.success !== false && found,
407
- found,
408
- email,
409
- firstName: data.first_name,
410
- lastName: data.last_name,
411
- confidence: data.confidence ?? data.confidence_score ?? (verified ? 1 : 0),
412
- verificationStatus,
413
- isVerified: verified,
414
- isVerifiedForSending: !needsReverification && data.verified_for_sending === true,
415
- isCatchAll: data.email_is_catch_all === true || data.is_catch_all === true,
416
- verificationFreshness,
417
- verificationAgeDays,
418
- verifiedAt: typeof data.verified_at === "string" ? data.verified_at : null,
419
- needsReverification,
420
- providerUsed: data.provider_used ?? data.provider ?? data.email_source ?? data.source ?? "unknown",
421
- error: found ? void 0 : data.error ?? "No verified email found",
422
- errorCode: found ? void 0 : data.error_code ?? "EMAIL_NOT_FOUND",
423
- raw: data
424
- };
387
+ const data = await this.client.post("api/v1/find-email", findEmailRequestBody(params));
388
+ return normalizeFindEmailResult(data);
425
389
  }
426
390
  async findEmails(params, options) {
427
- return runBatch(params, (item) => this.findEmail(item), options);
391
+ validateBatchSize(params);
392
+ const startedAt = Date.now();
393
+ const round = await this.runCoreBatchRound(
394
+ "api/v1/find-email",
395
+ params.map((item, index) => ({ index, request: findEmailRequestBody(item) })),
396
+ options
397
+ );
398
+ return finalizeCoreBatch(
399
+ params.length,
400
+ startedAt,
401
+ round,
402
+ (item) => normalizeFindEmailResult(item.raw)
403
+ );
428
404
  }
429
405
  async verifyEmail(email, options) {
430
406
  const data = await this.client.post("api/v1/verify-email", {
431
407
  email,
432
408
  skip_cache: options?.skipCache
433
409
  });
434
- const verificationStatus = String(data.verification_status ?? "").toLowerCase();
435
- const verified = data.email_verified === true || ["valid", "deliverable"].includes(verificationStatus);
436
- return {
437
- email: data.email ?? email,
438
- isValid: data.is_valid ?? data.valid ?? verified,
439
- isDeliverable: data.is_deliverable ?? data.deliverable ?? verified,
440
- isCatchAll: data.is_catch_all ?? data.catch_all ?? data.diagnostics?.is_catch_all ?? false,
441
- confidenceScore: data.confidence_score ?? data.confidence ?? data.diagnostics?.confidence_score ?? (verified ? 1 : 0),
442
- provider: data.provider,
443
- verificationSource: data.verification_source,
444
- raw: data
445
- };
410
+ return normalizeVerifyEmailResult(email, data);
446
411
  }
447
412
  async verifyEmails(emails, options) {
448
- return runBatch(emails, (email) => this.verifyEmail(email, { skipCache: options?.skipCache }), options);
413
+ validateBatchSize(emails);
414
+ const startedAt = Date.now();
415
+ const round = await this.runCoreBatchRound(
416
+ "api/v1/verify-email",
417
+ emails.map((email, index) => ({
418
+ index,
419
+ request: { email, skip_cache: options?.skipCache }
420
+ })),
421
+ options
422
+ );
423
+ return finalizeCoreBatch(
424
+ emails.length,
425
+ startedAt,
426
+ round,
427
+ (item) => normalizeVerifyEmailResult(emails[item.index], item.raw)
428
+ );
449
429
  }
450
430
  async enrichCompanySignals(params) {
451
- const online = params.online ?? true;
452
- const request = compact({
453
- signal_run_id: params.signalRunId,
454
- company_domain: params.companyDomain,
455
- company_name: params.companyName,
456
- research_prompt: params.researchPrompt,
457
- signal_types: params.signalTypes,
458
- target_signal_count: params.targetSignalCount,
459
- lookback_days: params.lookbackDays,
460
- online,
461
- enable_deep_search: params.enableDeepSearch ?? online,
462
- enable_outreach_intelligence: params.enableOutreachIntelligence,
463
- enable_predictive_intelligence: params.enablePredictiveIntelligence,
464
- skip_cache: params.skipCache,
465
- // REST always returns a resumable run instead of holding the connection;
466
- // waitForResult controls this SDK's polling loop below.
467
- wait_for_result: false,
468
- max_wait_ms: params.maxWaitMs
469
- });
431
+ const request = companySignalRequestBody(params);
470
432
  let data = await this.client.post("api/v1/company-signals", request);
471
433
  if (params.waitForResult !== false && data.run_id && isPendingSignalResponse(data)) {
472
434
  const maxWaitMs = Math.max(1e3, params.maxWaitMs ?? 20 * 6e4);
@@ -494,47 +456,68 @@ var Signaliz = class {
494
456
  throw new Error(`Company signal enrichment ${data.run_id} did not complete within ${maxWaitMs}ms`);
495
457
  }
496
458
  }
497
- return {
498
- success: data.success ?? true,
499
- status: data.status,
500
- signalRunId: data.signal_run_id ?? data.run_id,
501
- company: {
502
- name: data.company?.name ?? params.companyName ?? null,
503
- domain: data.company?.domain ?? params.companyDomain ?? null
504
- },
505
- signals: (data.signals ?? []).map((signal) => {
506
- const metadata = signal.metadata && typeof signal.metadata === "object" && !Array.isArray(signal.metadata) ? signal.metadata : void 0;
507
- return {
508
- id: signal.id,
509
- title: signal.title ?? "",
510
- type: signal.type ?? signal.signal_type ?? "unknown",
511
- content: signal.content ?? signal.description ?? "",
512
- date: signal.date ?? signal.detected_at ?? null,
513
- datePrecision: signal.date_precision,
514
- sourceUrl: signal.source_url ?? signal.url ?? null,
515
- sourceType: signal.source_type,
516
- sourceProvenance: signal.source_provenance,
517
- confidence: signal.confidence ?? signal.confidence_score ?? null,
518
- entityConfidence: signal.entity_confidence ?? metadata?.entity_confidence ?? null,
519
- signalFamily: signal.signal_family,
520
- eventType: signal.signal_event_type,
521
- eventLabel: signal.signal_event_label,
522
- classification: signal.signal_classification ?? null,
523
- derived: signal.derived === true,
524
- evidencePublishedDate: signal.evidence_published_date ?? metadata?.evidence_published_date ?? null,
525
- signalFeedSource: signal.signal_feed_source ?? metadata?.signal_feed_source,
526
- metadata
527
- };
528
- }),
529
- signalCount: data.signal_count ?? data.total_signals ?? data.signals?.length ?? 0,
530
- intelligence: data.intelligence ?? null,
531
- credits: data.credits,
532
- metadata: data.metadata,
533
- raw: data
534
- };
459
+ return normalizeCompanySignalResult(params, data);
535
460
  }
536
461
  async enrichCompanies(companies, options) {
537
- return runBatch(companies, (company) => this.enrichCompanySignals(company), options);
462
+ validateBatchSize(companies);
463
+ const startedAt = Date.now();
464
+ const results = new Array(companies.length);
465
+ let pending = companies.map((params, index) => ({
466
+ index,
467
+ request: companySignalRequestBody(params)
468
+ }));
469
+ while (pending.length > 0) {
470
+ const round = await this.runCoreBatchRound("api/v1/company-signals", pending, options);
471
+ const taskByIndex = new Map(pending.map((task) => [task.index, task]));
472
+ const nextPending = [];
473
+ let nextDelayMs = 6e4;
474
+ for (const item of round) {
475
+ const params = companies[item.index];
476
+ const task = taskByIndex.get(item.index);
477
+ if (!item.success || !item.raw) {
478
+ results[item.index] = { index: item.index, success: false, error: item.error || "Company Signal batch request failed" };
479
+ continue;
480
+ }
481
+ if (!isPendingSignalResponse(item.raw) || params.waitForResult === false) {
482
+ results[item.index] = { index: item.index, success: true, data: normalizeCompanySignalResult(params, item.raw) };
483
+ continue;
484
+ }
485
+ const maxWaitMs = Math.max(1e3, params.maxWaitMs ?? 20 * 6e4);
486
+ if (Date.now() - startedAt >= maxWaitMs) {
487
+ results[item.index] = {
488
+ index: item.index,
489
+ success: false,
490
+ error: `Company signal enrichment ${item.raw.signal_run_id || item.raw.run_id || ""} did not complete within ${maxWaitMs}ms`
491
+ };
492
+ continue;
493
+ }
494
+ const signalRunId = item.raw.signal_run_id || item.raw.run_id;
495
+ if (!signalRunId) {
496
+ results[item.index] = { index: item.index, success: false, error: "Company signal enrichment is processing without a signal_run_id" };
497
+ continue;
498
+ }
499
+ nextDelayMs = Math.min(
500
+ nextDelayMs,
501
+ signalPollDelayMs(item.raw, params.pollIntervalMs),
502
+ maxWaitMs - (Date.now() - startedAt)
503
+ );
504
+ nextPending.push({
505
+ ...task,
506
+ request: { ...task.request, signal_run_id: signalRunId }
507
+ });
508
+ }
509
+ if (nextPending.length === 0) break;
510
+ await sleep2(Math.max(1, nextDelayMs));
511
+ pending = nextPending;
512
+ }
513
+ const succeeded = results.filter((item) => item.success).length;
514
+ return {
515
+ total: companies.length,
516
+ succeeded,
517
+ failed: companies.length - succeeded,
518
+ durationMs: Date.now() - startedAt,
519
+ results
520
+ };
538
521
  }
539
522
  async signalToCopy(params) {
540
523
  const request = signalToCopyRequestBody(params);
@@ -557,29 +540,31 @@ var Signaliz = class {
557
540
  return normalizeSignalToCopyResult(data);
558
541
  }
559
542
  async createSignalCopyBatch(requests, options) {
560
- if (!Array.isArray(requests) || requests.length === 0) {
561
- throw new Error("Signaliz batch requests require at least one item");
562
- }
563
- if (requests.length > 5e3) {
564
- throw new Error(`Signaliz batch requests support at most 5,000 items; received ${requests.length}`);
565
- }
543
+ validateBatchSize(requests);
566
544
  const startedAt = Date.now();
545
+ const deduplicated = dedupeExactBatchItems(requests, (params) => JSON.stringify({
546
+ request: signalToCopyRequestBody(params),
547
+ wait_for_result: params.waitForResult,
548
+ max_wait_ms: params.maxWaitMs,
549
+ poll_interval_ms: params.pollIntervalMs
550
+ }));
551
+ const uniqueRequests = deduplicated.uniqueItems;
567
552
  const chunks = [];
568
- for (let offset = 0; offset < requests.length; offset += 25) {
569
- chunks.push({ offset, requests: requests.slice(offset, offset + 25) });
553
+ for (let offset = 0; offset < uniqueRequests.length; offset += 25) {
554
+ chunks.push({ offset, requests: uniqueRequests.slice(offset, offset + 25) });
570
555
  }
571
- const serverConcurrency = Math.min(10, options?.concurrency ?? 10);
556
+ const { serverConcurrency, chunkConcurrency } = batchConcurrencyPlan(options);
572
557
  const chunkBatch = await runBatch(
573
558
  chunks,
574
559
  (chunk) => this.runSignalCopyBatchChunk(chunk.requests, serverConcurrency),
575
- options
560
+ { concurrency: chunkConcurrency }
576
561
  );
577
- const results = new Array(requests.length);
562
+ const uniqueResults = new Array(uniqueRequests.length);
578
563
  for (const chunkResult of chunkBatch.results) {
579
564
  const chunk = chunks[chunkResult.index];
580
565
  if (!chunkResult.success || !chunkResult.data) {
581
566
  for (let index = 0; index < chunk.requests.length; index += 1) {
582
- results[chunk.offset + index] = {
567
+ uniqueResults[chunk.offset + index] = {
583
568
  index: chunk.offset + index,
584
569
  success: false,
585
570
  error: chunkResult.error || "Signal to Copy batch request failed"
@@ -588,9 +573,13 @@ var Signaliz = class {
588
573
  continue;
589
574
  }
590
575
  for (const item of chunkResult.data) {
591
- results[chunk.offset + item.index] = { ...item, index: chunk.offset + item.index };
576
+ uniqueResults[chunk.offset + item.index] = { ...item, index: chunk.offset + item.index };
592
577
  }
593
578
  }
579
+ const results = requests.map((_, index) => ({
580
+ ...uniqueResults[deduplicated.sourceIndexByInput[index]],
581
+ index
582
+ }));
594
583
  const succeeded = results.filter((item) => item.success).length;
595
584
  return {
596
585
  total: requests.length,
@@ -662,6 +651,55 @@ var Signaliz = class {
662
651
  }
663
652
  return results;
664
653
  }
654
+ async runCoreBatchRound(path2, tasks, options) {
655
+ const { serverConcurrency, chunkConcurrency } = batchConcurrencyPlan(options);
656
+ const deduplicated = dedupeExactBatchItems(tasks, (task) => JSON.stringify(task.request));
657
+ const uniqueTasks = deduplicated.uniqueItems;
658
+ const chunks = [];
659
+ for (let offset = 0; offset < uniqueTasks.length; offset += 25) {
660
+ chunks.push({ offset, tasks: uniqueTasks.slice(offset, offset + 25) });
661
+ }
662
+ const chunkBatch = await runBatch(chunks, async (chunk) => {
663
+ const data = await this.client.post(path2, {
664
+ requests: chunk.tasks.map((task) => task.request),
665
+ concurrency: serverConcurrency
666
+ });
667
+ if (!Array.isArray(data.results) || data.results.length !== chunk.tasks.length) {
668
+ throw new Error(`${path2} batch returned an invalid result count`);
669
+ }
670
+ if (data.results.some((row, index) => row.index !== index)) {
671
+ throw new Error(`${path2} batch returned results out of order`);
672
+ }
673
+ return data.results;
674
+ }, { concurrency: chunkConcurrency });
675
+ const uniqueResults = new Array(uniqueTasks.length);
676
+ for (const chunkResult of chunkBatch.results) {
677
+ const chunk = chunks[chunkResult.index];
678
+ if (!chunkResult.success || !chunkResult.data) {
679
+ for (let index = 0; index < chunk.tasks.length; index += 1) {
680
+ uniqueResults[chunk.offset + index] = {
681
+ index: chunk.tasks[index].index,
682
+ success: false,
683
+ error: chunkResult.error || `${path2} batch request failed`
684
+ };
685
+ }
686
+ continue;
687
+ }
688
+ for (let index = 0; index < chunkResult.data.length; index += 1) {
689
+ const raw = chunkResult.data[index];
690
+ uniqueResults[chunk.offset + index] = {
691
+ index: chunk.tasks[index].index,
692
+ success: raw.success !== false,
693
+ raw,
694
+ error: raw.success === false ? raw.error || raw.message || raw.error_code || `${path2} item failed` : void 0
695
+ };
696
+ }
697
+ }
698
+ return tasks.map((task, index) => ({
699
+ ...uniqueResults[deduplicated.sourceIndexByInput[index]],
700
+ index: task.index
701
+ }));
702
+ }
665
703
  async listTools() {
666
704
  const result = await this.client.mcp("tools/list");
667
705
  return result.tools ?? [];
@@ -677,6 +715,188 @@ var Signaliz = class {
677
715
  function compact(input) {
678
716
  return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== void 0));
679
717
  }
718
+ function findEmailRequestBody(params) {
719
+ return compact({
720
+ company_domain: params.companyDomain,
721
+ full_name: params.fullName,
722
+ first_name: params.firstName,
723
+ last_name: params.lastName,
724
+ linkedin_url: params.linkedinUrl,
725
+ company_name: params.companyName,
726
+ skip_cache: params.skipCache
727
+ });
728
+ }
729
+ function normalizeFindEmailResult(data) {
730
+ const email = typeof data.email === "string" && data.email.trim() ? data.email.trim() : null;
731
+ const found = Boolean(email) && data.found !== false;
732
+ const verificationStatus = data.verification_status ?? data.status ?? "unknown";
733
+ const rawFreshness = String(data.verification_freshness ?? "").toLowerCase();
734
+ const verificationFreshness = rawFreshness === "fresh" || rawFreshness === "stale" ? rawFreshness : "unknown";
735
+ const needsReverification = data.needs_reverification === true || verificationFreshness === "stale";
736
+ const explicitlyNotSendSafe = data.verified_for_sending === false || needsReverification;
737
+ const verified = !explicitlyNotSendSafe && (data.email_verified === true || data.verified_for_sending === true || ["valid", "deliverable"].includes(String(verificationStatus).toLowerCase()));
738
+ const verificationAgeDays = typeof data.verification_age_days === "number" && Number.isFinite(data.verification_age_days) ? data.verification_age_days : null;
739
+ return {
740
+ success: data.success !== false && found,
741
+ found,
742
+ email,
743
+ firstName: data.first_name,
744
+ lastName: data.last_name,
745
+ confidence: data.confidence ?? data.confidence_score ?? (verified ? 1 : 0),
746
+ verificationStatus,
747
+ isVerified: verified,
748
+ isVerifiedForSending: !needsReverification && data.verified_for_sending === true,
749
+ isCatchAll: data.email_is_catch_all === true || data.is_catch_all === true,
750
+ verificationFreshness,
751
+ verificationAgeDays,
752
+ verifiedAt: typeof data.verified_at === "string" ? data.verified_at : null,
753
+ needsReverification,
754
+ providerUsed: data.provider_used ?? data.provider ?? data.email_source ?? data.source ?? "unknown",
755
+ error: found ? void 0 : data.error ?? "No verified email found",
756
+ errorCode: found ? void 0 : data.error_code ?? "EMAIL_NOT_FOUND",
757
+ raw: data
758
+ };
759
+ }
760
+ function normalizeVerifyEmailResult(email, data) {
761
+ const verificationStatus = String(data.verification_status ?? "").toLowerCase();
762
+ const verified = data.email_verified === true || ["valid", "deliverable"].includes(verificationStatus);
763
+ return {
764
+ email: data.email ?? email,
765
+ isValid: data.is_valid ?? data.valid ?? verified,
766
+ isDeliverable: data.is_deliverable ?? data.deliverable ?? verified,
767
+ isCatchAll: data.email_is_catch_all ?? data.is_catch_all ?? data.catch_all ?? data.diagnostics?.is_catch_all ?? false,
768
+ confidenceScore: data.confidence_score ?? data.confidence ?? data.diagnostics?.confidence_score ?? (verified ? 1 : 0),
769
+ provider: data.provider,
770
+ verificationSource: data.verification_source,
771
+ raw: data
772
+ };
773
+ }
774
+ function companySignalRequestBody(params) {
775
+ const online = params.online ?? true;
776
+ return compact({
777
+ signal_run_id: params.signalRunId,
778
+ company_domain: params.companyDomain,
779
+ company_name: params.companyName,
780
+ research_prompt: params.researchPrompt,
781
+ signal_types: params.signalTypes,
782
+ target_signal_count: params.targetSignalCount,
783
+ lookback_days: params.lookbackDays,
784
+ online,
785
+ enable_deep_search: params.enableDeepSearch ?? online,
786
+ enable_outreach_intelligence: params.enableOutreachIntelligence,
787
+ enable_predictive_intelligence: params.enablePredictiveIntelligence,
788
+ skip_cache: params.skipCache,
789
+ // REST always returns a resumable run instead of holding the connection;
790
+ // waitForResult controls the SDK polling loop.
791
+ wait_for_result: false,
792
+ max_wait_ms: params.maxWaitMs
793
+ });
794
+ }
795
+ function normalizeCompanySignalResult(params, data) {
796
+ return {
797
+ success: data.success ?? true,
798
+ status: data.status,
799
+ signalRunId: data.signal_run_id ?? data.run_id,
800
+ company: {
801
+ name: data.company?.name ?? params.companyName ?? null,
802
+ domain: data.company?.domain ?? params.companyDomain ?? null
803
+ },
804
+ signals: (data.signals ?? []).map((signal) => {
805
+ const metadata = signal.metadata && typeof signal.metadata === "object" && !Array.isArray(signal.metadata) ? signal.metadata : void 0;
806
+ return {
807
+ id: signal.id,
808
+ title: signal.title ?? "",
809
+ type: signal.type ?? signal.signal_type ?? "unknown",
810
+ content: signal.content ?? signal.description ?? "",
811
+ date: signal.date ?? signal.detected_at ?? null,
812
+ datePrecision: signal.date_precision,
813
+ sourceUrl: signal.source_url ?? signal.url ?? null,
814
+ sourceType: signal.source_type,
815
+ sourceProvenance: signal.source_provenance,
816
+ confidence: signal.confidence ?? signal.confidence_score ?? null,
817
+ entityConfidence: signal.entity_confidence ?? metadata?.entity_confidence ?? null,
818
+ signalFamily: signal.signal_family,
819
+ eventType: signal.signal_event_type,
820
+ eventLabel: signal.signal_event_label,
821
+ classification: signal.signal_classification ?? null,
822
+ derived: signal.derived === true,
823
+ evidencePublishedDate: signal.evidence_published_date ?? metadata?.evidence_published_date ?? null,
824
+ signalFeedSource: signal.signal_feed_source ?? metadata?.signal_feed_source,
825
+ metadata
826
+ };
827
+ }),
828
+ signalCount: data.signal_count ?? data.total_signals ?? data.signals?.length ?? 0,
829
+ intelligence: data.intelligence ?? null,
830
+ credits: data.credits,
831
+ metadata: data.metadata,
832
+ raw: data
833
+ };
834
+ }
835
+ function validateBatchSize(items) {
836
+ if (!Array.isArray(items) || items.length === 0) {
837
+ throw new Error("Signaliz batch requests require at least one item");
838
+ }
839
+ if (items.length > 5e3) {
840
+ throw new Error(`Signaliz batch requests support at most 5,000 items; received ${items.length}`);
841
+ }
842
+ }
843
+ function validatedBatchConcurrency(options) {
844
+ const concurrency = options?.concurrency ?? 10;
845
+ if (!Number.isInteger(concurrency) || concurrency < 1 || concurrency > 50) {
846
+ throw new Error("Signaliz batch concurrency must be an integer between 1 and 50");
847
+ }
848
+ return concurrency;
849
+ }
850
+ function batchConcurrencyPlan(options) {
851
+ const concurrency = validatedBatchConcurrency(options);
852
+ const serverConcurrency = Math.min(10, concurrency);
853
+ return {
854
+ serverConcurrency,
855
+ chunkConcurrency: Math.max(1, Math.floor(concurrency / serverConcurrency))
856
+ };
857
+ }
858
+ function dedupeExactBatchItems(items, keyForItem) {
859
+ const uniqueItems = [];
860
+ const sourceIndexByInput = [];
861
+ const uniqueIndexByKey = /* @__PURE__ */ new Map();
862
+ for (const item of items) {
863
+ const key = keyForItem(item);
864
+ let uniqueIndex = uniqueIndexByKey.get(key);
865
+ if (uniqueIndex === void 0) {
866
+ uniqueIndex = uniqueItems.length;
867
+ uniqueIndexByKey.set(key, uniqueIndex);
868
+ uniqueItems.push(item);
869
+ }
870
+ sourceIndexByInput.push(uniqueIndex);
871
+ }
872
+ return { uniqueItems, sourceIndexByInput };
873
+ }
874
+ function finalizeCoreBatch(total, startedAt, round, normalize) {
875
+ const results = new Array(total);
876
+ for (const item of round) {
877
+ if (!item.success || !item.raw) {
878
+ results[item.index] = { index: item.index, success: false, error: item.error || "Signaliz batch item failed" };
879
+ continue;
880
+ }
881
+ try {
882
+ results[item.index] = { index: item.index, success: true, data: normalize(item) };
883
+ } catch (error) {
884
+ results[item.index] = {
885
+ index: item.index,
886
+ success: false,
887
+ error: error instanceof Error ? error.message : String(error)
888
+ };
889
+ }
890
+ }
891
+ const succeeded = results.filter((item) => item.success).length;
892
+ return {
893
+ total,
894
+ succeeded,
895
+ failed: total - succeeded,
896
+ durationMs: Date.now() - startedAt,
897
+ results
898
+ };
899
+ }
680
900
  function signalToCopyRequestBody(params) {
681
901
  return compact({
682
902
  company_domain: params.companyDomain,
@@ -738,16 +958,8 @@ function sleep2(ms) {
738
958
  return new Promise((resolve) => setTimeout(resolve, ms));
739
959
  }
740
960
  async function runBatch(items, execute, options) {
741
- if (!Array.isArray(items) || items.length === 0) {
742
- throw new Error("Signaliz batch requests require at least one item");
743
- }
744
- if (items.length > 5e3) {
745
- throw new Error(`Signaliz batch requests support at most 5,000 items; received ${items.length}`);
746
- }
747
- const concurrency = options?.concurrency ?? 10;
748
- if (!Number.isInteger(concurrency) || concurrency < 1 || concurrency > 50) {
749
- throw new Error("Signaliz batch concurrency must be an integer between 1 and 50");
750
- }
961
+ validateBatchSize(items);
962
+ const concurrency = validatedBatchConcurrency(options);
751
963
  const startedAt = Date.now();
752
964
  const results = new Array(items.length);
753
965
  let nextIndex = 0;
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  Signaliz
4
- } from "./chunk-R4DIAP7P.mjs";
4
+ } from "./chunk-P3ICLKAE.mjs";
5
5
 
6
6
  // src/mcp-config.ts
7
7
  import * as fs from "fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signaliz/sdk",
3
- "version": "1.0.29",
3
+ "version": "1.0.31",
4
4
  "description": "Signaliz SDK for Find Email, Verify Email, Company Signal Enrichment, and Signal to Copy AI.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -8,14 +8,24 @@
8
8
  "bin": {
9
9
  "signaliz-mcp": "dist/mcp-config.js"
10
10
  },
11
- "files": ["dist", "README.md"],
11
+ "files": [
12
+ "dist",
13
+ "README.md"
14
+ ],
12
15
  "scripts": {
13
16
  "generate-types": "tsx scripts/generate-types.ts",
14
17
  "build": "npm run generate-types && tsup src/index.ts src/mcp-config.ts --format cjs,esm --dts --clean",
15
18
  "test": "tsx tests/core-products.test.ts",
16
19
  "prepublishOnly": "npm run build"
17
20
  },
18
- "keywords": ["signaliz", "mcp", "email-finder", "email-verification", "company-signals", "signal-to-copy"],
21
+ "keywords": [
22
+ "signaliz",
23
+ "mcp",
24
+ "email-finder",
25
+ "email-verification",
26
+ "company-signals",
27
+ "signal-to-copy"
28
+ ],
19
29
  "license": "MIT",
20
30
  "repository": {
21
31
  "type": "git",