@signaliz/sdk 1.0.48 → 1.0.50

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/README.md CHANGED
@@ -97,21 +97,22 @@ when the REST API supplies them, including after automatic row retries are
97
97
  exhausted.
98
98
 
99
99
  For an ambiguous single request or batch submission failure, retry with the
100
- same `idempotencyKey` to recover the original request or supported email job without duplicate
100
+ same `idempotencyKey` to recover the original request or durable job without duplicate
101
101
  work.
102
102
 
103
- Each batch accepts up to 5,000 items. For Company Signals and Signal to Copy,
104
- the SDK chunks inputs into synchronous requests of at most 25 and waits for
105
- every chunk. It never returns queued work, job IDs, or polling instructions.
103
+ Each batch accepts up to 5,000 items. For all four core products, batches larger
104
+ than 25 use one recoverable REST job; the SDK waits for completion and retrieves
105
+ every result page before returning, so callers never receive queued work or
106
+ polling instructions. Find Email, Verify Email, and Signal to Copy use 500-row
107
+ result pages, while Company Signals uses 25-row result pages.
106
108
  Exact duplicate tasks are single-flighted across each full batch without
107
109
  changing input order or result cardinality. Set `compactDuplicates: true` to
108
110
  return repeated successful rows as `duplicateOf` references to the zero-based
109
- canonical input index; the default remains expanded for compatibility. Find Email and Verify Email
110
- batches
111
- larger than 25 use one cache-aware recoverable REST job with 500-row result
112
- pages. Company Signal Enrichment and Signal to Copy always use client-side
113
- 25-row chunks with terminal per-row results. Signal to Copy also shares company
114
- research across copy recipients.
111
+ canonical input index; the default remains expanded for compatibility. Signal
112
+ to Copy durable jobs use available company-signal data only. If any copy row
113
+ explicitly requests `skipCache` or `enableDeepSearch`, the SDK preserves that
114
+ fresh-research behavior by using synchronous client-side chunks of at most 25.
115
+ Signal to Copy also shares company research across copy recipients.
115
116
 
116
117
  Company Signal Enrichment defaults `online` and `enableDeepSearch` to `true`
117
118
  unless the caller explicitly disables them. Its `searchMode` defaults to
@@ -124,7 +125,8 @@ normally finishes within an agent turn; set `skipCache` or `enableDeepSearch`
124
125
  only when fresh or deeper research is required.
125
126
  Unclassified evidence is returned by signal enrichment but is not used to
126
127
  generate outreach copy.
127
- Each normalized signal also exposes `datePrecision`, `sourceProvenance`,
128
+ Each normalized signal keeps `date` separate from crawl-time `detectedAt` and
129
+ also exposes `datePrecision`, `hasSpecificDate`, `sourceProvenance`,
128
130
  `entityConfidence`, `classification`, `derived`, `evidencePublishedDate`,
129
131
  `signalFeedSource`, and the provider `metadata` needed for integrity audits.
130
132
 
@@ -457,6 +457,7 @@ var Signaliz = class {
457
457
  );
458
458
  }
459
459
  async enrichCompanySignals(params) {
460
+ validateCoreProductMaxWaitMs(params.maxWaitMs);
460
461
  const request = companySignalRequestBody(params);
461
462
  const data = await this.client.post("api/v1/company-signals", request);
462
463
  if (isCoreProductDryRun(data)) return normalizeCoreProductDryRunResult(data);
@@ -465,6 +466,7 @@ var Signaliz = class {
465
466
  }
466
467
  async enrichCompanies(companies, options) {
467
468
  validateBatchSize(companies);
469
+ companies.forEach((params) => validateCoreProductMaxWaitMs(params.maxWaitMs));
468
470
  if (options?.dryRun === true) {
469
471
  return this.runCoreProductDryRun(
470
472
  "api/v1/company-signals",
@@ -522,7 +524,10 @@ var Signaliz = class {
522
524
  request: signalToCopyRequestBody(params)
523
525
  }));
524
526
  const uniqueRequests = deduplicated.uniqueItems;
525
- const uniqueResults = await this.runSignalCopyBatchChunks(uniqueRequests, options);
527
+ const requiresFreshResearch = uniqueRequests.some(
528
+ (request) => request.skipCache === true || request.enableDeepSearch === true
529
+ );
530
+ const uniqueResults = uniqueRequests.length > 25 && !requiresFreshResearch ? await this.runRecoverableSignalCopyBatch(uniqueRequests, options) : await this.runSignalCopyBatchChunks(uniqueRequests, options);
526
531
  const results = requests.map((_, index) => ({
527
532
  ...uniqueResults[deduplicated.sourceIndexByInput[index]],
528
533
  index
@@ -648,6 +653,35 @@ var Signaliz = class {
648
653
  if (seen.size !== requests.length) throw new Error(`${label} batch returned incomplete indexed results`);
649
654
  return rows;
650
655
  }
656
+ async runRecoverableSignalCopyBatch(requests, options) {
657
+ const rows = await this.runRecoverableCoreBatchJob(
658
+ "api/v1/signal-to-copy",
659
+ requests.map(signalToCopyRequestBody),
660
+ "Signal to Copy",
661
+ 500,
662
+ 20 * 6e4,
663
+ options?.idempotencyKey
664
+ );
665
+ const results = new Array(requests.length);
666
+ for (const row of rows) {
667
+ const index = Number(row.index);
668
+ if (recoverableJobRowFailed(row)) {
669
+ results[index] = batchItemFailure(
670
+ index,
671
+ row.error || row._error || row.message || row.failure_reason || "Signal to Copy item failed",
672
+ row
673
+ );
674
+ continue;
675
+ }
676
+ try {
677
+ assertTerminalSignalResponse(row, "Signal to Copy");
678
+ results[index] = { index, success: true, data: normalizeSignalToCopyResult(row) };
679
+ } catch (error) {
680
+ results[index] = batchItemFailure(index, error instanceof Error ? error.message : String(error), row);
681
+ }
682
+ }
683
+ return results;
684
+ }
651
685
  async runSignalCopyBatchChunk(requests, concurrency, rowRateLimitAttempt = 0) {
652
686
  const results = new Array(requests.length);
653
687
  const rateLimited = [];
@@ -700,8 +734,8 @@ var Signaliz = class {
700
734
  const { serverConcurrency, chunkConcurrency } = batchConcurrencyPlan(options);
701
735
  const deduplicated = dedupeExactBatchItems(tasks, (task) => JSON.stringify(task.request));
702
736
  const uniqueTasks = deduplicated.uniqueItems;
703
- const recoverableBatch = path === "api/v1/find-email" ? { label: "Find Email", pageSize: 500, maxWaitMs: 20 * 6e4 } : path === "api/v1/verify-email" ? { label: "Verify Email", pageSize: 500, maxWaitMs: 20 * 6e4 } : void 0;
704
- if (path !== "api/v1/company-signals" && recoverableBatch && uniqueTasks.length > 25) {
737
+ const recoverableBatch = path === "api/v1/find-email" ? { label: "Find Email", pageSize: 500, maxWaitMs: 20 * 6e4 } : path === "api/v1/verify-email" ? { label: "Verify Email", pageSize: 500, maxWaitMs: 20 * 6e4 } : path === "api/v1/company-signals" ? { label: "Company Signals", pageSize: 25, maxWaitMs: 20 * 6e4 } : void 0;
738
+ if (recoverableBatch && uniqueTasks.length > 25) {
705
739
  const rows = await this.runRecoverableCoreBatchJob(
706
740
  path,
707
741
  uniqueTasks.map((task) => task.request),
@@ -710,12 +744,16 @@ var Signaliz = class {
710
744
  recoverableBatch.maxWaitMs,
711
745
  options?.idempotencyKey
712
746
  );
713
- const uniqueResults2 = rows.map((raw) => ({
714
- index: uniqueTasks[Number(raw.index)].index,
715
- success: !recoverableJobRowFailed(raw),
716
- raw,
717
- error: recoverableJobRowFailed(raw) ? raw.error || raw._error || raw.message || raw.failure_reason || `${recoverableBatch.label} item failed` : void 0
718
- }));
747
+ const uniqueResults2 = new Array(uniqueTasks.length);
748
+ for (const raw of rows) {
749
+ const index = Number(raw.index);
750
+ uniqueResults2[index] = {
751
+ index: uniqueTasks[index].index,
752
+ success: !recoverableJobRowFailed(raw),
753
+ raw,
754
+ error: recoverableJobRowFailed(raw) ? raw.error || raw._error || raw.message || raw.failure_reason || `${recoverableBatch.label} item failed` : void 0
755
+ };
756
+ }
719
757
  return tasks.map((task, index) => ({
720
758
  ...uniqueResults2[deduplicated.sourceIndexByInput[index]],
721
759
  index: task.index
@@ -901,6 +939,15 @@ function normalizeFindEmailResult(data) {
901
939
  verifiedAt: typeof data.verified_at === "string" ? data.verified_at : null,
902
940
  needsReverification,
903
941
  providerUsed: data.provider_used ?? data.provider ?? data.email_source ?? data.source ?? "unknown",
942
+ creditsUsed: data.credits_used,
943
+ estimatedExternalCostUsd: data.estimated_external_cost_usd,
944
+ billingMetadata: data.billing_metadata,
945
+ resultReturnedFrom: data.result_returned_from,
946
+ cacheHit: data.cache_hit,
947
+ freshEnrichmentUsed: data.fresh_enrichment_used,
948
+ liveProviderCalled: data.live_provider_called,
949
+ openrouterCalled: data.openrouter_called,
950
+ byoOpenrouterUsed: data.byo_openrouter_used,
904
951
  error: found ? void 0 : data.error ?? "No verified email found",
905
952
  errorCode: found ? void 0 : data.error_code ?? "EMAIL_NOT_FOUND",
906
953
  raw: data
@@ -910,6 +957,7 @@ function normalizeVerifyEmailResult(email, data) {
910
957
  const verificationStatus = String(data.verification_status ?? "").toLowerCase();
911
958
  const verified = data.email_verified === true || ["valid", "deliverable"].includes(verificationStatus);
912
959
  return {
960
+ success: data.success !== false,
913
961
  email: data.email ?? email,
914
962
  status: String(data.status || "").toLowerCase() === "processing" ? "processing" : "completed",
915
963
  verificationRunId: data.verification_run_id ?? data.run_id,
@@ -918,9 +966,20 @@ function normalizeVerifyEmailResult(email, data) {
918
966
  isValid: data.is_valid ?? data.valid ?? verified,
919
967
  isDeliverable: data.is_deliverable ?? data.deliverable ?? verified,
920
968
  isCatchAll: data.email_is_catch_all ?? data.is_catch_all ?? data.catch_all ?? data.diagnostics?.is_catch_all ?? false,
969
+ verifiedForSending: data.verified_for_sending === true,
970
+ verificationVerdict: data.verification_verdict ?? data.verification_status ?? "unknown",
921
971
  confidenceScore: data.confidence_score ?? data.confidence ?? data.diagnostics?.confidence_score ?? (verified ? 1 : 0),
922
972
  provider: data.provider,
923
973
  verificationSource: data.verification_source,
974
+ billingReplayed: data.billing_replayed,
975
+ creditsUsed: data.credits_used,
976
+ billingMetadata: data.billing_metadata,
977
+ resultReturnedFrom: data.result_returned_from,
978
+ cacheHit: data.cache_hit,
979
+ freshEnrichmentUsed: data.fresh_enrichment_used,
980
+ liveProviderCalled: data.live_provider_called,
981
+ openrouterCalled: data.openrouter_called,
982
+ byoOpenrouterUsed: data.byo_openrouter_used,
924
983
  raw: data
925
984
  };
926
985
  }
@@ -964,8 +1023,10 @@ function normalizeCompanySignalResult(params, data) {
964
1023
  title: signal.title ?? "",
965
1024
  type: signal.type ?? signal.signal_type ?? "unknown",
966
1025
  content: signal.content ?? signal.description ?? "",
967
- date: signal.date ?? signal.detected_at ?? null,
1026
+ date: signal.date ?? null,
1027
+ detectedAt: signal.detected_at ?? null,
968
1028
  datePrecision: signal.date_precision,
1029
+ hasSpecificDate: signal.has_specific_date ?? metadata?.has_specific_date,
969
1030
  sourceUrl: signal.source_url ?? signal.url ?? null,
970
1031
  sourceType: signal.source_type,
971
1032
  sourceProvenance: signal.source_provenance,
@@ -994,7 +1055,10 @@ function normalizeCompanySignalResult(params, data) {
994
1055
  billingMetadata: data.billing_metadata,
995
1056
  resultReturnedFrom: data.result_returned_from,
996
1057
  cacheHit: data.cache_hit,
1058
+ freshEnrichmentUsed: data.fresh_enrichment_used,
997
1059
  liveProviderCalled: data.live_provider_called,
1060
+ aiProviderCalled: data.ai_provider_called,
1061
+ byoAiUsed: data.byo_ai_used,
998
1062
  metadata: data.metadata,
999
1063
  raw: data
1000
1064
  };
@@ -1100,6 +1164,7 @@ function signalToCopyRequestBody(params) {
1100
1164
  });
1101
1165
  }
1102
1166
  function validateSignalToCopyParams(params) {
1167
+ validateCoreProductMaxWaitMs(params.maxWaitMs);
1103
1168
  if (typeof params.signalRunId === "string" && params.signalRunId.trim()) return;
1104
1169
  const missing = [
1105
1170
  ["companyDomain", params.companyDomain],
@@ -1111,6 +1176,12 @@ function validateSignalToCopyParams(params) {
1111
1176
  throw new TypeError(`Signal to Copy requires signalRunId or: ${missing.join(", ")}`);
1112
1177
  }
1113
1178
  }
1179
+ function validateCoreProductMaxWaitMs(value) {
1180
+ if (value === void 0) return;
1181
+ if (!Number.isInteger(value) || value < 1e4 || value > 12e4) {
1182
+ throw new RangeError("maxWaitMs must be an integer between 10000 and 120000");
1183
+ }
1184
+ }
1114
1185
  function normalizeSignalToCopyResult(data) {
1115
1186
  return {
1116
1187
  success: data.success ?? true,
package/dist/index.d.mts CHANGED
@@ -92,11 +92,21 @@ interface FindEmailResult {
92
92
  verifiedAt: string | null;
93
93
  needsReverification: boolean;
94
94
  providerUsed: string;
95
+ creditsUsed?: number;
96
+ estimatedExternalCostUsd?: number;
97
+ billingMetadata?: Record<string, unknown>;
98
+ resultReturnedFrom?: string;
99
+ cacheHit?: boolean;
100
+ freshEnrichmentUsed?: boolean;
101
+ liveProviderCalled?: boolean;
102
+ openrouterCalled?: boolean;
103
+ byoOpenrouterUsed?: boolean;
95
104
  error?: string;
96
105
  errorCode?: string;
97
106
  raw: Record<string, unknown>;
98
107
  }
99
108
  interface VerifyEmailResult {
109
+ success: boolean;
100
110
  email: string;
101
111
  /** Execution state. Processing results are never send-safe. */
102
112
  status: 'processing' | 'completed';
@@ -107,9 +117,21 @@ interface VerifyEmailResult {
107
117
  isValid: boolean;
108
118
  isDeliverable: boolean;
109
119
  isCatchAll: boolean;
120
+ /** Explicit send-safety verdict. Missing or false never becomes true by inference. */
121
+ verifiedForSending: boolean;
122
+ verificationVerdict: string;
110
123
  confidenceScore: number;
111
124
  provider?: string;
112
125
  verificationSource?: string;
126
+ billingReplayed?: boolean;
127
+ creditsUsed?: number;
128
+ billingMetadata?: Record<string, unknown>;
129
+ resultReturnedFrom?: string;
130
+ cacheHit?: boolean;
131
+ freshEnrichmentUsed?: boolean;
132
+ liveProviderCalled?: boolean;
133
+ openrouterCalled?: boolean;
134
+ byoOpenrouterUsed?: boolean;
113
135
  raw: Record<string, unknown>;
114
136
  }
115
137
  interface VerifyEmailOptions {
@@ -164,7 +186,9 @@ interface CompanySignal {
164
186
  type: string;
165
187
  content: string;
166
188
  date?: string | null;
189
+ detectedAt?: string | null;
167
190
  datePrecision?: string;
191
+ hasSpecificDate?: boolean;
168
192
  sourceUrl?: string | null;
169
193
  sourceType?: string;
170
194
  sourceProvenance?: string;
@@ -201,7 +225,10 @@ interface CompanySignalEnrichmentResult {
201
225
  billingMetadata?: Record<string, unknown>;
202
226
  resultReturnedFrom?: string;
203
227
  cacheHit?: boolean;
228
+ freshEnrichmentUsed?: boolean;
204
229
  liveProviderCalled?: boolean;
230
+ aiProviderCalled?: boolean;
231
+ byoAiUsed?: boolean;
205
232
  metadata?: Record<string, unknown>;
206
233
  raw: Record<string, unknown>;
207
234
  }
@@ -311,6 +338,7 @@ declare class Signaliz {
311
338
  private runCoreProductDryRun;
312
339
  private runSignalCopyBatchChunks;
313
340
  private runRecoverableCoreBatchJob;
341
+ private runRecoverableSignalCopyBatch;
314
342
  private runSignalCopyBatchChunk;
315
343
  private runCoreBatchRound;
316
344
  listTools(): Promise<MCPToolInfo[]>;
package/dist/index.d.ts CHANGED
@@ -92,11 +92,21 @@ interface FindEmailResult {
92
92
  verifiedAt: string | null;
93
93
  needsReverification: boolean;
94
94
  providerUsed: string;
95
+ creditsUsed?: number;
96
+ estimatedExternalCostUsd?: number;
97
+ billingMetadata?: Record<string, unknown>;
98
+ resultReturnedFrom?: string;
99
+ cacheHit?: boolean;
100
+ freshEnrichmentUsed?: boolean;
101
+ liveProviderCalled?: boolean;
102
+ openrouterCalled?: boolean;
103
+ byoOpenrouterUsed?: boolean;
95
104
  error?: string;
96
105
  errorCode?: string;
97
106
  raw: Record<string, unknown>;
98
107
  }
99
108
  interface VerifyEmailResult {
109
+ success: boolean;
100
110
  email: string;
101
111
  /** Execution state. Processing results are never send-safe. */
102
112
  status: 'processing' | 'completed';
@@ -107,9 +117,21 @@ interface VerifyEmailResult {
107
117
  isValid: boolean;
108
118
  isDeliverable: boolean;
109
119
  isCatchAll: boolean;
120
+ /** Explicit send-safety verdict. Missing or false never becomes true by inference. */
121
+ verifiedForSending: boolean;
122
+ verificationVerdict: string;
110
123
  confidenceScore: number;
111
124
  provider?: string;
112
125
  verificationSource?: string;
126
+ billingReplayed?: boolean;
127
+ creditsUsed?: number;
128
+ billingMetadata?: Record<string, unknown>;
129
+ resultReturnedFrom?: string;
130
+ cacheHit?: boolean;
131
+ freshEnrichmentUsed?: boolean;
132
+ liveProviderCalled?: boolean;
133
+ openrouterCalled?: boolean;
134
+ byoOpenrouterUsed?: boolean;
113
135
  raw: Record<string, unknown>;
114
136
  }
115
137
  interface VerifyEmailOptions {
@@ -164,7 +186,9 @@ interface CompanySignal {
164
186
  type: string;
165
187
  content: string;
166
188
  date?: string | null;
189
+ detectedAt?: string | null;
167
190
  datePrecision?: string;
191
+ hasSpecificDate?: boolean;
168
192
  sourceUrl?: string | null;
169
193
  sourceType?: string;
170
194
  sourceProvenance?: string;
@@ -201,7 +225,10 @@ interface CompanySignalEnrichmentResult {
201
225
  billingMetadata?: Record<string, unknown>;
202
226
  resultReturnedFrom?: string;
203
227
  cacheHit?: boolean;
228
+ freshEnrichmentUsed?: boolean;
204
229
  liveProviderCalled?: boolean;
230
+ aiProviderCalled?: boolean;
231
+ byoAiUsed?: boolean;
205
232
  metadata?: Record<string, unknown>;
206
233
  raw: Record<string, unknown>;
207
234
  }
@@ -311,6 +338,7 @@ declare class Signaliz {
311
338
  private runCoreProductDryRun;
312
339
  private runSignalCopyBatchChunks;
313
340
  private runRecoverableCoreBatchJob;
341
+ private runRecoverableSignalCopyBatch;
314
342
  private runSignalCopyBatchChunk;
315
343
  private runCoreBatchRound;
316
344
  listTools(): Promise<MCPToolInfo[]>;
package/dist/index.js CHANGED
@@ -484,6 +484,7 @@ var Signaliz = class {
484
484
  );
485
485
  }
486
486
  async enrichCompanySignals(params) {
487
+ validateCoreProductMaxWaitMs(params.maxWaitMs);
487
488
  const request = companySignalRequestBody(params);
488
489
  const data = await this.client.post("api/v1/company-signals", request);
489
490
  if (isCoreProductDryRun(data)) return normalizeCoreProductDryRunResult(data);
@@ -492,6 +493,7 @@ var Signaliz = class {
492
493
  }
493
494
  async enrichCompanies(companies, options) {
494
495
  validateBatchSize(companies);
496
+ companies.forEach((params) => validateCoreProductMaxWaitMs(params.maxWaitMs));
495
497
  if (options?.dryRun === true) {
496
498
  return this.runCoreProductDryRun(
497
499
  "api/v1/company-signals",
@@ -549,7 +551,10 @@ var Signaliz = class {
549
551
  request: signalToCopyRequestBody(params)
550
552
  }));
551
553
  const uniqueRequests = deduplicated.uniqueItems;
552
- const uniqueResults = await this.runSignalCopyBatchChunks(uniqueRequests, options);
554
+ const requiresFreshResearch = uniqueRequests.some(
555
+ (request) => request.skipCache === true || request.enableDeepSearch === true
556
+ );
557
+ const uniqueResults = uniqueRequests.length > 25 && !requiresFreshResearch ? await this.runRecoverableSignalCopyBatch(uniqueRequests, options) : await this.runSignalCopyBatchChunks(uniqueRequests, options);
553
558
  const results = requests.map((_, index) => ({
554
559
  ...uniqueResults[deduplicated.sourceIndexByInput[index]],
555
560
  index
@@ -675,6 +680,35 @@ var Signaliz = class {
675
680
  if (seen.size !== requests.length) throw new Error(`${label} batch returned incomplete indexed results`);
676
681
  return rows;
677
682
  }
683
+ async runRecoverableSignalCopyBatch(requests, options) {
684
+ const rows = await this.runRecoverableCoreBatchJob(
685
+ "api/v1/signal-to-copy",
686
+ requests.map(signalToCopyRequestBody),
687
+ "Signal to Copy",
688
+ 500,
689
+ 20 * 6e4,
690
+ options?.idempotencyKey
691
+ );
692
+ const results = new Array(requests.length);
693
+ for (const row of rows) {
694
+ const index = Number(row.index);
695
+ if (recoverableJobRowFailed(row)) {
696
+ results[index] = batchItemFailure(
697
+ index,
698
+ row.error || row._error || row.message || row.failure_reason || "Signal to Copy item failed",
699
+ row
700
+ );
701
+ continue;
702
+ }
703
+ try {
704
+ assertTerminalSignalResponse(row, "Signal to Copy");
705
+ results[index] = { index, success: true, data: normalizeSignalToCopyResult(row) };
706
+ } catch (error) {
707
+ results[index] = batchItemFailure(index, error instanceof Error ? error.message : String(error), row);
708
+ }
709
+ }
710
+ return results;
711
+ }
678
712
  async runSignalCopyBatchChunk(requests, concurrency, rowRateLimitAttempt = 0) {
679
713
  const results = new Array(requests.length);
680
714
  const rateLimited = [];
@@ -727,8 +761,8 @@ var Signaliz = class {
727
761
  const { serverConcurrency, chunkConcurrency } = batchConcurrencyPlan(options);
728
762
  const deduplicated = dedupeExactBatchItems(tasks, (task) => JSON.stringify(task.request));
729
763
  const uniqueTasks = deduplicated.uniqueItems;
730
- const recoverableBatch = path === "api/v1/find-email" ? { label: "Find Email", pageSize: 500, maxWaitMs: 20 * 6e4 } : path === "api/v1/verify-email" ? { label: "Verify Email", pageSize: 500, maxWaitMs: 20 * 6e4 } : void 0;
731
- if (path !== "api/v1/company-signals" && recoverableBatch && uniqueTasks.length > 25) {
764
+ const recoverableBatch = path === "api/v1/find-email" ? { label: "Find Email", pageSize: 500, maxWaitMs: 20 * 6e4 } : path === "api/v1/verify-email" ? { label: "Verify Email", pageSize: 500, maxWaitMs: 20 * 6e4 } : path === "api/v1/company-signals" ? { label: "Company Signals", pageSize: 25, maxWaitMs: 20 * 6e4 } : void 0;
765
+ if (recoverableBatch && uniqueTasks.length > 25) {
732
766
  const rows = await this.runRecoverableCoreBatchJob(
733
767
  path,
734
768
  uniqueTasks.map((task) => task.request),
@@ -737,12 +771,16 @@ var Signaliz = class {
737
771
  recoverableBatch.maxWaitMs,
738
772
  options?.idempotencyKey
739
773
  );
740
- const uniqueResults2 = rows.map((raw) => ({
741
- index: uniqueTasks[Number(raw.index)].index,
742
- success: !recoverableJobRowFailed(raw),
743
- raw,
744
- error: recoverableJobRowFailed(raw) ? raw.error || raw._error || raw.message || raw.failure_reason || `${recoverableBatch.label} item failed` : void 0
745
- }));
774
+ const uniqueResults2 = new Array(uniqueTasks.length);
775
+ for (const raw of rows) {
776
+ const index = Number(raw.index);
777
+ uniqueResults2[index] = {
778
+ index: uniqueTasks[index].index,
779
+ success: !recoverableJobRowFailed(raw),
780
+ raw,
781
+ error: recoverableJobRowFailed(raw) ? raw.error || raw._error || raw.message || raw.failure_reason || `${recoverableBatch.label} item failed` : void 0
782
+ };
783
+ }
746
784
  return tasks.map((task, index) => ({
747
785
  ...uniqueResults2[deduplicated.sourceIndexByInput[index]],
748
786
  index: task.index
@@ -928,6 +966,15 @@ function normalizeFindEmailResult(data) {
928
966
  verifiedAt: typeof data.verified_at === "string" ? data.verified_at : null,
929
967
  needsReverification,
930
968
  providerUsed: data.provider_used ?? data.provider ?? data.email_source ?? data.source ?? "unknown",
969
+ creditsUsed: data.credits_used,
970
+ estimatedExternalCostUsd: data.estimated_external_cost_usd,
971
+ billingMetadata: data.billing_metadata,
972
+ resultReturnedFrom: data.result_returned_from,
973
+ cacheHit: data.cache_hit,
974
+ freshEnrichmentUsed: data.fresh_enrichment_used,
975
+ liveProviderCalled: data.live_provider_called,
976
+ openrouterCalled: data.openrouter_called,
977
+ byoOpenrouterUsed: data.byo_openrouter_used,
931
978
  error: found ? void 0 : data.error ?? "No verified email found",
932
979
  errorCode: found ? void 0 : data.error_code ?? "EMAIL_NOT_FOUND",
933
980
  raw: data
@@ -937,6 +984,7 @@ function normalizeVerifyEmailResult(email, data) {
937
984
  const verificationStatus = String(data.verification_status ?? "").toLowerCase();
938
985
  const verified = data.email_verified === true || ["valid", "deliverable"].includes(verificationStatus);
939
986
  return {
987
+ success: data.success !== false,
940
988
  email: data.email ?? email,
941
989
  status: String(data.status || "").toLowerCase() === "processing" ? "processing" : "completed",
942
990
  verificationRunId: data.verification_run_id ?? data.run_id,
@@ -945,9 +993,20 @@ function normalizeVerifyEmailResult(email, data) {
945
993
  isValid: data.is_valid ?? data.valid ?? verified,
946
994
  isDeliverable: data.is_deliverable ?? data.deliverable ?? verified,
947
995
  isCatchAll: data.email_is_catch_all ?? data.is_catch_all ?? data.catch_all ?? data.diagnostics?.is_catch_all ?? false,
996
+ verifiedForSending: data.verified_for_sending === true,
997
+ verificationVerdict: data.verification_verdict ?? data.verification_status ?? "unknown",
948
998
  confidenceScore: data.confidence_score ?? data.confidence ?? data.diagnostics?.confidence_score ?? (verified ? 1 : 0),
949
999
  provider: data.provider,
950
1000
  verificationSource: data.verification_source,
1001
+ billingReplayed: data.billing_replayed,
1002
+ creditsUsed: data.credits_used,
1003
+ billingMetadata: data.billing_metadata,
1004
+ resultReturnedFrom: data.result_returned_from,
1005
+ cacheHit: data.cache_hit,
1006
+ freshEnrichmentUsed: data.fresh_enrichment_used,
1007
+ liveProviderCalled: data.live_provider_called,
1008
+ openrouterCalled: data.openrouter_called,
1009
+ byoOpenrouterUsed: data.byo_openrouter_used,
951
1010
  raw: data
952
1011
  };
953
1012
  }
@@ -991,8 +1050,10 @@ function normalizeCompanySignalResult(params, data) {
991
1050
  title: signal.title ?? "",
992
1051
  type: signal.type ?? signal.signal_type ?? "unknown",
993
1052
  content: signal.content ?? signal.description ?? "",
994
- date: signal.date ?? signal.detected_at ?? null,
1053
+ date: signal.date ?? null,
1054
+ detectedAt: signal.detected_at ?? null,
995
1055
  datePrecision: signal.date_precision,
1056
+ hasSpecificDate: signal.has_specific_date ?? metadata?.has_specific_date,
996
1057
  sourceUrl: signal.source_url ?? signal.url ?? null,
997
1058
  sourceType: signal.source_type,
998
1059
  sourceProvenance: signal.source_provenance,
@@ -1021,7 +1082,10 @@ function normalizeCompanySignalResult(params, data) {
1021
1082
  billingMetadata: data.billing_metadata,
1022
1083
  resultReturnedFrom: data.result_returned_from,
1023
1084
  cacheHit: data.cache_hit,
1085
+ freshEnrichmentUsed: data.fresh_enrichment_used,
1024
1086
  liveProviderCalled: data.live_provider_called,
1087
+ aiProviderCalled: data.ai_provider_called,
1088
+ byoAiUsed: data.byo_ai_used,
1025
1089
  metadata: data.metadata,
1026
1090
  raw: data
1027
1091
  };
@@ -1127,6 +1191,7 @@ function signalToCopyRequestBody(params) {
1127
1191
  });
1128
1192
  }
1129
1193
  function validateSignalToCopyParams(params) {
1194
+ validateCoreProductMaxWaitMs(params.maxWaitMs);
1130
1195
  if (typeof params.signalRunId === "string" && params.signalRunId.trim()) return;
1131
1196
  const missing = [
1132
1197
  ["companyDomain", params.companyDomain],
@@ -1138,6 +1203,12 @@ function validateSignalToCopyParams(params) {
1138
1203
  throw new TypeError(`Signal to Copy requires signalRunId or: ${missing.join(", ")}`);
1139
1204
  }
1140
1205
  }
1206
+ function validateCoreProductMaxWaitMs(value) {
1207
+ if (value === void 0) return;
1208
+ if (!Number.isInteger(value) || value < 1e4 || value > 12e4) {
1209
+ throw new RangeError("maxWaitMs must be an integer between 10000 and 120000");
1210
+ }
1211
+ }
1141
1212
  function normalizeSignalToCopyResult(data) {
1142
1213
  return {
1143
1214
  success: data.success ?? true,
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  Signaliz,
3
3
  SignalizError
4
- } from "./chunk-NOOQDYOJ.mjs";
4
+ } from "./chunk-BFMRS2FT.mjs";
5
5
  export {
6
6
  Signaliz,
7
7
  SignalizError
@@ -488,6 +488,7 @@ var Signaliz = class {
488
488
  );
489
489
  }
490
490
  async enrichCompanySignals(params) {
491
+ validateCoreProductMaxWaitMs(params.maxWaitMs);
491
492
  const request = companySignalRequestBody(params);
492
493
  const data = await this.client.post("api/v1/company-signals", request);
493
494
  if (isCoreProductDryRun(data)) return normalizeCoreProductDryRunResult(data);
@@ -496,6 +497,7 @@ var Signaliz = class {
496
497
  }
497
498
  async enrichCompanies(companies, options) {
498
499
  validateBatchSize(companies);
500
+ companies.forEach((params) => validateCoreProductMaxWaitMs(params.maxWaitMs));
499
501
  if (options?.dryRun === true) {
500
502
  return this.runCoreProductDryRun(
501
503
  "api/v1/company-signals",
@@ -553,7 +555,10 @@ var Signaliz = class {
553
555
  request: signalToCopyRequestBody(params)
554
556
  }));
555
557
  const uniqueRequests = deduplicated.uniqueItems;
556
- const uniqueResults = await this.runSignalCopyBatchChunks(uniqueRequests, options);
558
+ const requiresFreshResearch = uniqueRequests.some(
559
+ (request) => request.skipCache === true || request.enableDeepSearch === true
560
+ );
561
+ const uniqueResults = uniqueRequests.length > 25 && !requiresFreshResearch ? await this.runRecoverableSignalCopyBatch(uniqueRequests, options) : await this.runSignalCopyBatchChunks(uniqueRequests, options);
557
562
  const results = requests.map((_, index) => ({
558
563
  ...uniqueResults[deduplicated.sourceIndexByInput[index]],
559
564
  index
@@ -679,6 +684,35 @@ var Signaliz = class {
679
684
  if (seen.size !== requests.length) throw new Error(`${label} batch returned incomplete indexed results`);
680
685
  return rows;
681
686
  }
687
+ async runRecoverableSignalCopyBatch(requests, options) {
688
+ const rows = await this.runRecoverableCoreBatchJob(
689
+ "api/v1/signal-to-copy",
690
+ requests.map(signalToCopyRequestBody),
691
+ "Signal to Copy",
692
+ 500,
693
+ 20 * 6e4,
694
+ options?.idempotencyKey
695
+ );
696
+ const results = new Array(requests.length);
697
+ for (const row of rows) {
698
+ const index = Number(row.index);
699
+ if (recoverableJobRowFailed(row)) {
700
+ results[index] = batchItemFailure(
701
+ index,
702
+ row.error || row._error || row.message || row.failure_reason || "Signal to Copy item failed",
703
+ row
704
+ );
705
+ continue;
706
+ }
707
+ try {
708
+ assertTerminalSignalResponse(row, "Signal to Copy");
709
+ results[index] = { index, success: true, data: normalizeSignalToCopyResult(row) };
710
+ } catch (error) {
711
+ results[index] = batchItemFailure(index, error instanceof Error ? error.message : String(error), row);
712
+ }
713
+ }
714
+ return results;
715
+ }
682
716
  async runSignalCopyBatchChunk(requests, concurrency, rowRateLimitAttempt = 0) {
683
717
  const results = new Array(requests.length);
684
718
  const rateLimited = [];
@@ -731,8 +765,8 @@ var Signaliz = class {
731
765
  const { serverConcurrency, chunkConcurrency } = batchConcurrencyPlan(options);
732
766
  const deduplicated = dedupeExactBatchItems(tasks, (task) => JSON.stringify(task.request));
733
767
  const uniqueTasks = deduplicated.uniqueItems;
734
- const recoverableBatch = path2 === "api/v1/find-email" ? { label: "Find Email", pageSize: 500, maxWaitMs: 20 * 6e4 } : path2 === "api/v1/verify-email" ? { label: "Verify Email", pageSize: 500, maxWaitMs: 20 * 6e4 } : void 0;
735
- if (path2 !== "api/v1/company-signals" && recoverableBatch && uniqueTasks.length > 25) {
768
+ const recoverableBatch = path2 === "api/v1/find-email" ? { label: "Find Email", pageSize: 500, maxWaitMs: 20 * 6e4 } : path2 === "api/v1/verify-email" ? { label: "Verify Email", pageSize: 500, maxWaitMs: 20 * 6e4 } : path2 === "api/v1/company-signals" ? { label: "Company Signals", pageSize: 25, maxWaitMs: 20 * 6e4 } : void 0;
769
+ if (recoverableBatch && uniqueTasks.length > 25) {
736
770
  const rows = await this.runRecoverableCoreBatchJob(
737
771
  path2,
738
772
  uniqueTasks.map((task) => task.request),
@@ -741,12 +775,16 @@ var Signaliz = class {
741
775
  recoverableBatch.maxWaitMs,
742
776
  options?.idempotencyKey
743
777
  );
744
- const uniqueResults2 = rows.map((raw) => ({
745
- index: uniqueTasks[Number(raw.index)].index,
746
- success: !recoverableJobRowFailed(raw),
747
- raw,
748
- error: recoverableJobRowFailed(raw) ? raw.error || raw._error || raw.message || raw.failure_reason || `${recoverableBatch.label} item failed` : void 0
749
- }));
778
+ const uniqueResults2 = new Array(uniqueTasks.length);
779
+ for (const raw of rows) {
780
+ const index = Number(raw.index);
781
+ uniqueResults2[index] = {
782
+ index: uniqueTasks[index].index,
783
+ success: !recoverableJobRowFailed(raw),
784
+ raw,
785
+ error: recoverableJobRowFailed(raw) ? raw.error || raw._error || raw.message || raw.failure_reason || `${recoverableBatch.label} item failed` : void 0
786
+ };
787
+ }
750
788
  return tasks.map((task, index) => ({
751
789
  ...uniqueResults2[deduplicated.sourceIndexByInput[index]],
752
790
  index: task.index
@@ -932,6 +970,15 @@ function normalizeFindEmailResult(data) {
932
970
  verifiedAt: typeof data.verified_at === "string" ? data.verified_at : null,
933
971
  needsReverification,
934
972
  providerUsed: data.provider_used ?? data.provider ?? data.email_source ?? data.source ?? "unknown",
973
+ creditsUsed: data.credits_used,
974
+ estimatedExternalCostUsd: data.estimated_external_cost_usd,
975
+ billingMetadata: data.billing_metadata,
976
+ resultReturnedFrom: data.result_returned_from,
977
+ cacheHit: data.cache_hit,
978
+ freshEnrichmentUsed: data.fresh_enrichment_used,
979
+ liveProviderCalled: data.live_provider_called,
980
+ openrouterCalled: data.openrouter_called,
981
+ byoOpenrouterUsed: data.byo_openrouter_used,
935
982
  error: found ? void 0 : data.error ?? "No verified email found",
936
983
  errorCode: found ? void 0 : data.error_code ?? "EMAIL_NOT_FOUND",
937
984
  raw: data
@@ -941,6 +988,7 @@ function normalizeVerifyEmailResult(email, data) {
941
988
  const verificationStatus = String(data.verification_status ?? "").toLowerCase();
942
989
  const verified = data.email_verified === true || ["valid", "deliverable"].includes(verificationStatus);
943
990
  return {
991
+ success: data.success !== false,
944
992
  email: data.email ?? email,
945
993
  status: String(data.status || "").toLowerCase() === "processing" ? "processing" : "completed",
946
994
  verificationRunId: data.verification_run_id ?? data.run_id,
@@ -949,9 +997,20 @@ function normalizeVerifyEmailResult(email, data) {
949
997
  isValid: data.is_valid ?? data.valid ?? verified,
950
998
  isDeliverable: data.is_deliverable ?? data.deliverable ?? verified,
951
999
  isCatchAll: data.email_is_catch_all ?? data.is_catch_all ?? data.catch_all ?? data.diagnostics?.is_catch_all ?? false,
1000
+ verifiedForSending: data.verified_for_sending === true,
1001
+ verificationVerdict: data.verification_verdict ?? data.verification_status ?? "unknown",
952
1002
  confidenceScore: data.confidence_score ?? data.confidence ?? data.diagnostics?.confidence_score ?? (verified ? 1 : 0),
953
1003
  provider: data.provider,
954
1004
  verificationSource: data.verification_source,
1005
+ billingReplayed: data.billing_replayed,
1006
+ creditsUsed: data.credits_used,
1007
+ billingMetadata: data.billing_metadata,
1008
+ resultReturnedFrom: data.result_returned_from,
1009
+ cacheHit: data.cache_hit,
1010
+ freshEnrichmentUsed: data.fresh_enrichment_used,
1011
+ liveProviderCalled: data.live_provider_called,
1012
+ openrouterCalled: data.openrouter_called,
1013
+ byoOpenrouterUsed: data.byo_openrouter_used,
955
1014
  raw: data
956
1015
  };
957
1016
  }
@@ -995,8 +1054,10 @@ function normalizeCompanySignalResult(params, data) {
995
1054
  title: signal.title ?? "",
996
1055
  type: signal.type ?? signal.signal_type ?? "unknown",
997
1056
  content: signal.content ?? signal.description ?? "",
998
- date: signal.date ?? signal.detected_at ?? null,
1057
+ date: signal.date ?? null,
1058
+ detectedAt: signal.detected_at ?? null,
999
1059
  datePrecision: signal.date_precision,
1060
+ hasSpecificDate: signal.has_specific_date ?? metadata?.has_specific_date,
1000
1061
  sourceUrl: signal.source_url ?? signal.url ?? null,
1001
1062
  sourceType: signal.source_type,
1002
1063
  sourceProvenance: signal.source_provenance,
@@ -1025,7 +1086,10 @@ function normalizeCompanySignalResult(params, data) {
1025
1086
  billingMetadata: data.billing_metadata,
1026
1087
  resultReturnedFrom: data.result_returned_from,
1027
1088
  cacheHit: data.cache_hit,
1089
+ freshEnrichmentUsed: data.fresh_enrichment_used,
1028
1090
  liveProviderCalled: data.live_provider_called,
1091
+ aiProviderCalled: data.ai_provider_called,
1092
+ byoAiUsed: data.byo_ai_used,
1029
1093
  metadata: data.metadata,
1030
1094
  raw: data
1031
1095
  };
@@ -1131,6 +1195,7 @@ function signalToCopyRequestBody(params) {
1131
1195
  });
1132
1196
  }
1133
1197
  function validateSignalToCopyParams(params) {
1198
+ validateCoreProductMaxWaitMs(params.maxWaitMs);
1134
1199
  if (typeof params.signalRunId === "string" && params.signalRunId.trim()) return;
1135
1200
  const missing = [
1136
1201
  ["companyDomain", params.companyDomain],
@@ -1142,6 +1207,12 @@ function validateSignalToCopyParams(params) {
1142
1207
  throw new TypeError(`Signal to Copy requires signalRunId or: ${missing.join(", ")}`);
1143
1208
  }
1144
1209
  }
1210
+ function validateCoreProductMaxWaitMs(value) {
1211
+ if (value === void 0) return;
1212
+ if (!Number.isInteger(value) || value < 1e4 || value > 12e4) {
1213
+ throw new RangeError("maxWaitMs must be an integer between 10000 and 120000");
1214
+ }
1215
+ }
1145
1216
  function normalizeSignalToCopyResult(data) {
1146
1217
  return {
1147
1218
  success: data.success ?? true,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  Signaliz
4
- } from "./chunk-NOOQDYOJ.mjs";
4
+ } from "./chunk-BFMRS2FT.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.48",
3
+ "version": "1.0.50",
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",