@signaliz/sdk 1.0.47 → 1.0.49
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 +15 -33
- package/dist/{chunk-KTWDTUCI.mjs → chunk-KA66GBVZ.mjs} +87 -224
- package/dist/index.d.mts +34 -4
- package/dist/index.d.ts +34 -4
- package/dist/index.js +87 -224
- package/dist/index.mjs +1 -1
- package/dist/mcp-config.js +87 -224
- package/dist/mcp-config.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -59,15 +59,6 @@ const signals = await signaliz.enrichCompanySignals({
|
|
|
59
59
|
console.log(signals.signals[0].evidencePublishedDate);
|
|
60
60
|
console.log(signals.signals[0].signalFeedSource, signals.signals[0].derived);
|
|
61
61
|
|
|
62
|
-
// Persist a no-wait run ID and resume it later without duplicate spend.
|
|
63
|
-
const queuedSignals = await signaliz.enrichCompanySignals({
|
|
64
|
-
companyDomain: 'example.com',
|
|
65
|
-
waitForResult: false,
|
|
66
|
-
});
|
|
67
|
-
const resumedSignals = await signaliz.enrichCompanySignals({
|
|
68
|
-
signalRunId: queuedSignals.signalRunId,
|
|
69
|
-
});
|
|
70
|
-
|
|
71
62
|
const copy = await signaliz.signalToCopy({
|
|
72
63
|
companyDomain: 'example.com',
|
|
73
64
|
personName: 'Jane Doe',
|
|
@@ -79,16 +70,8 @@ const copy = await signaliz.signalToCopy({
|
|
|
79
70
|
enableDeepSearch: false,
|
|
80
71
|
});
|
|
81
72
|
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
const queuedCopy = await signaliz.signalToCopy({
|
|
85
|
-
companyDomain: 'example.com',
|
|
86
|
-
personName: 'Jane Doe',
|
|
87
|
-
title: 'VP Sales',
|
|
88
|
-
campaignOffer: 'pipeline intelligence',
|
|
89
|
-
waitForResult: false,
|
|
90
|
-
});
|
|
91
|
-
const resumedCopy = await signaliz.signalToCopy({ signalRunId: queuedCopy.runId });
|
|
73
|
+
// Company Signals and Signal to Copy are hard synchronous contracts: these
|
|
74
|
+
// methods return complete data or throw a terminal error in this same call.
|
|
92
75
|
```
|
|
93
76
|
|
|
94
77
|
All four products support bounded batch execution over the same REST endpoints.
|
|
@@ -114,36 +97,35 @@ when the REST API supplies them, including after automatic row retries are
|
|
|
114
97
|
exhausted.
|
|
115
98
|
|
|
116
99
|
For an ambiguous single request or batch submission failure, retry with the
|
|
117
|
-
same `idempotencyKey` to recover the original request or job without duplicate
|
|
100
|
+
same `idempotencyKey` to recover the original request or supported email job without duplicate
|
|
118
101
|
work.
|
|
119
102
|
|
|
120
|
-
Each batch accepts up to 5,000 items. Company Signal
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
server's adaptive polling hints by default and still honors `pollIntervalMs`
|
|
124
|
-
when a caller explicitly overrides the cadence.
|
|
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.
|
|
125
106
|
Exact duplicate tasks are single-flighted across each full batch without
|
|
126
107
|
changing input order or result cardinality. Set `compactDuplicates: true` to
|
|
127
108
|
return repeated successful rows as `duplicateOf` references to the zero-based
|
|
128
109
|
canonical input index; the default remains expanded for compatibility. Find Email and Verify Email
|
|
129
110
|
batches
|
|
130
111
|
larger than 25 use one cache-aware recoverable REST job with 500-row result
|
|
131
|
-
pages.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
Copy batches larger than 25 use one recoverable REST job when they can reuse
|
|
135
|
-
available signal data; fresh or deep-search requests keep the 25-row path.
|
|
136
|
-
Signal to Copy also shares company research across copy recipients.
|
|
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.
|
|
137
115
|
|
|
138
116
|
Company Signal Enrichment defaults `online` and `enableDeepSearch` to `true`
|
|
139
|
-
unless the caller explicitly disables them.
|
|
117
|
+
unless the caller explicitly disables them. Its `searchMode` defaults to
|
|
118
|
+
`balanced`; use `fast` for the primary low-latency search lane only or
|
|
119
|
+
`coverage` when breadth matters more than the sub-cent average budget target.
|
|
120
|
+
Signal to Copy AI returns three
|
|
140
121
|
complete, evidence-backed email variations when supported signals are available.
|
|
141
122
|
Signal to Copy is cache-first and defaults `enableDeepSearch` to `false` so it
|
|
142
123
|
normally finishes within an agent turn; set `skipCache` or `enableDeepSearch`
|
|
143
124
|
only when fresh or deeper research is required.
|
|
144
125
|
Unclassified evidence is returned by signal enrichment but is not used to
|
|
145
126
|
generate outreach copy.
|
|
146
|
-
Each normalized signal
|
|
127
|
+
Each normalized signal keeps `date` separate from crawl-time `detectedAt` and
|
|
128
|
+
also exposes `datePrecision`, `hasSpecificDate`, `sourceProvenance`,
|
|
147
129
|
`entityConfidence`, `classification`, `derived`, `evidencePublishedDate`,
|
|
148
130
|
`signalFeedSource`, and the provider `metadata` needed for integrity audits.
|
|
149
131
|
|
|
@@ -457,39 +457,16 @@ 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);
|
|
463
|
-
|
|
464
|
-
const maxWaitMs = Math.max(1e3, params.maxWaitMs ?? 20 * 6e4);
|
|
465
|
-
const startedAt = Date.now();
|
|
466
|
-
while (Date.now() - startedAt < maxWaitMs) {
|
|
467
|
-
if (!await waitForNextSignalPoll(data, params.pollIntervalMs, startedAt, maxWaitMs)) break;
|
|
468
|
-
const status = await this.client.post("api/v1/company-signals", {
|
|
469
|
-
...request,
|
|
470
|
-
signal_run_id: data.run_id
|
|
471
|
-
});
|
|
472
|
-
if (isCompletedSignalRun(status)) {
|
|
473
|
-
data = status.output ?? status.result ?? status.data ?? status;
|
|
474
|
-
break;
|
|
475
|
-
}
|
|
476
|
-
if (isFailedSignalRun(status)) {
|
|
477
|
-
throw new Error(`Company signal enrichment ${data.run_id} failed with status ${status.status || "unknown"}`);
|
|
478
|
-
}
|
|
479
|
-
if (!isPendingSignalResponse(status)) {
|
|
480
|
-
data = status.output ?? status.result ?? status.data ?? status;
|
|
481
|
-
break;
|
|
482
|
-
}
|
|
483
|
-
data = status;
|
|
484
|
-
}
|
|
485
|
-
if (isPendingSignalResponse(data)) {
|
|
486
|
-
throw new Error(`Company signal enrichment ${data.run_id} did not complete within ${maxWaitMs}ms`);
|
|
487
|
-
}
|
|
488
|
-
}
|
|
464
|
+
assertTerminalSignalResponse(data, "Company Signals");
|
|
489
465
|
return normalizeCompanySignalResult(params, data);
|
|
490
466
|
}
|
|
491
467
|
async enrichCompanies(companies, options) {
|
|
492
468
|
validateBatchSize(companies);
|
|
469
|
+
companies.forEach((params) => validateCoreProductMaxWaitMs(params.maxWaitMs));
|
|
493
470
|
if (options?.dryRun === true) {
|
|
494
471
|
return this.runCoreProductDryRun(
|
|
495
472
|
"api/v1/company-signals",
|
|
@@ -498,68 +475,22 @@ var Signaliz = class {
|
|
|
498
475
|
);
|
|
499
476
|
}
|
|
500
477
|
const startedAt = Date.now();
|
|
501
|
-
const results = new Array(companies.length);
|
|
502
478
|
const initialTasks = companies.map((params, index) => ({
|
|
503
479
|
index,
|
|
504
480
|
request: companySignalRequestBody(params)
|
|
505
481
|
}));
|
|
506
|
-
const
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
const round = await this.runCoreBatchRound(
|
|
511
|
-
"api/v1/company-signals",
|
|
512
|
-
pending,
|
|
513
|
-
options,
|
|
514
|
-
firstRound ? recoverableBatch : void 0
|
|
515
|
-
);
|
|
516
|
-
firstRound = false;
|
|
517
|
-
const taskByIndex = new Map(pending.map((task) => [task.index, task]));
|
|
518
|
-
const nextPending = [];
|
|
519
|
-
let nextDelayMs = 6e4;
|
|
520
|
-
for (const item of round) {
|
|
521
|
-
const params = companies[item.index];
|
|
522
|
-
const task = taskByIndex.get(item.index);
|
|
523
|
-
if (!item.success || !item.raw) {
|
|
524
|
-
results[item.index] = batchItemFailure(
|
|
525
|
-
item.index,
|
|
526
|
-
item.error || "Company Signal batch request failed",
|
|
527
|
-
item.raw ?? item
|
|
528
|
-
);
|
|
529
|
-
continue;
|
|
530
|
-
}
|
|
531
|
-
if (!isPendingSignalResponse(item.raw) || params.waitForResult === false) {
|
|
532
|
-
results[item.index] = { index: item.index, success: true, data: normalizeCompanySignalResult(params, item.raw) };
|
|
533
|
-
continue;
|
|
534
|
-
}
|
|
535
|
-
const maxWaitMs = Math.max(1e3, params.maxWaitMs ?? 20 * 6e4);
|
|
536
|
-
if (Date.now() - startedAt >= maxWaitMs) {
|
|
537
|
-
results[item.index] = {
|
|
538
|
-
index: item.index,
|
|
539
|
-
success: false,
|
|
540
|
-
error: `Company signal enrichment ${item.raw.signal_run_id || item.raw.run_id || ""} did not complete within ${maxWaitMs}ms`
|
|
541
|
-
};
|
|
542
|
-
continue;
|
|
543
|
-
}
|
|
544
|
-
const signalRunId = item.raw.signal_run_id || item.raw.run_id;
|
|
545
|
-
if (!signalRunId) {
|
|
546
|
-
results[item.index] = { index: item.index, success: false, error: "Company signal enrichment is processing without a signal_run_id" };
|
|
547
|
-
continue;
|
|
548
|
-
}
|
|
549
|
-
nextDelayMs = Math.min(
|
|
550
|
-
nextDelayMs,
|
|
551
|
-
signalPollDelayMs(item.raw, params.pollIntervalMs),
|
|
552
|
-
maxWaitMs - (Date.now() - startedAt)
|
|
553
|
-
);
|
|
554
|
-
nextPending.push({
|
|
555
|
-
...task,
|
|
556
|
-
request: { ...task.request, signal_run_id: signalRunId }
|
|
557
|
-
});
|
|
482
|
+
const round = await this.runCoreBatchRound("api/v1/company-signals", initialTasks, options);
|
|
483
|
+
const results = round.map((item) => {
|
|
484
|
+
if (!item.success || !item.raw) {
|
|
485
|
+
return batchItemFailure(item.index, item.error || "Company Signal batch request failed", item.raw ?? item);
|
|
558
486
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
487
|
+
try {
|
|
488
|
+
assertTerminalSignalResponse(item.raw, "Company Signals");
|
|
489
|
+
return { index: item.index, success: true, data: normalizeCompanySignalResult(companies[item.index], item.raw) };
|
|
490
|
+
} catch (error) {
|
|
491
|
+
return batchItemFailure(item.index, error instanceof Error ? error.message : String(error), item.raw);
|
|
492
|
+
}
|
|
493
|
+
});
|
|
563
494
|
const compactedResults = compactExactDuplicateResults(results, options?.compactDuplicates === true);
|
|
564
495
|
const succeeded = compactedResults.filter((item) => item.success).length;
|
|
565
496
|
return {
|
|
@@ -573,21 +504,9 @@ var Signaliz = class {
|
|
|
573
504
|
async signalToCopy(params) {
|
|
574
505
|
validateSignalToCopyParams(params);
|
|
575
506
|
const request = signalToCopyRequestBody(params);
|
|
576
|
-
|
|
507
|
+
const data = await this.client.post("api/v1/signal-to-copy", request);
|
|
577
508
|
if (isCoreProductDryRun(data)) return normalizeCoreProductDryRunResult(data);
|
|
578
|
-
|
|
579
|
-
const maxWaitMs = Math.max(1e3, params.maxWaitMs ?? 20 * 6e4);
|
|
580
|
-
const startedAt = Date.now();
|
|
581
|
-
while (Date.now() - startedAt < maxWaitMs) {
|
|
582
|
-
if (!await waitForNextSignalPoll(data, params.pollIntervalMs, startedAt, maxWaitMs)) break;
|
|
583
|
-
const signalRunId = data.signal_run_id || data.run_id;
|
|
584
|
-
data = await this.client.post("api/v1/signal-to-copy", data.resume_context_persisted === true ? { signal_run_id: signalRunId } : { ...request, signal_run_id: signalRunId });
|
|
585
|
-
if (!isPendingSignalResponse(data)) break;
|
|
586
|
-
}
|
|
587
|
-
if (isPendingSignalResponse(data)) {
|
|
588
|
-
throw new Error(`Signal Copy ${data.run_id} did not complete within ${maxWaitMs}ms`);
|
|
589
|
-
}
|
|
590
|
-
}
|
|
509
|
+
assertTerminalSignalResponse(data, "Signal to Copy");
|
|
591
510
|
return normalizeSignalToCopyResult(data);
|
|
592
511
|
}
|
|
593
512
|
async createSignalCopyBatch(requests, options) {
|
|
@@ -602,16 +521,10 @@ var Signaliz = class {
|
|
|
602
521
|
}
|
|
603
522
|
const startedAt = Date.now();
|
|
604
523
|
const deduplicated = dedupeExactBatchItems(requests, (params) => JSON.stringify({
|
|
605
|
-
request: signalToCopyRequestBody(params)
|
|
606
|
-
wait_for_result: params.waitForResult,
|
|
607
|
-
max_wait_ms: params.maxWaitMs,
|
|
608
|
-
poll_interval_ms: params.pollIntervalMs
|
|
524
|
+
request: signalToCopyRequestBody(params)
|
|
609
525
|
}));
|
|
610
526
|
const uniqueRequests = deduplicated.uniqueItems;
|
|
611
|
-
const
|
|
612
|
-
(params) => (!params.signalRunId || !params.signalRunId.startsWith("copy_") && [params.companyDomain, params.personName, params.title, params.campaignOffer].every((value) => typeof value === "string" && Boolean(value.trim()))) && params.waitForResult !== false && params.skipCache !== true && params.enableDeepSearch !== true && params.maxWaitMs === void 0 && params.pollIntervalMs === void 0
|
|
613
|
-
);
|
|
614
|
-
const uniqueResults = canUseRecoverableAvailableDataJob ? await this.runAvailableSignalCopyBatchJob(uniqueRequests, options) : await this.runSignalCopyBatchChunks(uniqueRequests, options);
|
|
527
|
+
const uniqueResults = await this.runSignalCopyBatchChunks(uniqueRequests, options);
|
|
615
528
|
const results = requests.map((_, index) => ({
|
|
616
529
|
...uniqueResults[deduplicated.sourceIndexByInput[index]],
|
|
617
530
|
index
|
|
@@ -667,22 +580,6 @@ var Signaliz = class {
|
|
|
667
580
|
}
|
|
668
581
|
return uniqueResults;
|
|
669
582
|
}
|
|
670
|
-
async runAvailableSignalCopyBatchJob(requests, options) {
|
|
671
|
-
const rows = await this.runRecoverableCoreBatchJob(
|
|
672
|
-
"api/v1/signal-to-copy",
|
|
673
|
-
requests.map(signalToCopyRequestBody),
|
|
674
|
-
"Signal to Copy",
|
|
675
|
-
500,
|
|
676
|
-
20 * 6e4,
|
|
677
|
-
options?.idempotencyKey
|
|
678
|
-
);
|
|
679
|
-
const results = new Array(requests.length);
|
|
680
|
-
for (const row of rows) {
|
|
681
|
-
const index = Number(row.index);
|
|
682
|
-
results[index] = recoverableJobRowFailed(row) ? batchItemFailure(index, row.error || row.message || "Signal to Copy failed", row) : { index, success: true, data: normalizeSignalToCopyResult(row) };
|
|
683
|
-
}
|
|
684
|
-
return results;
|
|
685
|
-
}
|
|
686
583
|
async runRecoverableCoreBatchJob(path, requests, label, pageSize = 500, maxWaitMs = 20 * 6e4, idempotencyKey) {
|
|
687
584
|
const startedAt = Date.now();
|
|
688
585
|
const submissionIdempotencyKey = idempotencyKey?.trim() || newBatchIdempotencyKey(label);
|
|
@@ -754,77 +651,35 @@ var Signaliz = class {
|
|
|
754
651
|
return rows;
|
|
755
652
|
}
|
|
756
653
|
async runSignalCopyBatchChunk(requests, concurrency, rowRateLimitAttempt = 0) {
|
|
757
|
-
const startedAt = Date.now();
|
|
758
654
|
const results = new Array(requests.length);
|
|
759
655
|
const rateLimited = [];
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
const task = pending[index];
|
|
777
|
-
const item = data.results[index];
|
|
778
|
-
if (item.success === false) {
|
|
779
|
-
if (rowRateLimitAttempt < MAX_ROW_RATE_LIMIT_RETRIES && isRetryableRowRateLimit({
|
|
780
|
-
index: task.index,
|
|
781
|
-
success: false,
|
|
782
|
-
raw: item
|
|
783
|
-
})) {
|
|
784
|
-
rateLimited.push({ index: task.index, params: task.params, raw: item });
|
|
785
|
-
continue;
|
|
786
|
-
}
|
|
787
|
-
results[task.index] = batchItemFailure(
|
|
788
|
-
task.index,
|
|
789
|
-
item.error || item.message || "Signal to Copy failed",
|
|
790
|
-
item
|
|
791
|
-
);
|
|
792
|
-
continue;
|
|
793
|
-
}
|
|
794
|
-
if (!isPendingSignalResponse(item)) {
|
|
795
|
-
results[task.index] = { index: task.index, success: true, data: normalizeSignalToCopyResult(item) };
|
|
796
|
-
continue;
|
|
797
|
-
}
|
|
798
|
-
if (task.params.waitForResult === false) {
|
|
799
|
-
results[task.index] = { index: task.index, success: true, data: normalizeSignalToCopyResult(item) };
|
|
800
|
-
continue;
|
|
801
|
-
}
|
|
802
|
-
const maxWaitMs = Math.max(1e3, task.params.maxWaitMs ?? 20 * 6e4);
|
|
803
|
-
if (Date.now() - startedAt >= maxWaitMs) {
|
|
804
|
-
results[task.index] = {
|
|
805
|
-
index: task.index,
|
|
806
|
-
success: false,
|
|
807
|
-
error: `Signal Copy ${item.signal_run_id || item.run_id || ""} did not complete within ${maxWaitMs}ms`
|
|
808
|
-
};
|
|
809
|
-
continue;
|
|
810
|
-
}
|
|
811
|
-
const signalRunId = item.signal_run_id || item.run_id;
|
|
812
|
-
if (!signalRunId) {
|
|
813
|
-
results[task.index] = { index: task.index, success: false, error: "Signal Copy is processing without a signal_run_id" };
|
|
656
|
+
const data = await this.client.post("api/v1/signal-to-copy", {
|
|
657
|
+
requests: requests.map(signalToCopyRequestBody),
|
|
658
|
+
concurrency
|
|
659
|
+
});
|
|
660
|
+
if (!Array.isArray(data.results) || data.results.length !== requests.length) {
|
|
661
|
+
throw new Error("Signal to Copy batch returned an invalid result count");
|
|
662
|
+
}
|
|
663
|
+
for (let index = 0; index < requests.length; index += 1) {
|
|
664
|
+
const item = data.results[index];
|
|
665
|
+
if (item.success === false) {
|
|
666
|
+
if (rowRateLimitAttempt < MAX_ROW_RATE_LIMIT_RETRIES && isRetryableRowRateLimit({
|
|
667
|
+
index,
|
|
668
|
+
success: false,
|
|
669
|
+
raw: item
|
|
670
|
+
})) {
|
|
671
|
+
rateLimited.push({ index, params: requests[index], raw: item });
|
|
814
672
|
continue;
|
|
815
673
|
}
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
);
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
});
|
|
674
|
+
results[index] = batchItemFailure(index, item.error || item.message || "Signal to Copy failed", item);
|
|
675
|
+
continue;
|
|
676
|
+
}
|
|
677
|
+
try {
|
|
678
|
+
assertTerminalSignalResponse(item, "Signal to Copy");
|
|
679
|
+
results[index] = { index, success: true, data: normalizeSignalToCopyResult(item) };
|
|
680
|
+
} catch (error) {
|
|
681
|
+
results[index] = batchItemFailure(index, error instanceof Error ? error.message : String(error), item);
|
|
825
682
|
}
|
|
826
|
-
pending = nextPending;
|
|
827
|
-
if (pending.length > 0) await sleep2(nextDelayMs);
|
|
828
683
|
}
|
|
829
684
|
if (rateLimited.length > 0) {
|
|
830
685
|
await sleep2(rowRateLimitDelayMs(rateLimited.map((item) => ({
|
|
@@ -843,12 +698,12 @@ var Signaliz = class {
|
|
|
843
698
|
}
|
|
844
699
|
return results;
|
|
845
700
|
}
|
|
846
|
-
async runCoreBatchRound(path, tasks, options,
|
|
701
|
+
async runCoreBatchRound(path, tasks, options, rowRateLimitAttempt = 0) {
|
|
847
702
|
const { serverConcurrency, chunkConcurrency } = batchConcurrencyPlan(options);
|
|
848
703
|
const deduplicated = dedupeExactBatchItems(tasks, (task) => JSON.stringify(task.request));
|
|
849
704
|
const uniqueTasks = deduplicated.uniqueItems;
|
|
850
|
-
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 } :
|
|
851
|
-
if (recoverableBatch && uniqueTasks.length > 25) {
|
|
705
|
+
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;
|
|
706
|
+
if (path !== "api/v1/company-signals" && recoverableBatch && uniqueTasks.length > 25) {
|
|
852
707
|
const rows = await this.runRecoverableCoreBatchJob(
|
|
853
708
|
path,
|
|
854
709
|
uniqueTasks.map((task) => task.request),
|
|
@@ -920,7 +775,6 @@ var Signaliz = class {
|
|
|
920
775
|
path,
|
|
921
776
|
retryTasks,
|
|
922
777
|
options,
|
|
923
|
-
void 0,
|
|
924
778
|
rowRateLimitAttempt + 1
|
|
925
779
|
);
|
|
926
780
|
const retriedByIndex = new Map(retried.map((item) => [item.index, item]));
|
|
@@ -1049,6 +903,15 @@ function normalizeFindEmailResult(data) {
|
|
|
1049
903
|
verifiedAt: typeof data.verified_at === "string" ? data.verified_at : null,
|
|
1050
904
|
needsReverification,
|
|
1051
905
|
providerUsed: data.provider_used ?? data.provider ?? data.email_source ?? data.source ?? "unknown",
|
|
906
|
+
creditsUsed: data.credits_used,
|
|
907
|
+
estimatedExternalCostUsd: data.estimated_external_cost_usd,
|
|
908
|
+
billingMetadata: data.billing_metadata,
|
|
909
|
+
resultReturnedFrom: data.result_returned_from,
|
|
910
|
+
cacheHit: data.cache_hit,
|
|
911
|
+
freshEnrichmentUsed: data.fresh_enrichment_used,
|
|
912
|
+
liveProviderCalled: data.live_provider_called,
|
|
913
|
+
openrouterCalled: data.openrouter_called,
|
|
914
|
+
byoOpenrouterUsed: data.byo_openrouter_used,
|
|
1052
915
|
error: found ? void 0 : data.error ?? "No verified email found",
|
|
1053
916
|
errorCode: found ? void 0 : data.error_code ?? "EMAIL_NOT_FOUND",
|
|
1054
917
|
raw: data
|
|
@@ -1058,6 +921,7 @@ function normalizeVerifyEmailResult(email, data) {
|
|
|
1058
921
|
const verificationStatus = String(data.verification_status ?? "").toLowerCase();
|
|
1059
922
|
const verified = data.email_verified === true || ["valid", "deliverable"].includes(verificationStatus);
|
|
1060
923
|
return {
|
|
924
|
+
success: data.success !== false,
|
|
1061
925
|
email: data.email ?? email,
|
|
1062
926
|
status: String(data.status || "").toLowerCase() === "processing" ? "processing" : "completed",
|
|
1063
927
|
verificationRunId: data.verification_run_id ?? data.run_id,
|
|
@@ -1066,9 +930,20 @@ function normalizeVerifyEmailResult(email, data) {
|
|
|
1066
930
|
isValid: data.is_valid ?? data.valid ?? verified,
|
|
1067
931
|
isDeliverable: data.is_deliverable ?? data.deliverable ?? verified,
|
|
1068
932
|
isCatchAll: data.email_is_catch_all ?? data.is_catch_all ?? data.catch_all ?? data.diagnostics?.is_catch_all ?? false,
|
|
933
|
+
verifiedForSending: data.verified_for_sending === true,
|
|
934
|
+
verificationVerdict: data.verification_verdict ?? data.verification_status ?? "unknown",
|
|
1069
935
|
confidenceScore: data.confidence_score ?? data.confidence ?? data.diagnostics?.confidence_score ?? (verified ? 1 : 0),
|
|
1070
936
|
provider: data.provider,
|
|
1071
937
|
verificationSource: data.verification_source,
|
|
938
|
+
billingReplayed: data.billing_replayed,
|
|
939
|
+
creditsUsed: data.credits_used,
|
|
940
|
+
billingMetadata: data.billing_metadata,
|
|
941
|
+
resultReturnedFrom: data.result_returned_from,
|
|
942
|
+
cacheHit: data.cache_hit,
|
|
943
|
+
freshEnrichmentUsed: data.fresh_enrichment_used,
|
|
944
|
+
liveProviderCalled: data.live_provider_called,
|
|
945
|
+
openrouterCalled: data.openrouter_called,
|
|
946
|
+
byoOpenrouterUsed: data.byo_openrouter_used,
|
|
1072
947
|
raw: data
|
|
1073
948
|
};
|
|
1074
949
|
}
|
|
@@ -1084,41 +959,17 @@ function companySignalRequestBody(params) {
|
|
|
1084
959
|
lookback_days: params.lookbackDays,
|
|
1085
960
|
online,
|
|
1086
961
|
enable_deep_search: params.enableDeepSearch ?? online,
|
|
962
|
+
search_mode: params.searchMode ?? "balanced",
|
|
1087
963
|
include_summary: params.includeSummary,
|
|
1088
964
|
enable_outreach_intelligence: params.enableOutreachIntelligence,
|
|
1089
965
|
enable_predictive_intelligence: params.enablePredictiveIntelligence,
|
|
1090
966
|
skip_cache: params.skipCache,
|
|
1091
|
-
|
|
1092
|
-
// waitForResult controls the SDK polling loop.
|
|
1093
|
-
wait_for_result: false,
|
|
967
|
+
wait_for_result: true,
|
|
1094
968
|
max_wait_ms: params.maxWaitMs,
|
|
1095
969
|
dry_run: params.dryRun,
|
|
1096
970
|
idempotency_key: params.idempotencyKey
|
|
1097
971
|
});
|
|
1098
972
|
}
|
|
1099
|
-
function companySignalRecoverableBatchOptions(companies, tasks) {
|
|
1100
|
-
if (companies.length <= 25 || companies.some((params) => params.waitForResult === false || Boolean(params.signalRunId))) {
|
|
1101
|
-
return void 0;
|
|
1102
|
-
}
|
|
1103
|
-
const maxWaitMs = Math.max(1e3, companies[0].maxWaitMs ?? 20 * 6e4);
|
|
1104
|
-
if (companies.some((params) => Math.max(1e3, params.maxWaitMs ?? 20 * 6e4) !== maxWaitMs)) {
|
|
1105
|
-
return void 0;
|
|
1106
|
-
}
|
|
1107
|
-
const configKey = (request) => {
|
|
1108
|
-
const {
|
|
1109
|
-
company_domain: _companyDomain,
|
|
1110
|
-
company_name: _companyName,
|
|
1111
|
-
signal_run_id: _signalRunId,
|
|
1112
|
-
wait_for_result: _waitForResult,
|
|
1113
|
-
max_wait_ms: _maxWaitMs,
|
|
1114
|
-
...config
|
|
1115
|
-
} = request;
|
|
1116
|
-
return JSON.stringify(config);
|
|
1117
|
-
};
|
|
1118
|
-
const sharedConfig = configKey(tasks[0].request);
|
|
1119
|
-
if (tasks.some((task) => configKey(task.request) !== sharedConfig)) return void 0;
|
|
1120
|
-
return { label: "Company Signals", pageSize: 25, maxWaitMs };
|
|
1121
|
-
}
|
|
1122
973
|
function normalizeCompanySignalResult(params, data) {
|
|
1123
974
|
const rawSignals = data.signals ?? data.signal_feed ?? [];
|
|
1124
975
|
return {
|
|
@@ -1136,8 +987,10 @@ function normalizeCompanySignalResult(params, data) {
|
|
|
1136
987
|
title: signal.title ?? "",
|
|
1137
988
|
type: signal.type ?? signal.signal_type ?? "unknown",
|
|
1138
989
|
content: signal.content ?? signal.description ?? "",
|
|
1139
|
-
date: signal.date ??
|
|
990
|
+
date: signal.date ?? null,
|
|
991
|
+
detectedAt: signal.detected_at ?? null,
|
|
1140
992
|
datePrecision: signal.date_precision,
|
|
993
|
+
hasSpecificDate: signal.has_specific_date ?? metadata?.has_specific_date,
|
|
1141
994
|
sourceUrl: signal.source_url ?? signal.url ?? null,
|
|
1142
995
|
sourceType: signal.source_type,
|
|
1143
996
|
sourceProvenance: signal.source_provenance,
|
|
@@ -1166,7 +1019,10 @@ function normalizeCompanySignalResult(params, data) {
|
|
|
1166
1019
|
billingMetadata: data.billing_metadata,
|
|
1167
1020
|
resultReturnedFrom: data.result_returned_from,
|
|
1168
1021
|
cacheHit: data.cache_hit,
|
|
1022
|
+
freshEnrichmentUsed: data.fresh_enrichment_used,
|
|
1169
1023
|
liveProviderCalled: data.live_provider_called,
|
|
1024
|
+
aiProviderCalled: data.ai_provider_called,
|
|
1025
|
+
byoAiUsed: data.byo_ai_used,
|
|
1170
1026
|
metadata: data.metadata,
|
|
1171
1027
|
raw: data
|
|
1172
1028
|
};
|
|
@@ -1266,11 +1122,13 @@ function signalToCopyRequestBody(params) {
|
|
|
1266
1122
|
signal_run_id: params.signalRunId,
|
|
1267
1123
|
skip_cache: params.skipCache,
|
|
1268
1124
|
enable_deep_search: params.enableDeepSearch,
|
|
1125
|
+
max_wait_ms: params.maxWaitMs,
|
|
1269
1126
|
dry_run: params.dryRun,
|
|
1270
1127
|
idempotency_key: params.idempotencyKey
|
|
1271
1128
|
});
|
|
1272
1129
|
}
|
|
1273
1130
|
function validateSignalToCopyParams(params) {
|
|
1131
|
+
validateCoreProductMaxWaitMs(params.maxWaitMs);
|
|
1274
1132
|
if (typeof params.signalRunId === "string" && params.signalRunId.trim()) return;
|
|
1275
1133
|
const missing = [
|
|
1276
1134
|
["companyDomain", params.companyDomain],
|
|
@@ -1282,6 +1140,12 @@ function validateSignalToCopyParams(params) {
|
|
|
1282
1140
|
throw new TypeError(`Signal to Copy requires signalRunId or: ${missing.join(", ")}`);
|
|
1283
1141
|
}
|
|
1284
1142
|
}
|
|
1143
|
+
function validateCoreProductMaxWaitMs(value) {
|
|
1144
|
+
if (value === void 0) return;
|
|
1145
|
+
if (!Number.isInteger(value) || value < 1e4 || value > 12e4) {
|
|
1146
|
+
throw new RangeError("maxWaitMs must be an integer between 10000 and 120000");
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1285
1149
|
function normalizeSignalToCopyResult(data) {
|
|
1286
1150
|
return {
|
|
1287
1151
|
success: data.success ?? true,
|
|
@@ -1312,11 +1176,10 @@ function normalizeSignalToCopyResult(data) {
|
|
|
1312
1176
|
function isPendingSignalResponse(data) {
|
|
1313
1177
|
return ["triggered", "queued", "processing", "pending", "pending_version", "waiting_for_deploy"].includes(String(data.status || "").toLowerCase());
|
|
1314
1178
|
}
|
|
1315
|
-
function
|
|
1316
|
-
|
|
1317
|
-
}
|
|
1318
|
-
|
|
1319
|
-
return ["failed", "error", "cancelled", "canceled", "crashed", "timed_out"].includes(String(data.status || "").toLowerCase());
|
|
1179
|
+
function assertTerminalSignalResponse(data, capability) {
|
|
1180
|
+
if (isPendingSignalResponse(data) || data.job_id) {
|
|
1181
|
+
throw new Error(`${capability} violated the synchronous response contract.`);
|
|
1182
|
+
}
|
|
1320
1183
|
}
|
|
1321
1184
|
function signalPollDelayMs(data, override) {
|
|
1322
1185
|
if (override !== void 0) return Math.max(250, override);
|
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 {
|
|
@@ -141,15 +163,17 @@ interface CompanySignalEnrichmentParams {
|
|
|
141
163
|
lookbackDays?: number;
|
|
142
164
|
online?: boolean;
|
|
143
165
|
enableDeepSearch?: boolean;
|
|
166
|
+
/** Web coverage policy. Balanced targets an average all-in search budget below one cent. */
|
|
167
|
+
searchMode?: 'fast' | 'balanced' | 'coverage';
|
|
144
168
|
includeSummary?: boolean;
|
|
145
169
|
enableOutreachIntelligence?: boolean;
|
|
146
170
|
enablePredictiveIntelligence?: boolean;
|
|
147
171
|
skipCache?: boolean;
|
|
148
|
-
/**
|
|
172
|
+
/** @deprecated Company Signals is always synchronous; this option is ignored. */
|
|
149
173
|
waitForResult?: boolean;
|
|
150
|
-
/** Maximum
|
|
174
|
+
/** Maximum server-side synchronous execution window. */
|
|
151
175
|
maxWaitMs?: number;
|
|
152
|
-
/**
|
|
176
|
+
/** @deprecated Company Signals never returns a polling contract. */
|
|
153
177
|
pollIntervalMs?: number;
|
|
154
178
|
/** Return a no-spend plan without provider calls or jobs. */
|
|
155
179
|
dryRun?: boolean;
|
|
@@ -162,7 +186,9 @@ interface CompanySignal {
|
|
|
162
186
|
type: string;
|
|
163
187
|
content: string;
|
|
164
188
|
date?: string | null;
|
|
189
|
+
detectedAt?: string | null;
|
|
165
190
|
datePrecision?: string;
|
|
191
|
+
hasSpecificDate?: boolean;
|
|
166
192
|
sourceUrl?: string | null;
|
|
167
193
|
sourceType?: string;
|
|
168
194
|
sourceProvenance?: string;
|
|
@@ -199,7 +225,10 @@ interface CompanySignalEnrichmentResult {
|
|
|
199
225
|
billingMetadata?: Record<string, unknown>;
|
|
200
226
|
resultReturnedFrom?: string;
|
|
201
227
|
cacheHit?: boolean;
|
|
228
|
+
freshEnrichmentUsed?: boolean;
|
|
202
229
|
liveProviderCalled?: boolean;
|
|
230
|
+
aiProviderCalled?: boolean;
|
|
231
|
+
byoAiUsed?: boolean;
|
|
203
232
|
metadata?: Record<string, unknown>;
|
|
204
233
|
raw: Record<string, unknown>;
|
|
205
234
|
}
|
|
@@ -214,8 +243,10 @@ interface SignalToCopyParams {
|
|
|
214
243
|
skipCache?: boolean;
|
|
215
244
|
/** Opt into slower deep research. Defaults to false. */
|
|
216
245
|
enableDeepSearch?: boolean;
|
|
246
|
+
/** @deprecated Signal to Copy is always synchronous; this option is ignored. */
|
|
217
247
|
waitForResult?: boolean;
|
|
218
248
|
maxWaitMs?: number;
|
|
249
|
+
/** @deprecated Signal to Copy never returns a polling contract. */
|
|
219
250
|
pollIntervalMs?: number;
|
|
220
251
|
/** Return a no-spend plan without provider calls or jobs. */
|
|
221
252
|
dryRun?: boolean;
|
|
@@ -306,7 +337,6 @@ declare class Signaliz {
|
|
|
306
337
|
createSignalCopyBatch(requests: SignalToCopyParams[], options?: BatchOptions): Promise<BatchResult<SignalToCopyResult>>;
|
|
307
338
|
private runCoreProductDryRun;
|
|
308
339
|
private runSignalCopyBatchChunks;
|
|
309
|
-
private runAvailableSignalCopyBatchJob;
|
|
310
340
|
private runRecoverableCoreBatchJob;
|
|
311
341
|
private runSignalCopyBatchChunk;
|
|
312
342
|
private runCoreBatchRound;
|