@signaliz/sdk 1.0.55 → 1.0.56
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 +7 -2
- package/dist/{chunk-QXMVHZIQ.mjs → chunk-K7RDDRMJ.mjs} +62 -13
- package/dist/index.d.mts +34 -2
- package/dist/index.d.ts +34 -2
- package/dist/index.js +62 -13
- package/dist/index.mjs +1 -1
- package/dist/mcp-config.js +62 -13
- package/dist/mcp-config.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,6 +29,8 @@ const plan = await signaliz.findEmail({
|
|
|
29
29
|
dryRun: true,
|
|
30
30
|
});
|
|
31
31
|
console.log(plan.estimatedCredits.max, plan.creditsCharged); // 2, 0
|
|
32
|
+
// Batch plans price only semantic unique work and expose duplicate suppression.
|
|
33
|
+
console.log(plan.inputCount, plan.uniqueFreshInputCount, plan.inputDuplicatesSuppressed);
|
|
32
34
|
|
|
33
35
|
const found = await signaliz.findEmail({
|
|
34
36
|
companyDomain: 'example.com',
|
|
@@ -111,8 +113,11 @@ when the REST API supplies them, including after automatic row retries are
|
|
|
111
113
|
exhausted.
|
|
112
114
|
|
|
113
115
|
For an ambiguous single request or batch submission failure, retry with the
|
|
114
|
-
same `idempotencyKey` to recover the original request
|
|
115
|
-
work.
|
|
116
|
+
same `idempotencyKey` to recover the original request, durable job, or provider
|
|
117
|
+
run without duplicate work or spend. The key is portable across REST API, MCP,
|
|
118
|
+
SDK, and CLI calls for the same workspace and logical input. Chunked batches
|
|
119
|
+
derive a stable key from each row's original input index, including after exact
|
|
120
|
+
duplicate compaction and rate-limit retries.
|
|
116
121
|
|
|
117
122
|
Each batch accepts up to 5,000 items. For the four row-oriented core products, batches larger
|
|
118
123
|
than 25 use one recoverable REST job; the SDK waits for completion and retrieves
|
|
@@ -536,7 +536,11 @@ var Signaliz = class {
|
|
|
536
536
|
request: signalToCopyRequestBody(params)
|
|
537
537
|
}));
|
|
538
538
|
const uniqueRequests = deduplicated.uniqueItems;
|
|
539
|
-
const
|
|
539
|
+
const uniqueInputIndices = new Array(uniqueRequests.length);
|
|
540
|
+
deduplicated.sourceIndexByInput.forEach((uniqueIndex, inputIndex) => {
|
|
541
|
+
if (uniqueInputIndices[uniqueIndex] === void 0) uniqueInputIndices[uniqueIndex] = inputIndex;
|
|
542
|
+
});
|
|
543
|
+
const uniqueResults = await this.runSignalCopyBatchChunks(uniqueRequests, options, uniqueInputIndices);
|
|
540
544
|
const results = requests.map((_, index) => ({
|
|
541
545
|
...uniqueResults[deduplicated.sourceIndexByInput[index]],
|
|
542
546
|
index
|
|
@@ -562,15 +566,25 @@ var Signaliz = class {
|
|
|
562
566
|
}
|
|
563
567
|
return normalizeCoreProductDryRunResult(data);
|
|
564
568
|
}
|
|
565
|
-
async runSignalCopyBatchChunks(uniqueRequests, options) {
|
|
569
|
+
async runSignalCopyBatchChunks(uniqueRequests, options, idempotencyItemIndices = uniqueRequests.map((_, index) => index)) {
|
|
566
570
|
const chunks = [];
|
|
567
571
|
for (let offset = 0; offset < uniqueRequests.length; offset += 25) {
|
|
568
|
-
chunks.push({
|
|
572
|
+
chunks.push({
|
|
573
|
+
offset,
|
|
574
|
+
requests: uniqueRequests.slice(offset, offset + 25),
|
|
575
|
+
idempotencyItemIndices: idempotencyItemIndices.slice(offset, offset + 25)
|
|
576
|
+
});
|
|
569
577
|
}
|
|
570
578
|
const { serverConcurrency, chunkConcurrency } = batchConcurrencyPlan(options, 25, 25);
|
|
571
579
|
const chunkBatch = await runBatch(
|
|
572
580
|
chunks,
|
|
573
|
-
(chunk) => this.runSignalCopyBatchChunk(
|
|
581
|
+
(chunk) => this.runSignalCopyBatchChunk(
|
|
582
|
+
chunk.requests,
|
|
583
|
+
serverConcurrency,
|
|
584
|
+
0,
|
|
585
|
+
options?.idempotencyKey,
|
|
586
|
+
chunk.idempotencyItemIndices
|
|
587
|
+
),
|
|
574
588
|
{ concurrency: chunkConcurrency }
|
|
575
589
|
);
|
|
576
590
|
const uniqueResults = new Array(uniqueRequests.length);
|
|
@@ -592,14 +606,15 @@ var Signaliz = class {
|
|
|
592
606
|
}
|
|
593
607
|
return uniqueResults;
|
|
594
608
|
}
|
|
595
|
-
async runRecoverableCoreBatchJob(path, requests, label, pageSize = 500, maxWaitMs = 20 * 6e4, idempotencyKey) {
|
|
609
|
+
async runRecoverableCoreBatchJob(path, requests, label, pageSize = 500, maxWaitMs = 20 * 6e4, idempotencyKey, idempotencyItemIndices) {
|
|
596
610
|
const startedAt = Date.now();
|
|
597
611
|
const submissionIdempotencyKey = idempotencyKey?.trim() || newBatchIdempotencyKey(label);
|
|
598
612
|
let submission;
|
|
599
613
|
try {
|
|
600
614
|
submission = await this.client.post(path, {
|
|
601
615
|
requests,
|
|
602
|
-
idempotency_key: submissionIdempotencyKey
|
|
616
|
+
idempotency_key: submissionIdempotencyKey,
|
|
617
|
+
batch_item_indices: idempotencyItemIndices
|
|
603
618
|
});
|
|
604
619
|
} catch (error) {
|
|
605
620
|
if (error instanceof SignalizError && !error.isRetryable) throw error;
|
|
@@ -662,12 +677,14 @@ var Signaliz = class {
|
|
|
662
677
|
if (seen.size !== requests.length) throw new Error(`${label} batch returned incomplete indexed results`);
|
|
663
678
|
return rows;
|
|
664
679
|
}
|
|
665
|
-
async runSignalCopyBatchChunk(requests, concurrency, rowRateLimitAttempt = 0) {
|
|
680
|
+
async runSignalCopyBatchChunk(requests, concurrency, rowRateLimitAttempt = 0, idempotencyKey, idempotencyItemIndices = requests.map((_, index) => index)) {
|
|
666
681
|
const results = new Array(requests.length);
|
|
667
682
|
const rateLimited = [];
|
|
668
683
|
const data = await this.client.post("api/v1/signal-to-copy", {
|
|
669
684
|
requests: requests.map(signalToCopyRequestBody),
|
|
670
|
-
concurrency
|
|
685
|
+
concurrency,
|
|
686
|
+
idempotency_key: idempotencyKey,
|
|
687
|
+
batch_item_indices: idempotencyItemIndices
|
|
671
688
|
});
|
|
672
689
|
if (!Array.isArray(data.results) || data.results.length !== requests.length) {
|
|
673
690
|
throw new Error("Signal to Copy batch returned an invalid result count");
|
|
@@ -702,7 +719,9 @@ var Signaliz = class {
|
|
|
702
719
|
const retried = await this.runSignalCopyBatchChunk(
|
|
703
720
|
rateLimited.map((item) => item.params),
|
|
704
721
|
concurrency,
|
|
705
|
-
rowRateLimitAttempt + 1
|
|
722
|
+
rowRateLimitAttempt + 1,
|
|
723
|
+
idempotencyKey,
|
|
724
|
+
rateLimited.map((item) => idempotencyItemIndices[item.index])
|
|
706
725
|
);
|
|
707
726
|
for (let index = 0; index < rateLimited.length; index += 1) {
|
|
708
727
|
results[rateLimited[index].index] = { ...retried[index], index: rateLimited[index].index };
|
|
@@ -722,7 +741,8 @@ var Signaliz = class {
|
|
|
722
741
|
recoverableBatch.label,
|
|
723
742
|
recoverableBatch.pageSize,
|
|
724
743
|
recoverableBatch.maxWaitMs,
|
|
725
|
-
options?.idempotencyKey
|
|
744
|
+
options?.idempotencyKey,
|
|
745
|
+
uniqueTasks.map((task) => task.index)
|
|
726
746
|
);
|
|
727
747
|
const uniqueResults2 = new Array(uniqueTasks.length);
|
|
728
748
|
for (const raw of rows) {
|
|
@@ -746,7 +766,9 @@ var Signaliz = class {
|
|
|
746
766
|
const chunkBatch = await runBatch(chunks, async (chunk) => {
|
|
747
767
|
const data = await this.client.post(path, {
|
|
748
768
|
requests: chunk.tasks.map((task) => task.request),
|
|
749
|
-
concurrency: serverConcurrency
|
|
769
|
+
concurrency: serverConcurrency,
|
|
770
|
+
idempotency_key: options?.idempotencyKey,
|
|
771
|
+
batch_item_indices: chunk.tasks.map((task) => task.index)
|
|
750
772
|
});
|
|
751
773
|
if (!Array.isArray(data.results) || data.results.length !== chunk.tasks.length) {
|
|
752
774
|
throw new Error(`${path} batch returned an invalid result count`);
|
|
@@ -881,7 +903,11 @@ function normalizeCoreProductDryRunResult(data) {
|
|
|
881
903
|
status: "planned",
|
|
882
904
|
capability: String(data.capability || ""),
|
|
883
905
|
inputCount: Number(data.input_count || 0),
|
|
906
|
+
freshInputCount: Number(data.fresh_input_count ?? data.input_count ?? 0),
|
|
907
|
+
uniqueFreshInputCount: Number(data.unique_fresh_input_count ?? data.fresh_input_count ?? data.input_count ?? 0),
|
|
908
|
+
inputDuplicatesSuppressed: Number(data.input_duplicates_suppressed || 0),
|
|
884
909
|
recoveryReadCount: Number(data.recovery_read_count || 0),
|
|
910
|
+
uniqueRecoveryReadCount: Number(data.unique_recovery_read_count ?? data.recovery_read_count ?? 0),
|
|
885
911
|
plan: data.plan && typeof data.plan === "object" ? data.plan : {},
|
|
886
912
|
estimate: data.estimate && typeof data.estimate === "object" ? data.estimate : {},
|
|
887
913
|
estimatedCredits: {
|
|
@@ -896,12 +922,12 @@ function normalizeCoreProductDryRunResult(data) {
|
|
|
896
922
|
function normalizeFindEmailResult(data) {
|
|
897
923
|
const email = typeof data.email === "string" && data.email.trim() ? data.email.trim() : null;
|
|
898
924
|
const found = Boolean(email) && data.found !== false;
|
|
899
|
-
const verificationStatus = data.verification_status ?? data.status ?? "unknown";
|
|
925
|
+
const verificationStatus = data.verification_status ?? (data.is_valid === true ? "valid" : data.status ?? "unknown");
|
|
900
926
|
const rawFreshness = String(data.verification_freshness ?? "").toLowerCase();
|
|
901
927
|
const verificationFreshness = rawFreshness === "fresh" || rawFreshness === "stale" ? rawFreshness : "unknown";
|
|
902
928
|
const needsReverification = data.needs_reverification === true || verificationFreshness === "stale";
|
|
903
929
|
const explicitlyNotSendSafe = data.verified_for_sending === false || needsReverification;
|
|
904
|
-
const verified = !explicitlyNotSendSafe && (data.email_verified === true || data.verified_for_sending === true || ["valid", "deliverable"].includes(String(verificationStatus).toLowerCase()));
|
|
930
|
+
const verified = !explicitlyNotSendSafe && (data.is_valid === true || data.isValid === true || data.email_verified === true || data.verified_for_sending === true || ["valid", "deliverable"].includes(String(verificationStatus).toLowerCase()));
|
|
905
931
|
const verificationAgeDays = typeof data.verification_age_days === "number" && Number.isFinite(data.verification_age_days) ? data.verification_age_days : null;
|
|
906
932
|
return {
|
|
907
933
|
success: data.success !== false && found,
|
|
@@ -924,6 +950,9 @@ function normalizeFindEmailResult(data) {
|
|
|
924
950
|
billingMetadata: data.billing_metadata,
|
|
925
951
|
resultReturnedFrom: data.result_returned_from,
|
|
926
952
|
cacheHit: data.cache_hit,
|
|
953
|
+
negativeCacheHit: data.negative_cache_hit,
|
|
954
|
+
negativeCacheTtlSeconds: data.negative_cache_ttl_seconds,
|
|
955
|
+
cacheTier: data.cache_tier,
|
|
927
956
|
freshEnrichmentUsed: data.fresh_enrichment_used,
|
|
928
957
|
liveProviderCalled: data.live_provider_called,
|
|
929
958
|
openrouterCalled: data.openrouter_called,
|
|
@@ -945,6 +974,7 @@ function normalizeVerifyEmailResult(email, data) {
|
|
|
945
974
|
nextPollAfterSeconds: data.next_poll_after_seconds,
|
|
946
975
|
isValid: data.is_valid ?? data.valid ?? verified,
|
|
947
976
|
isDeliverable: data.is_deliverable ?? data.deliverable ?? verified,
|
|
977
|
+
isMalformed: data.is_malformed === true || data.verification_verdict === "malformed" || data.verification_status === "malformed" || data.deliverability_status === "malformed",
|
|
948
978
|
isCatchAll: data.email_is_catch_all ?? data.is_catch_all ?? data.catch_all ?? data.diagnostics?.is_catch_all ?? false,
|
|
949
979
|
verifiedForSending: data.verified_for_sending === true,
|
|
950
980
|
verificationVerdict: data.verification_verdict ?? data.verification_status ?? "unknown",
|
|
@@ -956,6 +986,9 @@ function normalizeVerifyEmailResult(email, data) {
|
|
|
956
986
|
billingMetadata: data.billing_metadata,
|
|
957
987
|
resultReturnedFrom: data.result_returned_from,
|
|
958
988
|
cacheHit: data.cache_hit,
|
|
989
|
+
negativeCacheHit: data.negative_cache_hit,
|
|
990
|
+
negativeCacheTtlSeconds: data.negative_cache_ttl_seconds,
|
|
991
|
+
cacheTier: data.cache_tier,
|
|
959
992
|
freshEnrichmentUsed: data.fresh_enrichment_used,
|
|
960
993
|
liveProviderCalled: data.live_provider_called,
|
|
961
994
|
openrouterCalled: data.openrouter_called,
|
|
@@ -1025,6 +1058,14 @@ function normalizeCompanySignalResult(params, data) {
|
|
|
1025
1058
|
evidenceCountTotal: data.evidence_count_total,
|
|
1026
1059
|
evidenceSourcesOmitted: data.evidence_sources_omitted,
|
|
1027
1060
|
evidenceScope: data.evidence_scope,
|
|
1061
|
+
billingMetadata: data.billing_metadata,
|
|
1062
|
+
resultReturnedFrom: data.result_returned_from,
|
|
1063
|
+
cacheHit: data.cache_hit,
|
|
1064
|
+
freshEnrichmentUsed: data.fresh_enrichment_used,
|
|
1065
|
+
creditsUsed: data.credits_used,
|
|
1066
|
+
liveProviderCalled: data.live_provider_called,
|
|
1067
|
+
aiProviderCalled: data.ai_provider_called,
|
|
1068
|
+
byoAiUsed: data.byo_ai_used,
|
|
1028
1069
|
raw: data
|
|
1029
1070
|
};
|
|
1030
1071
|
}
|
|
@@ -1302,6 +1343,14 @@ function normalizeSignalToCopyResult(data) {
|
|
|
1302
1343
|
empty: data.empty,
|
|
1303
1344
|
emptyReason: data.empty_reason,
|
|
1304
1345
|
researchMetadata: data.research_metadata,
|
|
1346
|
+
billingMetadata: data.billing_metadata,
|
|
1347
|
+
resultReturnedFrom: data.result_returned_from,
|
|
1348
|
+
cacheHit: data.cache_hit,
|
|
1349
|
+
freshEnrichmentUsed: data.fresh_enrichment_used,
|
|
1350
|
+
creditsUsed: data.credits_used,
|
|
1351
|
+
liveProviderCalled: data.live_provider_called,
|
|
1352
|
+
aiProviderCalled: data.ai_provider_called,
|
|
1353
|
+
byoAiUsed: data.byo_ai_used,
|
|
1305
1354
|
variations: (data.variations ?? []).map((variation) => ({
|
|
1306
1355
|
style: variation.style,
|
|
1307
1356
|
subjectLine: variation.subject_line ?? "",
|
package/dist/index.d.mts
CHANGED
|
@@ -9,7 +9,7 @@ interface SignalizConfig {
|
|
|
9
9
|
interface BatchOptions {
|
|
10
10
|
/** Maximum simultaneous API requests. Defaults to 10; allowed range is 1-50. */
|
|
11
11
|
concurrency?: number;
|
|
12
|
-
/** Stable key
|
|
12
|
+
/** Stable cross-surface key. Retries reuse the same provider work; chunked batches derive one collision-free key per original row. */
|
|
13
13
|
idempotencyKey?: string;
|
|
14
14
|
/** Return exact repeated successes as duplicateOf references. Defaults to false. */
|
|
15
15
|
compactDuplicates?: boolean;
|
|
@@ -51,7 +51,11 @@ interface CoreProductDryRunResult {
|
|
|
51
51
|
status: 'planned';
|
|
52
52
|
capability: string;
|
|
53
53
|
inputCount: number;
|
|
54
|
+
freshInputCount: number;
|
|
55
|
+
uniqueFreshInputCount: number;
|
|
56
|
+
inputDuplicatesSuppressed: number;
|
|
54
57
|
recoveryReadCount: number;
|
|
58
|
+
uniqueRecoveryReadCount: number;
|
|
55
59
|
plan: Record<string, unknown>;
|
|
56
60
|
estimate: Record<string, unknown>;
|
|
57
61
|
estimatedCredits: {
|
|
@@ -97,6 +101,11 @@ interface FindEmailResult {
|
|
|
97
101
|
billingMetadata?: Record<string, unknown>;
|
|
98
102
|
resultReturnedFrom?: string;
|
|
99
103
|
cacheHit?: boolean;
|
|
104
|
+
/** True when a definitive no-email result came from the short-lived negative cache. */
|
|
105
|
+
negativeCacheHit?: boolean;
|
|
106
|
+
/** Remaining lifetime of the negative cache entry. */
|
|
107
|
+
negativeCacheTtlSeconds?: number;
|
|
108
|
+
cacheTier?: string;
|
|
100
109
|
freshEnrichmentUsed?: boolean;
|
|
101
110
|
liveProviderCalled?: boolean;
|
|
102
111
|
openrouterCalled?: boolean;
|
|
@@ -116,6 +125,8 @@ interface VerifyEmailResult {
|
|
|
116
125
|
nextPollAfterSeconds?: number;
|
|
117
126
|
isValid: boolean;
|
|
118
127
|
isDeliverable: boolean;
|
|
128
|
+
/** True when the address failed syntax validation before any provider call. */
|
|
129
|
+
isMalformed: boolean;
|
|
119
130
|
isCatchAll: boolean;
|
|
120
131
|
/** Explicit send-safety verdict. Missing or false never becomes true by inference. */
|
|
121
132
|
verifiedForSending: boolean;
|
|
@@ -128,6 +139,11 @@ interface VerifyEmailResult {
|
|
|
128
139
|
billingMetadata?: Record<string, unknown>;
|
|
129
140
|
resultReturnedFrom?: string;
|
|
130
141
|
cacheHit?: boolean;
|
|
142
|
+
/** True when a conclusive send-blocking verdict came from the short-lived rejection cache. */
|
|
143
|
+
negativeCacheHit?: boolean;
|
|
144
|
+
/** Remaining lifetime of the rejection cache entry. */
|
|
145
|
+
negativeCacheTtlSeconds?: number;
|
|
146
|
+
cacheTier?: string;
|
|
131
147
|
freshEnrichmentUsed?: boolean;
|
|
132
148
|
liveProviderCalled?: boolean;
|
|
133
149
|
openrouterCalled?: boolean;
|
|
@@ -217,6 +233,14 @@ interface CompanySignalEnrichmentResult {
|
|
|
217
233
|
evidenceCountTotal?: number;
|
|
218
234
|
evidenceSourcesOmitted?: number;
|
|
219
235
|
evidenceScope?: 'selected_signals' | 'all_candidates';
|
|
236
|
+
billingMetadata?: Record<string, unknown>;
|
|
237
|
+
resultReturnedFrom?: string;
|
|
238
|
+
cacheHit?: boolean;
|
|
239
|
+
freshEnrichmentUsed?: boolean;
|
|
240
|
+
creditsUsed?: number;
|
|
241
|
+
liveProviderCalled?: boolean;
|
|
242
|
+
aiProviderCalled?: boolean;
|
|
243
|
+
byoAiUsed?: boolean;
|
|
220
244
|
raw: Record<string, unknown>;
|
|
221
245
|
}
|
|
222
246
|
type SignalDiscoverySource = 'web' | 'news';
|
|
@@ -311,7 +335,7 @@ interface SignalToCopyParams {
|
|
|
311
335
|
signalRunId?: string;
|
|
312
336
|
/** Bypass cached company signals and start fresh research. */
|
|
313
337
|
skipCache?: boolean;
|
|
314
|
-
/**
|
|
338
|
+
/** Use the full deep-research provider portfolio. The default uses bounded credit-free first-party and Bing grounding. */
|
|
315
339
|
enableDeepSearch?: boolean;
|
|
316
340
|
/** @deprecated Signal to Copy is always synchronous; this option is ignored. */
|
|
317
341
|
waitForResult?: boolean;
|
|
@@ -346,6 +370,14 @@ interface SignalToCopyResult {
|
|
|
346
370
|
empty?: boolean;
|
|
347
371
|
emptyReason?: string;
|
|
348
372
|
researchMetadata?: Record<string, unknown>;
|
|
373
|
+
billingMetadata?: Record<string, unknown>;
|
|
374
|
+
resultReturnedFrom?: string;
|
|
375
|
+
cacheHit?: boolean;
|
|
376
|
+
freshEnrichmentUsed?: boolean;
|
|
377
|
+
creditsUsed?: number;
|
|
378
|
+
liveProviderCalled?: boolean;
|
|
379
|
+
aiProviderCalled?: boolean;
|
|
380
|
+
byoAiUsed?: boolean;
|
|
349
381
|
variations: SignalToCopyVariation[];
|
|
350
382
|
raw: Record<string, unknown>;
|
|
351
383
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ interface SignalizConfig {
|
|
|
9
9
|
interface BatchOptions {
|
|
10
10
|
/** Maximum simultaneous API requests. Defaults to 10; allowed range is 1-50. */
|
|
11
11
|
concurrency?: number;
|
|
12
|
-
/** Stable key
|
|
12
|
+
/** Stable cross-surface key. Retries reuse the same provider work; chunked batches derive one collision-free key per original row. */
|
|
13
13
|
idempotencyKey?: string;
|
|
14
14
|
/** Return exact repeated successes as duplicateOf references. Defaults to false. */
|
|
15
15
|
compactDuplicates?: boolean;
|
|
@@ -51,7 +51,11 @@ interface CoreProductDryRunResult {
|
|
|
51
51
|
status: 'planned';
|
|
52
52
|
capability: string;
|
|
53
53
|
inputCount: number;
|
|
54
|
+
freshInputCount: number;
|
|
55
|
+
uniqueFreshInputCount: number;
|
|
56
|
+
inputDuplicatesSuppressed: number;
|
|
54
57
|
recoveryReadCount: number;
|
|
58
|
+
uniqueRecoveryReadCount: number;
|
|
55
59
|
plan: Record<string, unknown>;
|
|
56
60
|
estimate: Record<string, unknown>;
|
|
57
61
|
estimatedCredits: {
|
|
@@ -97,6 +101,11 @@ interface FindEmailResult {
|
|
|
97
101
|
billingMetadata?: Record<string, unknown>;
|
|
98
102
|
resultReturnedFrom?: string;
|
|
99
103
|
cacheHit?: boolean;
|
|
104
|
+
/** True when a definitive no-email result came from the short-lived negative cache. */
|
|
105
|
+
negativeCacheHit?: boolean;
|
|
106
|
+
/** Remaining lifetime of the negative cache entry. */
|
|
107
|
+
negativeCacheTtlSeconds?: number;
|
|
108
|
+
cacheTier?: string;
|
|
100
109
|
freshEnrichmentUsed?: boolean;
|
|
101
110
|
liveProviderCalled?: boolean;
|
|
102
111
|
openrouterCalled?: boolean;
|
|
@@ -116,6 +125,8 @@ interface VerifyEmailResult {
|
|
|
116
125
|
nextPollAfterSeconds?: number;
|
|
117
126
|
isValid: boolean;
|
|
118
127
|
isDeliverable: boolean;
|
|
128
|
+
/** True when the address failed syntax validation before any provider call. */
|
|
129
|
+
isMalformed: boolean;
|
|
119
130
|
isCatchAll: boolean;
|
|
120
131
|
/** Explicit send-safety verdict. Missing or false never becomes true by inference. */
|
|
121
132
|
verifiedForSending: boolean;
|
|
@@ -128,6 +139,11 @@ interface VerifyEmailResult {
|
|
|
128
139
|
billingMetadata?: Record<string, unknown>;
|
|
129
140
|
resultReturnedFrom?: string;
|
|
130
141
|
cacheHit?: boolean;
|
|
142
|
+
/** True when a conclusive send-blocking verdict came from the short-lived rejection cache. */
|
|
143
|
+
negativeCacheHit?: boolean;
|
|
144
|
+
/** Remaining lifetime of the rejection cache entry. */
|
|
145
|
+
negativeCacheTtlSeconds?: number;
|
|
146
|
+
cacheTier?: string;
|
|
131
147
|
freshEnrichmentUsed?: boolean;
|
|
132
148
|
liveProviderCalled?: boolean;
|
|
133
149
|
openrouterCalled?: boolean;
|
|
@@ -217,6 +233,14 @@ interface CompanySignalEnrichmentResult {
|
|
|
217
233
|
evidenceCountTotal?: number;
|
|
218
234
|
evidenceSourcesOmitted?: number;
|
|
219
235
|
evidenceScope?: 'selected_signals' | 'all_candidates';
|
|
236
|
+
billingMetadata?: Record<string, unknown>;
|
|
237
|
+
resultReturnedFrom?: string;
|
|
238
|
+
cacheHit?: boolean;
|
|
239
|
+
freshEnrichmentUsed?: boolean;
|
|
240
|
+
creditsUsed?: number;
|
|
241
|
+
liveProviderCalled?: boolean;
|
|
242
|
+
aiProviderCalled?: boolean;
|
|
243
|
+
byoAiUsed?: boolean;
|
|
220
244
|
raw: Record<string, unknown>;
|
|
221
245
|
}
|
|
222
246
|
type SignalDiscoverySource = 'web' | 'news';
|
|
@@ -311,7 +335,7 @@ interface SignalToCopyParams {
|
|
|
311
335
|
signalRunId?: string;
|
|
312
336
|
/** Bypass cached company signals and start fresh research. */
|
|
313
337
|
skipCache?: boolean;
|
|
314
|
-
/**
|
|
338
|
+
/** Use the full deep-research provider portfolio. The default uses bounded credit-free first-party and Bing grounding. */
|
|
315
339
|
enableDeepSearch?: boolean;
|
|
316
340
|
/** @deprecated Signal to Copy is always synchronous; this option is ignored. */
|
|
317
341
|
waitForResult?: boolean;
|
|
@@ -346,6 +370,14 @@ interface SignalToCopyResult {
|
|
|
346
370
|
empty?: boolean;
|
|
347
371
|
emptyReason?: string;
|
|
348
372
|
researchMetadata?: Record<string, unknown>;
|
|
373
|
+
billingMetadata?: Record<string, unknown>;
|
|
374
|
+
resultReturnedFrom?: string;
|
|
375
|
+
cacheHit?: boolean;
|
|
376
|
+
freshEnrichmentUsed?: boolean;
|
|
377
|
+
creditsUsed?: number;
|
|
378
|
+
liveProviderCalled?: boolean;
|
|
379
|
+
aiProviderCalled?: boolean;
|
|
380
|
+
byoAiUsed?: boolean;
|
|
349
381
|
variations: SignalToCopyVariation[];
|
|
350
382
|
raw: Record<string, unknown>;
|
|
351
383
|
}
|
package/dist/index.js
CHANGED
|
@@ -563,7 +563,11 @@ var Signaliz = class {
|
|
|
563
563
|
request: signalToCopyRequestBody(params)
|
|
564
564
|
}));
|
|
565
565
|
const uniqueRequests = deduplicated.uniqueItems;
|
|
566
|
-
const
|
|
566
|
+
const uniqueInputIndices = new Array(uniqueRequests.length);
|
|
567
|
+
deduplicated.sourceIndexByInput.forEach((uniqueIndex, inputIndex) => {
|
|
568
|
+
if (uniqueInputIndices[uniqueIndex] === void 0) uniqueInputIndices[uniqueIndex] = inputIndex;
|
|
569
|
+
});
|
|
570
|
+
const uniqueResults = await this.runSignalCopyBatchChunks(uniqueRequests, options, uniqueInputIndices);
|
|
567
571
|
const results = requests.map((_, index) => ({
|
|
568
572
|
...uniqueResults[deduplicated.sourceIndexByInput[index]],
|
|
569
573
|
index
|
|
@@ -589,15 +593,25 @@ var Signaliz = class {
|
|
|
589
593
|
}
|
|
590
594
|
return normalizeCoreProductDryRunResult(data);
|
|
591
595
|
}
|
|
592
|
-
async runSignalCopyBatchChunks(uniqueRequests, options) {
|
|
596
|
+
async runSignalCopyBatchChunks(uniqueRequests, options, idempotencyItemIndices = uniqueRequests.map((_, index) => index)) {
|
|
593
597
|
const chunks = [];
|
|
594
598
|
for (let offset = 0; offset < uniqueRequests.length; offset += 25) {
|
|
595
|
-
chunks.push({
|
|
599
|
+
chunks.push({
|
|
600
|
+
offset,
|
|
601
|
+
requests: uniqueRequests.slice(offset, offset + 25),
|
|
602
|
+
idempotencyItemIndices: idempotencyItemIndices.slice(offset, offset + 25)
|
|
603
|
+
});
|
|
596
604
|
}
|
|
597
605
|
const { serverConcurrency, chunkConcurrency } = batchConcurrencyPlan(options, 25, 25);
|
|
598
606
|
const chunkBatch = await runBatch(
|
|
599
607
|
chunks,
|
|
600
|
-
(chunk) => this.runSignalCopyBatchChunk(
|
|
608
|
+
(chunk) => this.runSignalCopyBatchChunk(
|
|
609
|
+
chunk.requests,
|
|
610
|
+
serverConcurrency,
|
|
611
|
+
0,
|
|
612
|
+
options?.idempotencyKey,
|
|
613
|
+
chunk.idempotencyItemIndices
|
|
614
|
+
),
|
|
601
615
|
{ concurrency: chunkConcurrency }
|
|
602
616
|
);
|
|
603
617
|
const uniqueResults = new Array(uniqueRequests.length);
|
|
@@ -619,14 +633,15 @@ var Signaliz = class {
|
|
|
619
633
|
}
|
|
620
634
|
return uniqueResults;
|
|
621
635
|
}
|
|
622
|
-
async runRecoverableCoreBatchJob(path, requests, label, pageSize = 500, maxWaitMs = 20 * 6e4, idempotencyKey) {
|
|
636
|
+
async runRecoverableCoreBatchJob(path, requests, label, pageSize = 500, maxWaitMs = 20 * 6e4, idempotencyKey, idempotencyItemIndices) {
|
|
623
637
|
const startedAt = Date.now();
|
|
624
638
|
const submissionIdempotencyKey = idempotencyKey?.trim() || newBatchIdempotencyKey(label);
|
|
625
639
|
let submission;
|
|
626
640
|
try {
|
|
627
641
|
submission = await this.client.post(path, {
|
|
628
642
|
requests,
|
|
629
|
-
idempotency_key: submissionIdempotencyKey
|
|
643
|
+
idempotency_key: submissionIdempotencyKey,
|
|
644
|
+
batch_item_indices: idempotencyItemIndices
|
|
630
645
|
});
|
|
631
646
|
} catch (error) {
|
|
632
647
|
if (error instanceof SignalizError && !error.isRetryable) throw error;
|
|
@@ -689,12 +704,14 @@ var Signaliz = class {
|
|
|
689
704
|
if (seen.size !== requests.length) throw new Error(`${label} batch returned incomplete indexed results`);
|
|
690
705
|
return rows;
|
|
691
706
|
}
|
|
692
|
-
async runSignalCopyBatchChunk(requests, concurrency, rowRateLimitAttempt = 0) {
|
|
707
|
+
async runSignalCopyBatchChunk(requests, concurrency, rowRateLimitAttempt = 0, idempotencyKey, idempotencyItemIndices = requests.map((_, index) => index)) {
|
|
693
708
|
const results = new Array(requests.length);
|
|
694
709
|
const rateLimited = [];
|
|
695
710
|
const data = await this.client.post("api/v1/signal-to-copy", {
|
|
696
711
|
requests: requests.map(signalToCopyRequestBody),
|
|
697
|
-
concurrency
|
|
712
|
+
concurrency,
|
|
713
|
+
idempotency_key: idempotencyKey,
|
|
714
|
+
batch_item_indices: idempotencyItemIndices
|
|
698
715
|
});
|
|
699
716
|
if (!Array.isArray(data.results) || data.results.length !== requests.length) {
|
|
700
717
|
throw new Error("Signal to Copy batch returned an invalid result count");
|
|
@@ -729,7 +746,9 @@ var Signaliz = class {
|
|
|
729
746
|
const retried = await this.runSignalCopyBatchChunk(
|
|
730
747
|
rateLimited.map((item) => item.params),
|
|
731
748
|
concurrency,
|
|
732
|
-
rowRateLimitAttempt + 1
|
|
749
|
+
rowRateLimitAttempt + 1,
|
|
750
|
+
idempotencyKey,
|
|
751
|
+
rateLimited.map((item) => idempotencyItemIndices[item.index])
|
|
733
752
|
);
|
|
734
753
|
for (let index = 0; index < rateLimited.length; index += 1) {
|
|
735
754
|
results[rateLimited[index].index] = { ...retried[index], index: rateLimited[index].index };
|
|
@@ -749,7 +768,8 @@ var Signaliz = class {
|
|
|
749
768
|
recoverableBatch.label,
|
|
750
769
|
recoverableBatch.pageSize,
|
|
751
770
|
recoverableBatch.maxWaitMs,
|
|
752
|
-
options?.idempotencyKey
|
|
771
|
+
options?.idempotencyKey,
|
|
772
|
+
uniqueTasks.map((task) => task.index)
|
|
753
773
|
);
|
|
754
774
|
const uniqueResults2 = new Array(uniqueTasks.length);
|
|
755
775
|
for (const raw of rows) {
|
|
@@ -773,7 +793,9 @@ var Signaliz = class {
|
|
|
773
793
|
const chunkBatch = await runBatch(chunks, async (chunk) => {
|
|
774
794
|
const data = await this.client.post(path, {
|
|
775
795
|
requests: chunk.tasks.map((task) => task.request),
|
|
776
|
-
concurrency: serverConcurrency
|
|
796
|
+
concurrency: serverConcurrency,
|
|
797
|
+
idempotency_key: options?.idempotencyKey,
|
|
798
|
+
batch_item_indices: chunk.tasks.map((task) => task.index)
|
|
777
799
|
});
|
|
778
800
|
if (!Array.isArray(data.results) || data.results.length !== chunk.tasks.length) {
|
|
779
801
|
throw new Error(`${path} batch returned an invalid result count`);
|
|
@@ -908,7 +930,11 @@ function normalizeCoreProductDryRunResult(data) {
|
|
|
908
930
|
status: "planned",
|
|
909
931
|
capability: String(data.capability || ""),
|
|
910
932
|
inputCount: Number(data.input_count || 0),
|
|
933
|
+
freshInputCount: Number(data.fresh_input_count ?? data.input_count ?? 0),
|
|
934
|
+
uniqueFreshInputCount: Number(data.unique_fresh_input_count ?? data.fresh_input_count ?? data.input_count ?? 0),
|
|
935
|
+
inputDuplicatesSuppressed: Number(data.input_duplicates_suppressed || 0),
|
|
911
936
|
recoveryReadCount: Number(data.recovery_read_count || 0),
|
|
937
|
+
uniqueRecoveryReadCount: Number(data.unique_recovery_read_count ?? data.recovery_read_count ?? 0),
|
|
912
938
|
plan: data.plan && typeof data.plan === "object" ? data.plan : {},
|
|
913
939
|
estimate: data.estimate && typeof data.estimate === "object" ? data.estimate : {},
|
|
914
940
|
estimatedCredits: {
|
|
@@ -923,12 +949,12 @@ function normalizeCoreProductDryRunResult(data) {
|
|
|
923
949
|
function normalizeFindEmailResult(data) {
|
|
924
950
|
const email = typeof data.email === "string" && data.email.trim() ? data.email.trim() : null;
|
|
925
951
|
const found = Boolean(email) && data.found !== false;
|
|
926
|
-
const verificationStatus = data.verification_status ?? data.status ?? "unknown";
|
|
952
|
+
const verificationStatus = data.verification_status ?? (data.is_valid === true ? "valid" : data.status ?? "unknown");
|
|
927
953
|
const rawFreshness = String(data.verification_freshness ?? "").toLowerCase();
|
|
928
954
|
const verificationFreshness = rawFreshness === "fresh" || rawFreshness === "stale" ? rawFreshness : "unknown";
|
|
929
955
|
const needsReverification = data.needs_reverification === true || verificationFreshness === "stale";
|
|
930
956
|
const explicitlyNotSendSafe = data.verified_for_sending === false || needsReverification;
|
|
931
|
-
const verified = !explicitlyNotSendSafe && (data.email_verified === true || data.verified_for_sending === true || ["valid", "deliverable"].includes(String(verificationStatus).toLowerCase()));
|
|
957
|
+
const verified = !explicitlyNotSendSafe && (data.is_valid === true || data.isValid === true || data.email_verified === true || data.verified_for_sending === true || ["valid", "deliverable"].includes(String(verificationStatus).toLowerCase()));
|
|
932
958
|
const verificationAgeDays = typeof data.verification_age_days === "number" && Number.isFinite(data.verification_age_days) ? data.verification_age_days : null;
|
|
933
959
|
return {
|
|
934
960
|
success: data.success !== false && found,
|
|
@@ -951,6 +977,9 @@ function normalizeFindEmailResult(data) {
|
|
|
951
977
|
billingMetadata: data.billing_metadata,
|
|
952
978
|
resultReturnedFrom: data.result_returned_from,
|
|
953
979
|
cacheHit: data.cache_hit,
|
|
980
|
+
negativeCacheHit: data.negative_cache_hit,
|
|
981
|
+
negativeCacheTtlSeconds: data.negative_cache_ttl_seconds,
|
|
982
|
+
cacheTier: data.cache_tier,
|
|
954
983
|
freshEnrichmentUsed: data.fresh_enrichment_used,
|
|
955
984
|
liveProviderCalled: data.live_provider_called,
|
|
956
985
|
openrouterCalled: data.openrouter_called,
|
|
@@ -972,6 +1001,7 @@ function normalizeVerifyEmailResult(email, data) {
|
|
|
972
1001
|
nextPollAfterSeconds: data.next_poll_after_seconds,
|
|
973
1002
|
isValid: data.is_valid ?? data.valid ?? verified,
|
|
974
1003
|
isDeliverable: data.is_deliverable ?? data.deliverable ?? verified,
|
|
1004
|
+
isMalformed: data.is_malformed === true || data.verification_verdict === "malformed" || data.verification_status === "malformed" || data.deliverability_status === "malformed",
|
|
975
1005
|
isCatchAll: data.email_is_catch_all ?? data.is_catch_all ?? data.catch_all ?? data.diagnostics?.is_catch_all ?? false,
|
|
976
1006
|
verifiedForSending: data.verified_for_sending === true,
|
|
977
1007
|
verificationVerdict: data.verification_verdict ?? data.verification_status ?? "unknown",
|
|
@@ -983,6 +1013,9 @@ function normalizeVerifyEmailResult(email, data) {
|
|
|
983
1013
|
billingMetadata: data.billing_metadata,
|
|
984
1014
|
resultReturnedFrom: data.result_returned_from,
|
|
985
1015
|
cacheHit: data.cache_hit,
|
|
1016
|
+
negativeCacheHit: data.negative_cache_hit,
|
|
1017
|
+
negativeCacheTtlSeconds: data.negative_cache_ttl_seconds,
|
|
1018
|
+
cacheTier: data.cache_tier,
|
|
986
1019
|
freshEnrichmentUsed: data.fresh_enrichment_used,
|
|
987
1020
|
liveProviderCalled: data.live_provider_called,
|
|
988
1021
|
openrouterCalled: data.openrouter_called,
|
|
@@ -1052,6 +1085,14 @@ function normalizeCompanySignalResult(params, data) {
|
|
|
1052
1085
|
evidenceCountTotal: data.evidence_count_total,
|
|
1053
1086
|
evidenceSourcesOmitted: data.evidence_sources_omitted,
|
|
1054
1087
|
evidenceScope: data.evidence_scope,
|
|
1088
|
+
billingMetadata: data.billing_metadata,
|
|
1089
|
+
resultReturnedFrom: data.result_returned_from,
|
|
1090
|
+
cacheHit: data.cache_hit,
|
|
1091
|
+
freshEnrichmentUsed: data.fresh_enrichment_used,
|
|
1092
|
+
creditsUsed: data.credits_used,
|
|
1093
|
+
liveProviderCalled: data.live_provider_called,
|
|
1094
|
+
aiProviderCalled: data.ai_provider_called,
|
|
1095
|
+
byoAiUsed: data.byo_ai_used,
|
|
1055
1096
|
raw: data
|
|
1056
1097
|
};
|
|
1057
1098
|
}
|
|
@@ -1329,6 +1370,14 @@ function normalizeSignalToCopyResult(data) {
|
|
|
1329
1370
|
empty: data.empty,
|
|
1330
1371
|
emptyReason: data.empty_reason,
|
|
1331
1372
|
researchMetadata: data.research_metadata,
|
|
1373
|
+
billingMetadata: data.billing_metadata,
|
|
1374
|
+
resultReturnedFrom: data.result_returned_from,
|
|
1375
|
+
cacheHit: data.cache_hit,
|
|
1376
|
+
freshEnrichmentUsed: data.fresh_enrichment_used,
|
|
1377
|
+
creditsUsed: data.credits_used,
|
|
1378
|
+
liveProviderCalled: data.live_provider_called,
|
|
1379
|
+
aiProviderCalled: data.ai_provider_called,
|
|
1380
|
+
byoAiUsed: data.byo_ai_used,
|
|
1332
1381
|
variations: (data.variations ?? []).map((variation) => ({
|
|
1333
1382
|
style: variation.style,
|
|
1334
1383
|
subjectLine: variation.subject_line ?? "",
|
package/dist/index.mjs
CHANGED
package/dist/mcp-config.js
CHANGED
|
@@ -567,7 +567,11 @@ var Signaliz = class {
|
|
|
567
567
|
request: signalToCopyRequestBody(params)
|
|
568
568
|
}));
|
|
569
569
|
const uniqueRequests = deduplicated.uniqueItems;
|
|
570
|
-
const
|
|
570
|
+
const uniqueInputIndices = new Array(uniqueRequests.length);
|
|
571
|
+
deduplicated.sourceIndexByInput.forEach((uniqueIndex, inputIndex) => {
|
|
572
|
+
if (uniqueInputIndices[uniqueIndex] === void 0) uniqueInputIndices[uniqueIndex] = inputIndex;
|
|
573
|
+
});
|
|
574
|
+
const uniqueResults = await this.runSignalCopyBatchChunks(uniqueRequests, options, uniqueInputIndices);
|
|
571
575
|
const results = requests.map((_, index) => ({
|
|
572
576
|
...uniqueResults[deduplicated.sourceIndexByInput[index]],
|
|
573
577
|
index
|
|
@@ -593,15 +597,25 @@ var Signaliz = class {
|
|
|
593
597
|
}
|
|
594
598
|
return normalizeCoreProductDryRunResult(data);
|
|
595
599
|
}
|
|
596
|
-
async runSignalCopyBatchChunks(uniqueRequests, options) {
|
|
600
|
+
async runSignalCopyBatchChunks(uniqueRequests, options, idempotencyItemIndices = uniqueRequests.map((_, index) => index)) {
|
|
597
601
|
const chunks = [];
|
|
598
602
|
for (let offset = 0; offset < uniqueRequests.length; offset += 25) {
|
|
599
|
-
chunks.push({
|
|
603
|
+
chunks.push({
|
|
604
|
+
offset,
|
|
605
|
+
requests: uniqueRequests.slice(offset, offset + 25),
|
|
606
|
+
idempotencyItemIndices: idempotencyItemIndices.slice(offset, offset + 25)
|
|
607
|
+
});
|
|
600
608
|
}
|
|
601
609
|
const { serverConcurrency, chunkConcurrency } = batchConcurrencyPlan(options, 25, 25);
|
|
602
610
|
const chunkBatch = await runBatch(
|
|
603
611
|
chunks,
|
|
604
|
-
(chunk) => this.runSignalCopyBatchChunk(
|
|
612
|
+
(chunk) => this.runSignalCopyBatchChunk(
|
|
613
|
+
chunk.requests,
|
|
614
|
+
serverConcurrency,
|
|
615
|
+
0,
|
|
616
|
+
options?.idempotencyKey,
|
|
617
|
+
chunk.idempotencyItemIndices
|
|
618
|
+
),
|
|
605
619
|
{ concurrency: chunkConcurrency }
|
|
606
620
|
);
|
|
607
621
|
const uniqueResults = new Array(uniqueRequests.length);
|
|
@@ -623,14 +637,15 @@ var Signaliz = class {
|
|
|
623
637
|
}
|
|
624
638
|
return uniqueResults;
|
|
625
639
|
}
|
|
626
|
-
async runRecoverableCoreBatchJob(path2, requests, label, pageSize = 500, maxWaitMs = 20 * 6e4, idempotencyKey) {
|
|
640
|
+
async runRecoverableCoreBatchJob(path2, requests, label, pageSize = 500, maxWaitMs = 20 * 6e4, idempotencyKey, idempotencyItemIndices) {
|
|
627
641
|
const startedAt = Date.now();
|
|
628
642
|
const submissionIdempotencyKey = idempotencyKey?.trim() || newBatchIdempotencyKey(label);
|
|
629
643
|
let submission;
|
|
630
644
|
try {
|
|
631
645
|
submission = await this.client.post(path2, {
|
|
632
646
|
requests,
|
|
633
|
-
idempotency_key: submissionIdempotencyKey
|
|
647
|
+
idempotency_key: submissionIdempotencyKey,
|
|
648
|
+
batch_item_indices: idempotencyItemIndices
|
|
634
649
|
});
|
|
635
650
|
} catch (error) {
|
|
636
651
|
if (error instanceof SignalizError && !error.isRetryable) throw error;
|
|
@@ -693,12 +708,14 @@ var Signaliz = class {
|
|
|
693
708
|
if (seen.size !== requests.length) throw new Error(`${label} batch returned incomplete indexed results`);
|
|
694
709
|
return rows;
|
|
695
710
|
}
|
|
696
|
-
async runSignalCopyBatchChunk(requests, concurrency, rowRateLimitAttempt = 0) {
|
|
711
|
+
async runSignalCopyBatchChunk(requests, concurrency, rowRateLimitAttempt = 0, idempotencyKey, idempotencyItemIndices = requests.map((_, index) => index)) {
|
|
697
712
|
const results = new Array(requests.length);
|
|
698
713
|
const rateLimited = [];
|
|
699
714
|
const data = await this.client.post("api/v1/signal-to-copy", {
|
|
700
715
|
requests: requests.map(signalToCopyRequestBody),
|
|
701
|
-
concurrency
|
|
716
|
+
concurrency,
|
|
717
|
+
idempotency_key: idempotencyKey,
|
|
718
|
+
batch_item_indices: idempotencyItemIndices
|
|
702
719
|
});
|
|
703
720
|
if (!Array.isArray(data.results) || data.results.length !== requests.length) {
|
|
704
721
|
throw new Error("Signal to Copy batch returned an invalid result count");
|
|
@@ -733,7 +750,9 @@ var Signaliz = class {
|
|
|
733
750
|
const retried = await this.runSignalCopyBatchChunk(
|
|
734
751
|
rateLimited.map((item) => item.params),
|
|
735
752
|
concurrency,
|
|
736
|
-
rowRateLimitAttempt + 1
|
|
753
|
+
rowRateLimitAttempt + 1,
|
|
754
|
+
idempotencyKey,
|
|
755
|
+
rateLimited.map((item) => idempotencyItemIndices[item.index])
|
|
737
756
|
);
|
|
738
757
|
for (let index = 0; index < rateLimited.length; index += 1) {
|
|
739
758
|
results[rateLimited[index].index] = { ...retried[index], index: rateLimited[index].index };
|
|
@@ -753,7 +772,8 @@ var Signaliz = class {
|
|
|
753
772
|
recoverableBatch.label,
|
|
754
773
|
recoverableBatch.pageSize,
|
|
755
774
|
recoverableBatch.maxWaitMs,
|
|
756
|
-
options?.idempotencyKey
|
|
775
|
+
options?.idempotencyKey,
|
|
776
|
+
uniqueTasks.map((task) => task.index)
|
|
757
777
|
);
|
|
758
778
|
const uniqueResults2 = new Array(uniqueTasks.length);
|
|
759
779
|
for (const raw of rows) {
|
|
@@ -777,7 +797,9 @@ var Signaliz = class {
|
|
|
777
797
|
const chunkBatch = await runBatch(chunks, async (chunk) => {
|
|
778
798
|
const data = await this.client.post(path2, {
|
|
779
799
|
requests: chunk.tasks.map((task) => task.request),
|
|
780
|
-
concurrency: serverConcurrency
|
|
800
|
+
concurrency: serverConcurrency,
|
|
801
|
+
idempotency_key: options?.idempotencyKey,
|
|
802
|
+
batch_item_indices: chunk.tasks.map((task) => task.index)
|
|
781
803
|
});
|
|
782
804
|
if (!Array.isArray(data.results) || data.results.length !== chunk.tasks.length) {
|
|
783
805
|
throw new Error(`${path2} batch returned an invalid result count`);
|
|
@@ -912,7 +934,11 @@ function normalizeCoreProductDryRunResult(data) {
|
|
|
912
934
|
status: "planned",
|
|
913
935
|
capability: String(data.capability || ""),
|
|
914
936
|
inputCount: Number(data.input_count || 0),
|
|
937
|
+
freshInputCount: Number(data.fresh_input_count ?? data.input_count ?? 0),
|
|
938
|
+
uniqueFreshInputCount: Number(data.unique_fresh_input_count ?? data.fresh_input_count ?? data.input_count ?? 0),
|
|
939
|
+
inputDuplicatesSuppressed: Number(data.input_duplicates_suppressed || 0),
|
|
915
940
|
recoveryReadCount: Number(data.recovery_read_count || 0),
|
|
941
|
+
uniqueRecoveryReadCount: Number(data.unique_recovery_read_count ?? data.recovery_read_count ?? 0),
|
|
916
942
|
plan: data.plan && typeof data.plan === "object" ? data.plan : {},
|
|
917
943
|
estimate: data.estimate && typeof data.estimate === "object" ? data.estimate : {},
|
|
918
944
|
estimatedCredits: {
|
|
@@ -927,12 +953,12 @@ function normalizeCoreProductDryRunResult(data) {
|
|
|
927
953
|
function normalizeFindEmailResult(data) {
|
|
928
954
|
const email = typeof data.email === "string" && data.email.trim() ? data.email.trim() : null;
|
|
929
955
|
const found = Boolean(email) && data.found !== false;
|
|
930
|
-
const verificationStatus = data.verification_status ?? data.status ?? "unknown";
|
|
956
|
+
const verificationStatus = data.verification_status ?? (data.is_valid === true ? "valid" : data.status ?? "unknown");
|
|
931
957
|
const rawFreshness = String(data.verification_freshness ?? "").toLowerCase();
|
|
932
958
|
const verificationFreshness = rawFreshness === "fresh" || rawFreshness === "stale" ? rawFreshness : "unknown";
|
|
933
959
|
const needsReverification = data.needs_reverification === true || verificationFreshness === "stale";
|
|
934
960
|
const explicitlyNotSendSafe = data.verified_for_sending === false || needsReverification;
|
|
935
|
-
const verified = !explicitlyNotSendSafe && (data.email_verified === true || data.verified_for_sending === true || ["valid", "deliverable"].includes(String(verificationStatus).toLowerCase()));
|
|
961
|
+
const verified = !explicitlyNotSendSafe && (data.is_valid === true || data.isValid === true || data.email_verified === true || data.verified_for_sending === true || ["valid", "deliverable"].includes(String(verificationStatus).toLowerCase()));
|
|
936
962
|
const verificationAgeDays = typeof data.verification_age_days === "number" && Number.isFinite(data.verification_age_days) ? data.verification_age_days : null;
|
|
937
963
|
return {
|
|
938
964
|
success: data.success !== false && found,
|
|
@@ -955,6 +981,9 @@ function normalizeFindEmailResult(data) {
|
|
|
955
981
|
billingMetadata: data.billing_metadata,
|
|
956
982
|
resultReturnedFrom: data.result_returned_from,
|
|
957
983
|
cacheHit: data.cache_hit,
|
|
984
|
+
negativeCacheHit: data.negative_cache_hit,
|
|
985
|
+
negativeCacheTtlSeconds: data.negative_cache_ttl_seconds,
|
|
986
|
+
cacheTier: data.cache_tier,
|
|
958
987
|
freshEnrichmentUsed: data.fresh_enrichment_used,
|
|
959
988
|
liveProviderCalled: data.live_provider_called,
|
|
960
989
|
openrouterCalled: data.openrouter_called,
|
|
@@ -976,6 +1005,7 @@ function normalizeVerifyEmailResult(email, data) {
|
|
|
976
1005
|
nextPollAfterSeconds: data.next_poll_after_seconds,
|
|
977
1006
|
isValid: data.is_valid ?? data.valid ?? verified,
|
|
978
1007
|
isDeliverable: data.is_deliverable ?? data.deliverable ?? verified,
|
|
1008
|
+
isMalformed: data.is_malformed === true || data.verification_verdict === "malformed" || data.verification_status === "malformed" || data.deliverability_status === "malformed",
|
|
979
1009
|
isCatchAll: data.email_is_catch_all ?? data.is_catch_all ?? data.catch_all ?? data.diagnostics?.is_catch_all ?? false,
|
|
980
1010
|
verifiedForSending: data.verified_for_sending === true,
|
|
981
1011
|
verificationVerdict: data.verification_verdict ?? data.verification_status ?? "unknown",
|
|
@@ -987,6 +1017,9 @@ function normalizeVerifyEmailResult(email, data) {
|
|
|
987
1017
|
billingMetadata: data.billing_metadata,
|
|
988
1018
|
resultReturnedFrom: data.result_returned_from,
|
|
989
1019
|
cacheHit: data.cache_hit,
|
|
1020
|
+
negativeCacheHit: data.negative_cache_hit,
|
|
1021
|
+
negativeCacheTtlSeconds: data.negative_cache_ttl_seconds,
|
|
1022
|
+
cacheTier: data.cache_tier,
|
|
990
1023
|
freshEnrichmentUsed: data.fresh_enrichment_used,
|
|
991
1024
|
liveProviderCalled: data.live_provider_called,
|
|
992
1025
|
openrouterCalled: data.openrouter_called,
|
|
@@ -1056,6 +1089,14 @@ function normalizeCompanySignalResult(params, data) {
|
|
|
1056
1089
|
evidenceCountTotal: data.evidence_count_total,
|
|
1057
1090
|
evidenceSourcesOmitted: data.evidence_sources_omitted,
|
|
1058
1091
|
evidenceScope: data.evidence_scope,
|
|
1092
|
+
billingMetadata: data.billing_metadata,
|
|
1093
|
+
resultReturnedFrom: data.result_returned_from,
|
|
1094
|
+
cacheHit: data.cache_hit,
|
|
1095
|
+
freshEnrichmentUsed: data.fresh_enrichment_used,
|
|
1096
|
+
creditsUsed: data.credits_used,
|
|
1097
|
+
liveProviderCalled: data.live_provider_called,
|
|
1098
|
+
aiProviderCalled: data.ai_provider_called,
|
|
1099
|
+
byoAiUsed: data.byo_ai_used,
|
|
1059
1100
|
raw: data
|
|
1060
1101
|
};
|
|
1061
1102
|
}
|
|
@@ -1333,6 +1374,14 @@ function normalizeSignalToCopyResult(data) {
|
|
|
1333
1374
|
empty: data.empty,
|
|
1334
1375
|
emptyReason: data.empty_reason,
|
|
1335
1376
|
researchMetadata: data.research_metadata,
|
|
1377
|
+
billingMetadata: data.billing_metadata,
|
|
1378
|
+
resultReturnedFrom: data.result_returned_from,
|
|
1379
|
+
cacheHit: data.cache_hit,
|
|
1380
|
+
freshEnrichmentUsed: data.fresh_enrichment_used,
|
|
1381
|
+
creditsUsed: data.credits_used,
|
|
1382
|
+
liveProviderCalled: data.live_provider_called,
|
|
1383
|
+
aiProviderCalled: data.ai_provider_called,
|
|
1384
|
+
byoAiUsed: data.byo_ai_used,
|
|
1336
1385
|
variations: (data.variations ?? []).map((variation) => ({
|
|
1337
1386
|
style: variation.style,
|
|
1338
1387
|
subjectLine: variation.subject_line ?? "",
|
package/dist/mcp-config.mjs
CHANGED
package/package.json
CHANGED