@signaliz/sdk 1.0.47 → 1.0.48
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 +13 -32
- package/dist/{chunk-KTWDTUCI.mjs → chunk-NOOQDYOJ.mjs} +51 -223
- package/dist/index.d.mts +7 -4
- package/dist/index.d.ts +7 -4
- package/dist/index.js +51 -223
- package/dist/index.mjs +1 -1
- package/dist/mcp-config.js +51 -223
- 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,29 +97,27 @@ 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`
|
|
@@ -458,34 +458,9 @@ var Signaliz = class {
|
|
|
458
458
|
}
|
|
459
459
|
async enrichCompanySignals(params) {
|
|
460
460
|
const request = companySignalRequestBody(params);
|
|
461
|
-
|
|
461
|
+
const data = await this.client.post("api/v1/company-signals", request);
|
|
462
462
|
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
|
-
}
|
|
463
|
+
assertTerminalSignalResponse(data, "Company Signals");
|
|
489
464
|
return normalizeCompanySignalResult(params, data);
|
|
490
465
|
}
|
|
491
466
|
async enrichCompanies(companies, options) {
|
|
@@ -498,68 +473,22 @@ var Signaliz = class {
|
|
|
498
473
|
);
|
|
499
474
|
}
|
|
500
475
|
const startedAt = Date.now();
|
|
501
|
-
const results = new Array(companies.length);
|
|
502
476
|
const initialTasks = companies.map((params, index) => ({
|
|
503
477
|
index,
|
|
504
478
|
request: companySignalRequestBody(params)
|
|
505
479
|
}));
|
|
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
|
-
});
|
|
480
|
+
const round = await this.runCoreBatchRound("api/v1/company-signals", initialTasks, options);
|
|
481
|
+
const results = round.map((item) => {
|
|
482
|
+
if (!item.success || !item.raw) {
|
|
483
|
+
return batchItemFailure(item.index, item.error || "Company Signal batch request failed", item.raw ?? item);
|
|
558
484
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
485
|
+
try {
|
|
486
|
+
assertTerminalSignalResponse(item.raw, "Company Signals");
|
|
487
|
+
return { index: item.index, success: true, data: normalizeCompanySignalResult(companies[item.index], item.raw) };
|
|
488
|
+
} catch (error) {
|
|
489
|
+
return batchItemFailure(item.index, error instanceof Error ? error.message : String(error), item.raw);
|
|
490
|
+
}
|
|
491
|
+
});
|
|
563
492
|
const compactedResults = compactExactDuplicateResults(results, options?.compactDuplicates === true);
|
|
564
493
|
const succeeded = compactedResults.filter((item) => item.success).length;
|
|
565
494
|
return {
|
|
@@ -573,21 +502,9 @@ var Signaliz = class {
|
|
|
573
502
|
async signalToCopy(params) {
|
|
574
503
|
validateSignalToCopyParams(params);
|
|
575
504
|
const request = signalToCopyRequestBody(params);
|
|
576
|
-
|
|
505
|
+
const data = await this.client.post("api/v1/signal-to-copy", request);
|
|
577
506
|
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
|
-
}
|
|
507
|
+
assertTerminalSignalResponse(data, "Signal to Copy");
|
|
591
508
|
return normalizeSignalToCopyResult(data);
|
|
592
509
|
}
|
|
593
510
|
async createSignalCopyBatch(requests, options) {
|
|
@@ -602,16 +519,10 @@ var Signaliz = class {
|
|
|
602
519
|
}
|
|
603
520
|
const startedAt = Date.now();
|
|
604
521
|
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
|
|
522
|
+
request: signalToCopyRequestBody(params)
|
|
609
523
|
}));
|
|
610
524
|
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);
|
|
525
|
+
const uniqueResults = await this.runSignalCopyBatchChunks(uniqueRequests, options);
|
|
615
526
|
const results = requests.map((_, index) => ({
|
|
616
527
|
...uniqueResults[deduplicated.sourceIndexByInput[index]],
|
|
617
528
|
index
|
|
@@ -667,22 +578,6 @@ var Signaliz = class {
|
|
|
667
578
|
}
|
|
668
579
|
return uniqueResults;
|
|
669
580
|
}
|
|
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
581
|
async runRecoverableCoreBatchJob(path, requests, label, pageSize = 500, maxWaitMs = 20 * 6e4, idempotencyKey) {
|
|
687
582
|
const startedAt = Date.now();
|
|
688
583
|
const submissionIdempotencyKey = idempotencyKey?.trim() || newBatchIdempotencyKey(label);
|
|
@@ -754,77 +649,35 @@ var Signaliz = class {
|
|
|
754
649
|
return rows;
|
|
755
650
|
}
|
|
756
651
|
async runSignalCopyBatchChunk(requests, concurrency, rowRateLimitAttempt = 0) {
|
|
757
|
-
const startedAt = Date.now();
|
|
758
652
|
const results = new Array(requests.length);
|
|
759
653
|
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" };
|
|
654
|
+
const data = await this.client.post("api/v1/signal-to-copy", {
|
|
655
|
+
requests: requests.map(signalToCopyRequestBody),
|
|
656
|
+
concurrency
|
|
657
|
+
});
|
|
658
|
+
if (!Array.isArray(data.results) || data.results.length !== requests.length) {
|
|
659
|
+
throw new Error("Signal to Copy batch returned an invalid result count");
|
|
660
|
+
}
|
|
661
|
+
for (let index = 0; index < requests.length; index += 1) {
|
|
662
|
+
const item = data.results[index];
|
|
663
|
+
if (item.success === false) {
|
|
664
|
+
if (rowRateLimitAttempt < MAX_ROW_RATE_LIMIT_RETRIES && isRetryableRowRateLimit({
|
|
665
|
+
index,
|
|
666
|
+
success: false,
|
|
667
|
+
raw: item
|
|
668
|
+
})) {
|
|
669
|
+
rateLimited.push({ index, params: requests[index], raw: item });
|
|
814
670
|
continue;
|
|
815
671
|
}
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
);
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
});
|
|
672
|
+
results[index] = batchItemFailure(index, item.error || item.message || "Signal to Copy failed", item);
|
|
673
|
+
continue;
|
|
674
|
+
}
|
|
675
|
+
try {
|
|
676
|
+
assertTerminalSignalResponse(item, "Signal to Copy");
|
|
677
|
+
results[index] = { index, success: true, data: normalizeSignalToCopyResult(item) };
|
|
678
|
+
} catch (error) {
|
|
679
|
+
results[index] = batchItemFailure(index, error instanceof Error ? error.message : String(error), item);
|
|
825
680
|
}
|
|
826
|
-
pending = nextPending;
|
|
827
|
-
if (pending.length > 0) await sleep2(nextDelayMs);
|
|
828
681
|
}
|
|
829
682
|
if (rateLimited.length > 0) {
|
|
830
683
|
await sleep2(rowRateLimitDelayMs(rateLimited.map((item) => ({
|
|
@@ -843,12 +696,12 @@ var Signaliz = class {
|
|
|
843
696
|
}
|
|
844
697
|
return results;
|
|
845
698
|
}
|
|
846
|
-
async runCoreBatchRound(path, tasks, options,
|
|
699
|
+
async runCoreBatchRound(path, tasks, options, rowRateLimitAttempt = 0) {
|
|
847
700
|
const { serverConcurrency, chunkConcurrency } = batchConcurrencyPlan(options);
|
|
848
701
|
const deduplicated = dedupeExactBatchItems(tasks, (task) => JSON.stringify(task.request));
|
|
849
702
|
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) {
|
|
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) {
|
|
852
705
|
const rows = await this.runRecoverableCoreBatchJob(
|
|
853
706
|
path,
|
|
854
707
|
uniqueTasks.map((task) => task.request),
|
|
@@ -920,7 +773,6 @@ var Signaliz = class {
|
|
|
920
773
|
path,
|
|
921
774
|
retryTasks,
|
|
922
775
|
options,
|
|
923
|
-
void 0,
|
|
924
776
|
rowRateLimitAttempt + 1
|
|
925
777
|
);
|
|
926
778
|
const retriedByIndex = new Map(retried.map((item) => [item.index, item]));
|
|
@@ -1084,41 +936,17 @@ function companySignalRequestBody(params) {
|
|
|
1084
936
|
lookback_days: params.lookbackDays,
|
|
1085
937
|
online,
|
|
1086
938
|
enable_deep_search: params.enableDeepSearch ?? online,
|
|
939
|
+
search_mode: params.searchMode ?? "balanced",
|
|
1087
940
|
include_summary: params.includeSummary,
|
|
1088
941
|
enable_outreach_intelligence: params.enableOutreachIntelligence,
|
|
1089
942
|
enable_predictive_intelligence: params.enablePredictiveIntelligence,
|
|
1090
943
|
skip_cache: params.skipCache,
|
|
1091
|
-
|
|
1092
|
-
// waitForResult controls the SDK polling loop.
|
|
1093
|
-
wait_for_result: false,
|
|
944
|
+
wait_for_result: true,
|
|
1094
945
|
max_wait_ms: params.maxWaitMs,
|
|
1095
946
|
dry_run: params.dryRun,
|
|
1096
947
|
idempotency_key: params.idempotencyKey
|
|
1097
948
|
});
|
|
1098
949
|
}
|
|
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
950
|
function normalizeCompanySignalResult(params, data) {
|
|
1123
951
|
const rawSignals = data.signals ?? data.signal_feed ?? [];
|
|
1124
952
|
return {
|
|
@@ -1266,6 +1094,7 @@ function signalToCopyRequestBody(params) {
|
|
|
1266
1094
|
signal_run_id: params.signalRunId,
|
|
1267
1095
|
skip_cache: params.skipCache,
|
|
1268
1096
|
enable_deep_search: params.enableDeepSearch,
|
|
1097
|
+
max_wait_ms: params.maxWaitMs,
|
|
1269
1098
|
dry_run: params.dryRun,
|
|
1270
1099
|
idempotency_key: params.idempotencyKey
|
|
1271
1100
|
});
|
|
@@ -1312,11 +1141,10 @@ function normalizeSignalToCopyResult(data) {
|
|
|
1312
1141
|
function isPendingSignalResponse(data) {
|
|
1313
1142
|
return ["triggered", "queued", "processing", "pending", "pending_version", "waiting_for_deploy"].includes(String(data.status || "").toLowerCase());
|
|
1314
1143
|
}
|
|
1315
|
-
function
|
|
1316
|
-
|
|
1317
|
-
}
|
|
1318
|
-
|
|
1319
|
-
return ["failed", "error", "cancelled", "canceled", "crashed", "timed_out"].includes(String(data.status || "").toLowerCase());
|
|
1144
|
+
function assertTerminalSignalResponse(data, capability) {
|
|
1145
|
+
if (isPendingSignalResponse(data) || data.job_id) {
|
|
1146
|
+
throw new Error(`${capability} violated the synchronous response contract.`);
|
|
1147
|
+
}
|
|
1320
1148
|
}
|
|
1321
1149
|
function signalPollDelayMs(data, override) {
|
|
1322
1150
|
if (override !== void 0) return Math.max(250, override);
|
package/dist/index.d.mts
CHANGED
|
@@ -141,15 +141,17 @@ interface CompanySignalEnrichmentParams {
|
|
|
141
141
|
lookbackDays?: number;
|
|
142
142
|
online?: boolean;
|
|
143
143
|
enableDeepSearch?: boolean;
|
|
144
|
+
/** Web coverage policy. Balanced targets an average all-in search budget below one cent. */
|
|
145
|
+
searchMode?: 'fast' | 'balanced' | 'coverage';
|
|
144
146
|
includeSummary?: boolean;
|
|
145
147
|
enableOutreachIntelligence?: boolean;
|
|
146
148
|
enablePredictiveIntelligence?: boolean;
|
|
147
149
|
skipCache?: boolean;
|
|
148
|
-
/**
|
|
150
|
+
/** @deprecated Company Signals is always synchronous; this option is ignored. */
|
|
149
151
|
waitForResult?: boolean;
|
|
150
|
-
/** Maximum
|
|
152
|
+
/** Maximum server-side synchronous execution window. */
|
|
151
153
|
maxWaitMs?: number;
|
|
152
|
-
/**
|
|
154
|
+
/** @deprecated Company Signals never returns a polling contract. */
|
|
153
155
|
pollIntervalMs?: number;
|
|
154
156
|
/** Return a no-spend plan without provider calls or jobs. */
|
|
155
157
|
dryRun?: boolean;
|
|
@@ -214,8 +216,10 @@ interface SignalToCopyParams {
|
|
|
214
216
|
skipCache?: boolean;
|
|
215
217
|
/** Opt into slower deep research. Defaults to false. */
|
|
216
218
|
enableDeepSearch?: boolean;
|
|
219
|
+
/** @deprecated Signal to Copy is always synchronous; this option is ignored. */
|
|
217
220
|
waitForResult?: boolean;
|
|
218
221
|
maxWaitMs?: number;
|
|
222
|
+
/** @deprecated Signal to Copy never returns a polling contract. */
|
|
219
223
|
pollIntervalMs?: number;
|
|
220
224
|
/** Return a no-spend plan without provider calls or jobs. */
|
|
221
225
|
dryRun?: boolean;
|
|
@@ -306,7 +310,6 @@ declare class Signaliz {
|
|
|
306
310
|
createSignalCopyBatch(requests: SignalToCopyParams[], options?: BatchOptions): Promise<BatchResult<SignalToCopyResult>>;
|
|
307
311
|
private runCoreProductDryRun;
|
|
308
312
|
private runSignalCopyBatchChunks;
|
|
309
|
-
private runAvailableSignalCopyBatchJob;
|
|
310
313
|
private runRecoverableCoreBatchJob;
|
|
311
314
|
private runSignalCopyBatchChunk;
|
|
312
315
|
private runCoreBatchRound;
|
package/dist/index.d.ts
CHANGED
|
@@ -141,15 +141,17 @@ interface CompanySignalEnrichmentParams {
|
|
|
141
141
|
lookbackDays?: number;
|
|
142
142
|
online?: boolean;
|
|
143
143
|
enableDeepSearch?: boolean;
|
|
144
|
+
/** Web coverage policy. Balanced targets an average all-in search budget below one cent. */
|
|
145
|
+
searchMode?: 'fast' | 'balanced' | 'coverage';
|
|
144
146
|
includeSummary?: boolean;
|
|
145
147
|
enableOutreachIntelligence?: boolean;
|
|
146
148
|
enablePredictiveIntelligence?: boolean;
|
|
147
149
|
skipCache?: boolean;
|
|
148
|
-
/**
|
|
150
|
+
/** @deprecated Company Signals is always synchronous; this option is ignored. */
|
|
149
151
|
waitForResult?: boolean;
|
|
150
|
-
/** Maximum
|
|
152
|
+
/** Maximum server-side synchronous execution window. */
|
|
151
153
|
maxWaitMs?: number;
|
|
152
|
-
/**
|
|
154
|
+
/** @deprecated Company Signals never returns a polling contract. */
|
|
153
155
|
pollIntervalMs?: number;
|
|
154
156
|
/** Return a no-spend plan without provider calls or jobs. */
|
|
155
157
|
dryRun?: boolean;
|
|
@@ -214,8 +216,10 @@ interface SignalToCopyParams {
|
|
|
214
216
|
skipCache?: boolean;
|
|
215
217
|
/** Opt into slower deep research. Defaults to false. */
|
|
216
218
|
enableDeepSearch?: boolean;
|
|
219
|
+
/** @deprecated Signal to Copy is always synchronous; this option is ignored. */
|
|
217
220
|
waitForResult?: boolean;
|
|
218
221
|
maxWaitMs?: number;
|
|
222
|
+
/** @deprecated Signal to Copy never returns a polling contract. */
|
|
219
223
|
pollIntervalMs?: number;
|
|
220
224
|
/** Return a no-spend plan without provider calls or jobs. */
|
|
221
225
|
dryRun?: boolean;
|
|
@@ -306,7 +310,6 @@ declare class Signaliz {
|
|
|
306
310
|
createSignalCopyBatch(requests: SignalToCopyParams[], options?: BatchOptions): Promise<BatchResult<SignalToCopyResult>>;
|
|
307
311
|
private runCoreProductDryRun;
|
|
308
312
|
private runSignalCopyBatchChunks;
|
|
309
|
-
private runAvailableSignalCopyBatchJob;
|
|
310
313
|
private runRecoverableCoreBatchJob;
|
|
311
314
|
private runSignalCopyBatchChunk;
|
|
312
315
|
private runCoreBatchRound;
|
package/dist/index.js
CHANGED
|
@@ -485,34 +485,9 @@ var Signaliz = class {
|
|
|
485
485
|
}
|
|
486
486
|
async enrichCompanySignals(params) {
|
|
487
487
|
const request = companySignalRequestBody(params);
|
|
488
|
-
|
|
488
|
+
const data = await this.client.post("api/v1/company-signals", request);
|
|
489
489
|
if (isCoreProductDryRun(data)) return normalizeCoreProductDryRunResult(data);
|
|
490
|
-
|
|
491
|
-
const maxWaitMs = Math.max(1e3, params.maxWaitMs ?? 20 * 6e4);
|
|
492
|
-
const startedAt = Date.now();
|
|
493
|
-
while (Date.now() - startedAt < maxWaitMs) {
|
|
494
|
-
if (!await waitForNextSignalPoll(data, params.pollIntervalMs, startedAt, maxWaitMs)) break;
|
|
495
|
-
const status = await this.client.post("api/v1/company-signals", {
|
|
496
|
-
...request,
|
|
497
|
-
signal_run_id: data.run_id
|
|
498
|
-
});
|
|
499
|
-
if (isCompletedSignalRun(status)) {
|
|
500
|
-
data = status.output ?? status.result ?? status.data ?? status;
|
|
501
|
-
break;
|
|
502
|
-
}
|
|
503
|
-
if (isFailedSignalRun(status)) {
|
|
504
|
-
throw new Error(`Company signal enrichment ${data.run_id} failed with status ${status.status || "unknown"}`);
|
|
505
|
-
}
|
|
506
|
-
if (!isPendingSignalResponse(status)) {
|
|
507
|
-
data = status.output ?? status.result ?? status.data ?? status;
|
|
508
|
-
break;
|
|
509
|
-
}
|
|
510
|
-
data = status;
|
|
511
|
-
}
|
|
512
|
-
if (isPendingSignalResponse(data)) {
|
|
513
|
-
throw new Error(`Company signal enrichment ${data.run_id} did not complete within ${maxWaitMs}ms`);
|
|
514
|
-
}
|
|
515
|
-
}
|
|
490
|
+
assertTerminalSignalResponse(data, "Company Signals");
|
|
516
491
|
return normalizeCompanySignalResult(params, data);
|
|
517
492
|
}
|
|
518
493
|
async enrichCompanies(companies, options) {
|
|
@@ -525,68 +500,22 @@ var Signaliz = class {
|
|
|
525
500
|
);
|
|
526
501
|
}
|
|
527
502
|
const startedAt = Date.now();
|
|
528
|
-
const results = new Array(companies.length);
|
|
529
503
|
const initialTasks = companies.map((params, index) => ({
|
|
530
504
|
index,
|
|
531
505
|
request: companySignalRequestBody(params)
|
|
532
506
|
}));
|
|
533
|
-
const
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
const round = await this.runCoreBatchRound(
|
|
538
|
-
"api/v1/company-signals",
|
|
539
|
-
pending,
|
|
540
|
-
options,
|
|
541
|
-
firstRound ? recoverableBatch : void 0
|
|
542
|
-
);
|
|
543
|
-
firstRound = false;
|
|
544
|
-
const taskByIndex = new Map(pending.map((task) => [task.index, task]));
|
|
545
|
-
const nextPending = [];
|
|
546
|
-
let nextDelayMs = 6e4;
|
|
547
|
-
for (const item of round) {
|
|
548
|
-
const params = companies[item.index];
|
|
549
|
-
const task = taskByIndex.get(item.index);
|
|
550
|
-
if (!item.success || !item.raw) {
|
|
551
|
-
results[item.index] = batchItemFailure(
|
|
552
|
-
item.index,
|
|
553
|
-
item.error || "Company Signal batch request failed",
|
|
554
|
-
item.raw ?? item
|
|
555
|
-
);
|
|
556
|
-
continue;
|
|
557
|
-
}
|
|
558
|
-
if (!isPendingSignalResponse(item.raw) || params.waitForResult === false) {
|
|
559
|
-
results[item.index] = { index: item.index, success: true, data: normalizeCompanySignalResult(params, item.raw) };
|
|
560
|
-
continue;
|
|
561
|
-
}
|
|
562
|
-
const maxWaitMs = Math.max(1e3, params.maxWaitMs ?? 20 * 6e4);
|
|
563
|
-
if (Date.now() - startedAt >= maxWaitMs) {
|
|
564
|
-
results[item.index] = {
|
|
565
|
-
index: item.index,
|
|
566
|
-
success: false,
|
|
567
|
-
error: `Company signal enrichment ${item.raw.signal_run_id || item.raw.run_id || ""} did not complete within ${maxWaitMs}ms`
|
|
568
|
-
};
|
|
569
|
-
continue;
|
|
570
|
-
}
|
|
571
|
-
const signalRunId = item.raw.signal_run_id || item.raw.run_id;
|
|
572
|
-
if (!signalRunId) {
|
|
573
|
-
results[item.index] = { index: item.index, success: false, error: "Company signal enrichment is processing without a signal_run_id" };
|
|
574
|
-
continue;
|
|
575
|
-
}
|
|
576
|
-
nextDelayMs = Math.min(
|
|
577
|
-
nextDelayMs,
|
|
578
|
-
signalPollDelayMs(item.raw, params.pollIntervalMs),
|
|
579
|
-
maxWaitMs - (Date.now() - startedAt)
|
|
580
|
-
);
|
|
581
|
-
nextPending.push({
|
|
582
|
-
...task,
|
|
583
|
-
request: { ...task.request, signal_run_id: signalRunId }
|
|
584
|
-
});
|
|
507
|
+
const round = await this.runCoreBatchRound("api/v1/company-signals", initialTasks, options);
|
|
508
|
+
const results = round.map((item) => {
|
|
509
|
+
if (!item.success || !item.raw) {
|
|
510
|
+
return batchItemFailure(item.index, item.error || "Company Signal batch request failed", item.raw ?? item);
|
|
585
511
|
}
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
512
|
+
try {
|
|
513
|
+
assertTerminalSignalResponse(item.raw, "Company Signals");
|
|
514
|
+
return { index: item.index, success: true, data: normalizeCompanySignalResult(companies[item.index], item.raw) };
|
|
515
|
+
} catch (error) {
|
|
516
|
+
return batchItemFailure(item.index, error instanceof Error ? error.message : String(error), item.raw);
|
|
517
|
+
}
|
|
518
|
+
});
|
|
590
519
|
const compactedResults = compactExactDuplicateResults(results, options?.compactDuplicates === true);
|
|
591
520
|
const succeeded = compactedResults.filter((item) => item.success).length;
|
|
592
521
|
return {
|
|
@@ -600,21 +529,9 @@ var Signaliz = class {
|
|
|
600
529
|
async signalToCopy(params) {
|
|
601
530
|
validateSignalToCopyParams(params);
|
|
602
531
|
const request = signalToCopyRequestBody(params);
|
|
603
|
-
|
|
532
|
+
const data = await this.client.post("api/v1/signal-to-copy", request);
|
|
604
533
|
if (isCoreProductDryRun(data)) return normalizeCoreProductDryRunResult(data);
|
|
605
|
-
|
|
606
|
-
const maxWaitMs = Math.max(1e3, params.maxWaitMs ?? 20 * 6e4);
|
|
607
|
-
const startedAt = Date.now();
|
|
608
|
-
while (Date.now() - startedAt < maxWaitMs) {
|
|
609
|
-
if (!await waitForNextSignalPoll(data, params.pollIntervalMs, startedAt, maxWaitMs)) break;
|
|
610
|
-
const signalRunId = data.signal_run_id || data.run_id;
|
|
611
|
-
data = await this.client.post("api/v1/signal-to-copy", data.resume_context_persisted === true ? { signal_run_id: signalRunId } : { ...request, signal_run_id: signalRunId });
|
|
612
|
-
if (!isPendingSignalResponse(data)) break;
|
|
613
|
-
}
|
|
614
|
-
if (isPendingSignalResponse(data)) {
|
|
615
|
-
throw new Error(`Signal Copy ${data.run_id} did not complete within ${maxWaitMs}ms`);
|
|
616
|
-
}
|
|
617
|
-
}
|
|
534
|
+
assertTerminalSignalResponse(data, "Signal to Copy");
|
|
618
535
|
return normalizeSignalToCopyResult(data);
|
|
619
536
|
}
|
|
620
537
|
async createSignalCopyBatch(requests, options) {
|
|
@@ -629,16 +546,10 @@ var Signaliz = class {
|
|
|
629
546
|
}
|
|
630
547
|
const startedAt = Date.now();
|
|
631
548
|
const deduplicated = dedupeExactBatchItems(requests, (params) => JSON.stringify({
|
|
632
|
-
request: signalToCopyRequestBody(params)
|
|
633
|
-
wait_for_result: params.waitForResult,
|
|
634
|
-
max_wait_ms: params.maxWaitMs,
|
|
635
|
-
poll_interval_ms: params.pollIntervalMs
|
|
549
|
+
request: signalToCopyRequestBody(params)
|
|
636
550
|
}));
|
|
637
551
|
const uniqueRequests = deduplicated.uniqueItems;
|
|
638
|
-
const
|
|
639
|
-
(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
|
|
640
|
-
);
|
|
641
|
-
const uniqueResults = canUseRecoverableAvailableDataJob ? await this.runAvailableSignalCopyBatchJob(uniqueRequests, options) : await this.runSignalCopyBatchChunks(uniqueRequests, options);
|
|
552
|
+
const uniqueResults = await this.runSignalCopyBatchChunks(uniqueRequests, options);
|
|
642
553
|
const results = requests.map((_, index) => ({
|
|
643
554
|
...uniqueResults[deduplicated.sourceIndexByInput[index]],
|
|
644
555
|
index
|
|
@@ -694,22 +605,6 @@ var Signaliz = class {
|
|
|
694
605
|
}
|
|
695
606
|
return uniqueResults;
|
|
696
607
|
}
|
|
697
|
-
async runAvailableSignalCopyBatchJob(requests, options) {
|
|
698
|
-
const rows = await this.runRecoverableCoreBatchJob(
|
|
699
|
-
"api/v1/signal-to-copy",
|
|
700
|
-
requests.map(signalToCopyRequestBody),
|
|
701
|
-
"Signal to Copy",
|
|
702
|
-
500,
|
|
703
|
-
20 * 6e4,
|
|
704
|
-
options?.idempotencyKey
|
|
705
|
-
);
|
|
706
|
-
const results = new Array(requests.length);
|
|
707
|
-
for (const row of rows) {
|
|
708
|
-
const index = Number(row.index);
|
|
709
|
-
results[index] = recoverableJobRowFailed(row) ? batchItemFailure(index, row.error || row.message || "Signal to Copy failed", row) : { index, success: true, data: normalizeSignalToCopyResult(row) };
|
|
710
|
-
}
|
|
711
|
-
return results;
|
|
712
|
-
}
|
|
713
608
|
async runRecoverableCoreBatchJob(path, requests, label, pageSize = 500, maxWaitMs = 20 * 6e4, idempotencyKey) {
|
|
714
609
|
const startedAt = Date.now();
|
|
715
610
|
const submissionIdempotencyKey = idempotencyKey?.trim() || newBatchIdempotencyKey(label);
|
|
@@ -781,77 +676,35 @@ var Signaliz = class {
|
|
|
781
676
|
return rows;
|
|
782
677
|
}
|
|
783
678
|
async runSignalCopyBatchChunk(requests, concurrency, rowRateLimitAttempt = 0) {
|
|
784
|
-
const startedAt = Date.now();
|
|
785
679
|
const results = new Array(requests.length);
|
|
786
680
|
const rateLimited = [];
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
const task = pending[index];
|
|
804
|
-
const item = data.results[index];
|
|
805
|
-
if (item.success === false) {
|
|
806
|
-
if (rowRateLimitAttempt < MAX_ROW_RATE_LIMIT_RETRIES && isRetryableRowRateLimit({
|
|
807
|
-
index: task.index,
|
|
808
|
-
success: false,
|
|
809
|
-
raw: item
|
|
810
|
-
})) {
|
|
811
|
-
rateLimited.push({ index: task.index, params: task.params, raw: item });
|
|
812
|
-
continue;
|
|
813
|
-
}
|
|
814
|
-
results[task.index] = batchItemFailure(
|
|
815
|
-
task.index,
|
|
816
|
-
item.error || item.message || "Signal to Copy failed",
|
|
817
|
-
item
|
|
818
|
-
);
|
|
819
|
-
continue;
|
|
820
|
-
}
|
|
821
|
-
if (!isPendingSignalResponse(item)) {
|
|
822
|
-
results[task.index] = { index: task.index, success: true, data: normalizeSignalToCopyResult(item) };
|
|
823
|
-
continue;
|
|
824
|
-
}
|
|
825
|
-
if (task.params.waitForResult === false) {
|
|
826
|
-
results[task.index] = { index: task.index, success: true, data: normalizeSignalToCopyResult(item) };
|
|
827
|
-
continue;
|
|
828
|
-
}
|
|
829
|
-
const maxWaitMs = Math.max(1e3, task.params.maxWaitMs ?? 20 * 6e4);
|
|
830
|
-
if (Date.now() - startedAt >= maxWaitMs) {
|
|
831
|
-
results[task.index] = {
|
|
832
|
-
index: task.index,
|
|
833
|
-
success: false,
|
|
834
|
-
error: `Signal Copy ${item.signal_run_id || item.run_id || ""} did not complete within ${maxWaitMs}ms`
|
|
835
|
-
};
|
|
836
|
-
continue;
|
|
837
|
-
}
|
|
838
|
-
const signalRunId = item.signal_run_id || item.run_id;
|
|
839
|
-
if (!signalRunId) {
|
|
840
|
-
results[task.index] = { index: task.index, success: false, error: "Signal Copy is processing without a signal_run_id" };
|
|
681
|
+
const data = await this.client.post("api/v1/signal-to-copy", {
|
|
682
|
+
requests: requests.map(signalToCopyRequestBody),
|
|
683
|
+
concurrency
|
|
684
|
+
});
|
|
685
|
+
if (!Array.isArray(data.results) || data.results.length !== requests.length) {
|
|
686
|
+
throw new Error("Signal to Copy batch returned an invalid result count");
|
|
687
|
+
}
|
|
688
|
+
for (let index = 0; index < requests.length; index += 1) {
|
|
689
|
+
const item = data.results[index];
|
|
690
|
+
if (item.success === false) {
|
|
691
|
+
if (rowRateLimitAttempt < MAX_ROW_RATE_LIMIT_RETRIES && isRetryableRowRateLimit({
|
|
692
|
+
index,
|
|
693
|
+
success: false,
|
|
694
|
+
raw: item
|
|
695
|
+
})) {
|
|
696
|
+
rateLimited.push({ index, params: requests[index], raw: item });
|
|
841
697
|
continue;
|
|
842
698
|
}
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
);
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
});
|
|
699
|
+
results[index] = batchItemFailure(index, item.error || item.message || "Signal to Copy failed", item);
|
|
700
|
+
continue;
|
|
701
|
+
}
|
|
702
|
+
try {
|
|
703
|
+
assertTerminalSignalResponse(item, "Signal to Copy");
|
|
704
|
+
results[index] = { index, success: true, data: normalizeSignalToCopyResult(item) };
|
|
705
|
+
} catch (error) {
|
|
706
|
+
results[index] = batchItemFailure(index, error instanceof Error ? error.message : String(error), item);
|
|
852
707
|
}
|
|
853
|
-
pending = nextPending;
|
|
854
|
-
if (pending.length > 0) await sleep2(nextDelayMs);
|
|
855
708
|
}
|
|
856
709
|
if (rateLimited.length > 0) {
|
|
857
710
|
await sleep2(rowRateLimitDelayMs(rateLimited.map((item) => ({
|
|
@@ -870,12 +723,12 @@ var Signaliz = class {
|
|
|
870
723
|
}
|
|
871
724
|
return results;
|
|
872
725
|
}
|
|
873
|
-
async runCoreBatchRound(path, tasks, options,
|
|
726
|
+
async runCoreBatchRound(path, tasks, options, rowRateLimitAttempt = 0) {
|
|
874
727
|
const { serverConcurrency, chunkConcurrency } = batchConcurrencyPlan(options);
|
|
875
728
|
const deduplicated = dedupeExactBatchItems(tasks, (task) => JSON.stringify(task.request));
|
|
876
729
|
const uniqueTasks = deduplicated.uniqueItems;
|
|
877
|
-
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 } :
|
|
878
|
-
if (recoverableBatch && uniqueTasks.length > 25) {
|
|
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) {
|
|
879
732
|
const rows = await this.runRecoverableCoreBatchJob(
|
|
880
733
|
path,
|
|
881
734
|
uniqueTasks.map((task) => task.request),
|
|
@@ -947,7 +800,6 @@ var Signaliz = class {
|
|
|
947
800
|
path,
|
|
948
801
|
retryTasks,
|
|
949
802
|
options,
|
|
950
|
-
void 0,
|
|
951
803
|
rowRateLimitAttempt + 1
|
|
952
804
|
);
|
|
953
805
|
const retriedByIndex = new Map(retried.map((item) => [item.index, item]));
|
|
@@ -1111,41 +963,17 @@ function companySignalRequestBody(params) {
|
|
|
1111
963
|
lookback_days: params.lookbackDays,
|
|
1112
964
|
online,
|
|
1113
965
|
enable_deep_search: params.enableDeepSearch ?? online,
|
|
966
|
+
search_mode: params.searchMode ?? "balanced",
|
|
1114
967
|
include_summary: params.includeSummary,
|
|
1115
968
|
enable_outreach_intelligence: params.enableOutreachIntelligence,
|
|
1116
969
|
enable_predictive_intelligence: params.enablePredictiveIntelligence,
|
|
1117
970
|
skip_cache: params.skipCache,
|
|
1118
|
-
|
|
1119
|
-
// waitForResult controls the SDK polling loop.
|
|
1120
|
-
wait_for_result: false,
|
|
971
|
+
wait_for_result: true,
|
|
1121
972
|
max_wait_ms: params.maxWaitMs,
|
|
1122
973
|
dry_run: params.dryRun,
|
|
1123
974
|
idempotency_key: params.idempotencyKey
|
|
1124
975
|
});
|
|
1125
976
|
}
|
|
1126
|
-
function companySignalRecoverableBatchOptions(companies, tasks) {
|
|
1127
|
-
if (companies.length <= 25 || companies.some((params) => params.waitForResult === false || Boolean(params.signalRunId))) {
|
|
1128
|
-
return void 0;
|
|
1129
|
-
}
|
|
1130
|
-
const maxWaitMs = Math.max(1e3, companies[0].maxWaitMs ?? 20 * 6e4);
|
|
1131
|
-
if (companies.some((params) => Math.max(1e3, params.maxWaitMs ?? 20 * 6e4) !== maxWaitMs)) {
|
|
1132
|
-
return void 0;
|
|
1133
|
-
}
|
|
1134
|
-
const configKey = (request) => {
|
|
1135
|
-
const {
|
|
1136
|
-
company_domain: _companyDomain,
|
|
1137
|
-
company_name: _companyName,
|
|
1138
|
-
signal_run_id: _signalRunId,
|
|
1139
|
-
wait_for_result: _waitForResult,
|
|
1140
|
-
max_wait_ms: _maxWaitMs,
|
|
1141
|
-
...config
|
|
1142
|
-
} = request;
|
|
1143
|
-
return JSON.stringify(config);
|
|
1144
|
-
};
|
|
1145
|
-
const sharedConfig = configKey(tasks[0].request);
|
|
1146
|
-
if (tasks.some((task) => configKey(task.request) !== sharedConfig)) return void 0;
|
|
1147
|
-
return { label: "Company Signals", pageSize: 25, maxWaitMs };
|
|
1148
|
-
}
|
|
1149
977
|
function normalizeCompanySignalResult(params, data) {
|
|
1150
978
|
const rawSignals = data.signals ?? data.signal_feed ?? [];
|
|
1151
979
|
return {
|
|
@@ -1293,6 +1121,7 @@ function signalToCopyRequestBody(params) {
|
|
|
1293
1121
|
signal_run_id: params.signalRunId,
|
|
1294
1122
|
skip_cache: params.skipCache,
|
|
1295
1123
|
enable_deep_search: params.enableDeepSearch,
|
|
1124
|
+
max_wait_ms: params.maxWaitMs,
|
|
1296
1125
|
dry_run: params.dryRun,
|
|
1297
1126
|
idempotency_key: params.idempotencyKey
|
|
1298
1127
|
});
|
|
@@ -1339,11 +1168,10 @@ function normalizeSignalToCopyResult(data) {
|
|
|
1339
1168
|
function isPendingSignalResponse(data) {
|
|
1340
1169
|
return ["triggered", "queued", "processing", "pending", "pending_version", "waiting_for_deploy"].includes(String(data.status || "").toLowerCase());
|
|
1341
1170
|
}
|
|
1342
|
-
function
|
|
1343
|
-
|
|
1344
|
-
}
|
|
1345
|
-
|
|
1346
|
-
return ["failed", "error", "cancelled", "canceled", "crashed", "timed_out"].includes(String(data.status || "").toLowerCase());
|
|
1171
|
+
function assertTerminalSignalResponse(data, capability) {
|
|
1172
|
+
if (isPendingSignalResponse(data) || data.job_id) {
|
|
1173
|
+
throw new Error(`${capability} violated the synchronous response contract.`);
|
|
1174
|
+
}
|
|
1347
1175
|
}
|
|
1348
1176
|
function signalPollDelayMs(data, override) {
|
|
1349
1177
|
if (override !== void 0) return Math.max(250, override);
|
package/dist/index.mjs
CHANGED
package/dist/mcp-config.js
CHANGED
|
@@ -489,34 +489,9 @@ var Signaliz = class {
|
|
|
489
489
|
}
|
|
490
490
|
async enrichCompanySignals(params) {
|
|
491
491
|
const request = companySignalRequestBody(params);
|
|
492
|
-
|
|
492
|
+
const data = await this.client.post("api/v1/company-signals", request);
|
|
493
493
|
if (isCoreProductDryRun(data)) return normalizeCoreProductDryRunResult(data);
|
|
494
|
-
|
|
495
|
-
const maxWaitMs = Math.max(1e3, params.maxWaitMs ?? 20 * 6e4);
|
|
496
|
-
const startedAt = Date.now();
|
|
497
|
-
while (Date.now() - startedAt < maxWaitMs) {
|
|
498
|
-
if (!await waitForNextSignalPoll(data, params.pollIntervalMs, startedAt, maxWaitMs)) break;
|
|
499
|
-
const status = await this.client.post("api/v1/company-signals", {
|
|
500
|
-
...request,
|
|
501
|
-
signal_run_id: data.run_id
|
|
502
|
-
});
|
|
503
|
-
if (isCompletedSignalRun(status)) {
|
|
504
|
-
data = status.output ?? status.result ?? status.data ?? status;
|
|
505
|
-
break;
|
|
506
|
-
}
|
|
507
|
-
if (isFailedSignalRun(status)) {
|
|
508
|
-
throw new Error(`Company signal enrichment ${data.run_id} failed with status ${status.status || "unknown"}`);
|
|
509
|
-
}
|
|
510
|
-
if (!isPendingSignalResponse(status)) {
|
|
511
|
-
data = status.output ?? status.result ?? status.data ?? status;
|
|
512
|
-
break;
|
|
513
|
-
}
|
|
514
|
-
data = status;
|
|
515
|
-
}
|
|
516
|
-
if (isPendingSignalResponse(data)) {
|
|
517
|
-
throw new Error(`Company signal enrichment ${data.run_id} did not complete within ${maxWaitMs}ms`);
|
|
518
|
-
}
|
|
519
|
-
}
|
|
494
|
+
assertTerminalSignalResponse(data, "Company Signals");
|
|
520
495
|
return normalizeCompanySignalResult(params, data);
|
|
521
496
|
}
|
|
522
497
|
async enrichCompanies(companies, options) {
|
|
@@ -529,68 +504,22 @@ var Signaliz = class {
|
|
|
529
504
|
);
|
|
530
505
|
}
|
|
531
506
|
const startedAt = Date.now();
|
|
532
|
-
const results = new Array(companies.length);
|
|
533
507
|
const initialTasks = companies.map((params, index) => ({
|
|
534
508
|
index,
|
|
535
509
|
request: companySignalRequestBody(params)
|
|
536
510
|
}));
|
|
537
|
-
const
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
const round = await this.runCoreBatchRound(
|
|
542
|
-
"api/v1/company-signals",
|
|
543
|
-
pending,
|
|
544
|
-
options,
|
|
545
|
-
firstRound ? recoverableBatch : void 0
|
|
546
|
-
);
|
|
547
|
-
firstRound = false;
|
|
548
|
-
const taskByIndex = new Map(pending.map((task) => [task.index, task]));
|
|
549
|
-
const nextPending = [];
|
|
550
|
-
let nextDelayMs = 6e4;
|
|
551
|
-
for (const item of round) {
|
|
552
|
-
const params = companies[item.index];
|
|
553
|
-
const task = taskByIndex.get(item.index);
|
|
554
|
-
if (!item.success || !item.raw) {
|
|
555
|
-
results[item.index] = batchItemFailure(
|
|
556
|
-
item.index,
|
|
557
|
-
item.error || "Company Signal batch request failed",
|
|
558
|
-
item.raw ?? item
|
|
559
|
-
);
|
|
560
|
-
continue;
|
|
561
|
-
}
|
|
562
|
-
if (!isPendingSignalResponse(item.raw) || params.waitForResult === false) {
|
|
563
|
-
results[item.index] = { index: item.index, success: true, data: normalizeCompanySignalResult(params, item.raw) };
|
|
564
|
-
continue;
|
|
565
|
-
}
|
|
566
|
-
const maxWaitMs = Math.max(1e3, params.maxWaitMs ?? 20 * 6e4);
|
|
567
|
-
if (Date.now() - startedAt >= maxWaitMs) {
|
|
568
|
-
results[item.index] = {
|
|
569
|
-
index: item.index,
|
|
570
|
-
success: false,
|
|
571
|
-
error: `Company signal enrichment ${item.raw.signal_run_id || item.raw.run_id || ""} did not complete within ${maxWaitMs}ms`
|
|
572
|
-
};
|
|
573
|
-
continue;
|
|
574
|
-
}
|
|
575
|
-
const signalRunId = item.raw.signal_run_id || item.raw.run_id;
|
|
576
|
-
if (!signalRunId) {
|
|
577
|
-
results[item.index] = { index: item.index, success: false, error: "Company signal enrichment is processing without a signal_run_id" };
|
|
578
|
-
continue;
|
|
579
|
-
}
|
|
580
|
-
nextDelayMs = Math.min(
|
|
581
|
-
nextDelayMs,
|
|
582
|
-
signalPollDelayMs(item.raw, params.pollIntervalMs),
|
|
583
|
-
maxWaitMs - (Date.now() - startedAt)
|
|
584
|
-
);
|
|
585
|
-
nextPending.push({
|
|
586
|
-
...task,
|
|
587
|
-
request: { ...task.request, signal_run_id: signalRunId }
|
|
588
|
-
});
|
|
511
|
+
const round = await this.runCoreBatchRound("api/v1/company-signals", initialTasks, options);
|
|
512
|
+
const results = round.map((item) => {
|
|
513
|
+
if (!item.success || !item.raw) {
|
|
514
|
+
return batchItemFailure(item.index, item.error || "Company Signal batch request failed", item.raw ?? item);
|
|
589
515
|
}
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
516
|
+
try {
|
|
517
|
+
assertTerminalSignalResponse(item.raw, "Company Signals");
|
|
518
|
+
return { index: item.index, success: true, data: normalizeCompanySignalResult(companies[item.index], item.raw) };
|
|
519
|
+
} catch (error) {
|
|
520
|
+
return batchItemFailure(item.index, error instanceof Error ? error.message : String(error), item.raw);
|
|
521
|
+
}
|
|
522
|
+
});
|
|
594
523
|
const compactedResults = compactExactDuplicateResults(results, options?.compactDuplicates === true);
|
|
595
524
|
const succeeded = compactedResults.filter((item) => item.success).length;
|
|
596
525
|
return {
|
|
@@ -604,21 +533,9 @@ var Signaliz = class {
|
|
|
604
533
|
async signalToCopy(params) {
|
|
605
534
|
validateSignalToCopyParams(params);
|
|
606
535
|
const request = signalToCopyRequestBody(params);
|
|
607
|
-
|
|
536
|
+
const data = await this.client.post("api/v1/signal-to-copy", request);
|
|
608
537
|
if (isCoreProductDryRun(data)) return normalizeCoreProductDryRunResult(data);
|
|
609
|
-
|
|
610
|
-
const maxWaitMs = Math.max(1e3, params.maxWaitMs ?? 20 * 6e4);
|
|
611
|
-
const startedAt = Date.now();
|
|
612
|
-
while (Date.now() - startedAt < maxWaitMs) {
|
|
613
|
-
if (!await waitForNextSignalPoll(data, params.pollIntervalMs, startedAt, maxWaitMs)) break;
|
|
614
|
-
const signalRunId = data.signal_run_id || data.run_id;
|
|
615
|
-
data = await this.client.post("api/v1/signal-to-copy", data.resume_context_persisted === true ? { signal_run_id: signalRunId } : { ...request, signal_run_id: signalRunId });
|
|
616
|
-
if (!isPendingSignalResponse(data)) break;
|
|
617
|
-
}
|
|
618
|
-
if (isPendingSignalResponse(data)) {
|
|
619
|
-
throw new Error(`Signal Copy ${data.run_id} did not complete within ${maxWaitMs}ms`);
|
|
620
|
-
}
|
|
621
|
-
}
|
|
538
|
+
assertTerminalSignalResponse(data, "Signal to Copy");
|
|
622
539
|
return normalizeSignalToCopyResult(data);
|
|
623
540
|
}
|
|
624
541
|
async createSignalCopyBatch(requests, options) {
|
|
@@ -633,16 +550,10 @@ var Signaliz = class {
|
|
|
633
550
|
}
|
|
634
551
|
const startedAt = Date.now();
|
|
635
552
|
const deduplicated = dedupeExactBatchItems(requests, (params) => JSON.stringify({
|
|
636
|
-
request: signalToCopyRequestBody(params)
|
|
637
|
-
wait_for_result: params.waitForResult,
|
|
638
|
-
max_wait_ms: params.maxWaitMs,
|
|
639
|
-
poll_interval_ms: params.pollIntervalMs
|
|
553
|
+
request: signalToCopyRequestBody(params)
|
|
640
554
|
}));
|
|
641
555
|
const uniqueRequests = deduplicated.uniqueItems;
|
|
642
|
-
const
|
|
643
|
-
(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
|
|
644
|
-
);
|
|
645
|
-
const uniqueResults = canUseRecoverableAvailableDataJob ? await this.runAvailableSignalCopyBatchJob(uniqueRequests, options) : await this.runSignalCopyBatchChunks(uniqueRequests, options);
|
|
556
|
+
const uniqueResults = await this.runSignalCopyBatchChunks(uniqueRequests, options);
|
|
646
557
|
const results = requests.map((_, index) => ({
|
|
647
558
|
...uniqueResults[deduplicated.sourceIndexByInput[index]],
|
|
648
559
|
index
|
|
@@ -698,22 +609,6 @@ var Signaliz = class {
|
|
|
698
609
|
}
|
|
699
610
|
return uniqueResults;
|
|
700
611
|
}
|
|
701
|
-
async runAvailableSignalCopyBatchJob(requests, options) {
|
|
702
|
-
const rows = await this.runRecoverableCoreBatchJob(
|
|
703
|
-
"api/v1/signal-to-copy",
|
|
704
|
-
requests.map(signalToCopyRequestBody),
|
|
705
|
-
"Signal to Copy",
|
|
706
|
-
500,
|
|
707
|
-
20 * 6e4,
|
|
708
|
-
options?.idempotencyKey
|
|
709
|
-
);
|
|
710
|
-
const results = new Array(requests.length);
|
|
711
|
-
for (const row of rows) {
|
|
712
|
-
const index = Number(row.index);
|
|
713
|
-
results[index] = recoverableJobRowFailed(row) ? batchItemFailure(index, row.error || row.message || "Signal to Copy failed", row) : { index, success: true, data: normalizeSignalToCopyResult(row) };
|
|
714
|
-
}
|
|
715
|
-
return results;
|
|
716
|
-
}
|
|
717
612
|
async runRecoverableCoreBatchJob(path2, requests, label, pageSize = 500, maxWaitMs = 20 * 6e4, idempotencyKey) {
|
|
718
613
|
const startedAt = Date.now();
|
|
719
614
|
const submissionIdempotencyKey = idempotencyKey?.trim() || newBatchIdempotencyKey(label);
|
|
@@ -785,77 +680,35 @@ var Signaliz = class {
|
|
|
785
680
|
return rows;
|
|
786
681
|
}
|
|
787
682
|
async runSignalCopyBatchChunk(requests, concurrency, rowRateLimitAttempt = 0) {
|
|
788
|
-
const startedAt = Date.now();
|
|
789
683
|
const results = new Array(requests.length);
|
|
790
684
|
const rateLimited = [];
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
const task = pending[index];
|
|
808
|
-
const item = data.results[index];
|
|
809
|
-
if (item.success === false) {
|
|
810
|
-
if (rowRateLimitAttempt < MAX_ROW_RATE_LIMIT_RETRIES && isRetryableRowRateLimit({
|
|
811
|
-
index: task.index,
|
|
812
|
-
success: false,
|
|
813
|
-
raw: item
|
|
814
|
-
})) {
|
|
815
|
-
rateLimited.push({ index: task.index, params: task.params, raw: item });
|
|
816
|
-
continue;
|
|
817
|
-
}
|
|
818
|
-
results[task.index] = batchItemFailure(
|
|
819
|
-
task.index,
|
|
820
|
-
item.error || item.message || "Signal to Copy failed",
|
|
821
|
-
item
|
|
822
|
-
);
|
|
823
|
-
continue;
|
|
824
|
-
}
|
|
825
|
-
if (!isPendingSignalResponse(item)) {
|
|
826
|
-
results[task.index] = { index: task.index, success: true, data: normalizeSignalToCopyResult(item) };
|
|
827
|
-
continue;
|
|
828
|
-
}
|
|
829
|
-
if (task.params.waitForResult === false) {
|
|
830
|
-
results[task.index] = { index: task.index, success: true, data: normalizeSignalToCopyResult(item) };
|
|
831
|
-
continue;
|
|
832
|
-
}
|
|
833
|
-
const maxWaitMs = Math.max(1e3, task.params.maxWaitMs ?? 20 * 6e4);
|
|
834
|
-
if (Date.now() - startedAt >= maxWaitMs) {
|
|
835
|
-
results[task.index] = {
|
|
836
|
-
index: task.index,
|
|
837
|
-
success: false,
|
|
838
|
-
error: `Signal Copy ${item.signal_run_id || item.run_id || ""} did not complete within ${maxWaitMs}ms`
|
|
839
|
-
};
|
|
840
|
-
continue;
|
|
841
|
-
}
|
|
842
|
-
const signalRunId = item.signal_run_id || item.run_id;
|
|
843
|
-
if (!signalRunId) {
|
|
844
|
-
results[task.index] = { index: task.index, success: false, error: "Signal Copy is processing without a signal_run_id" };
|
|
685
|
+
const data = await this.client.post("api/v1/signal-to-copy", {
|
|
686
|
+
requests: requests.map(signalToCopyRequestBody),
|
|
687
|
+
concurrency
|
|
688
|
+
});
|
|
689
|
+
if (!Array.isArray(data.results) || data.results.length !== requests.length) {
|
|
690
|
+
throw new Error("Signal to Copy batch returned an invalid result count");
|
|
691
|
+
}
|
|
692
|
+
for (let index = 0; index < requests.length; index += 1) {
|
|
693
|
+
const item = data.results[index];
|
|
694
|
+
if (item.success === false) {
|
|
695
|
+
if (rowRateLimitAttempt < MAX_ROW_RATE_LIMIT_RETRIES && isRetryableRowRateLimit({
|
|
696
|
+
index,
|
|
697
|
+
success: false,
|
|
698
|
+
raw: item
|
|
699
|
+
})) {
|
|
700
|
+
rateLimited.push({ index, params: requests[index], raw: item });
|
|
845
701
|
continue;
|
|
846
702
|
}
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
);
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
});
|
|
703
|
+
results[index] = batchItemFailure(index, item.error || item.message || "Signal to Copy failed", item);
|
|
704
|
+
continue;
|
|
705
|
+
}
|
|
706
|
+
try {
|
|
707
|
+
assertTerminalSignalResponse(item, "Signal to Copy");
|
|
708
|
+
results[index] = { index, success: true, data: normalizeSignalToCopyResult(item) };
|
|
709
|
+
} catch (error) {
|
|
710
|
+
results[index] = batchItemFailure(index, error instanceof Error ? error.message : String(error), item);
|
|
856
711
|
}
|
|
857
|
-
pending = nextPending;
|
|
858
|
-
if (pending.length > 0) await sleep2(nextDelayMs);
|
|
859
712
|
}
|
|
860
713
|
if (rateLimited.length > 0) {
|
|
861
714
|
await sleep2(rowRateLimitDelayMs(rateLimited.map((item) => ({
|
|
@@ -874,12 +727,12 @@ var Signaliz = class {
|
|
|
874
727
|
}
|
|
875
728
|
return results;
|
|
876
729
|
}
|
|
877
|
-
async runCoreBatchRound(path2, tasks, options,
|
|
730
|
+
async runCoreBatchRound(path2, tasks, options, rowRateLimitAttempt = 0) {
|
|
878
731
|
const { serverConcurrency, chunkConcurrency } = batchConcurrencyPlan(options);
|
|
879
732
|
const deduplicated = dedupeExactBatchItems(tasks, (task) => JSON.stringify(task.request));
|
|
880
733
|
const uniqueTasks = deduplicated.uniqueItems;
|
|
881
|
-
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 } :
|
|
882
|
-
if (recoverableBatch && uniqueTasks.length > 25) {
|
|
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) {
|
|
883
736
|
const rows = await this.runRecoverableCoreBatchJob(
|
|
884
737
|
path2,
|
|
885
738
|
uniqueTasks.map((task) => task.request),
|
|
@@ -951,7 +804,6 @@ var Signaliz = class {
|
|
|
951
804
|
path2,
|
|
952
805
|
retryTasks,
|
|
953
806
|
options,
|
|
954
|
-
void 0,
|
|
955
807
|
rowRateLimitAttempt + 1
|
|
956
808
|
);
|
|
957
809
|
const retriedByIndex = new Map(retried.map((item) => [item.index, item]));
|
|
@@ -1115,41 +967,17 @@ function companySignalRequestBody(params) {
|
|
|
1115
967
|
lookback_days: params.lookbackDays,
|
|
1116
968
|
online,
|
|
1117
969
|
enable_deep_search: params.enableDeepSearch ?? online,
|
|
970
|
+
search_mode: params.searchMode ?? "balanced",
|
|
1118
971
|
include_summary: params.includeSummary,
|
|
1119
972
|
enable_outreach_intelligence: params.enableOutreachIntelligence,
|
|
1120
973
|
enable_predictive_intelligence: params.enablePredictiveIntelligence,
|
|
1121
974
|
skip_cache: params.skipCache,
|
|
1122
|
-
|
|
1123
|
-
// waitForResult controls the SDK polling loop.
|
|
1124
|
-
wait_for_result: false,
|
|
975
|
+
wait_for_result: true,
|
|
1125
976
|
max_wait_ms: params.maxWaitMs,
|
|
1126
977
|
dry_run: params.dryRun,
|
|
1127
978
|
idempotency_key: params.idempotencyKey
|
|
1128
979
|
});
|
|
1129
980
|
}
|
|
1130
|
-
function companySignalRecoverableBatchOptions(companies, tasks) {
|
|
1131
|
-
if (companies.length <= 25 || companies.some((params) => params.waitForResult === false || Boolean(params.signalRunId))) {
|
|
1132
|
-
return void 0;
|
|
1133
|
-
}
|
|
1134
|
-
const maxWaitMs = Math.max(1e3, companies[0].maxWaitMs ?? 20 * 6e4);
|
|
1135
|
-
if (companies.some((params) => Math.max(1e3, params.maxWaitMs ?? 20 * 6e4) !== maxWaitMs)) {
|
|
1136
|
-
return void 0;
|
|
1137
|
-
}
|
|
1138
|
-
const configKey = (request) => {
|
|
1139
|
-
const {
|
|
1140
|
-
company_domain: _companyDomain,
|
|
1141
|
-
company_name: _companyName,
|
|
1142
|
-
signal_run_id: _signalRunId,
|
|
1143
|
-
wait_for_result: _waitForResult,
|
|
1144
|
-
max_wait_ms: _maxWaitMs,
|
|
1145
|
-
...config
|
|
1146
|
-
} = request;
|
|
1147
|
-
return JSON.stringify(config);
|
|
1148
|
-
};
|
|
1149
|
-
const sharedConfig = configKey(tasks[0].request);
|
|
1150
|
-
if (tasks.some((task) => configKey(task.request) !== sharedConfig)) return void 0;
|
|
1151
|
-
return { label: "Company Signals", pageSize: 25, maxWaitMs };
|
|
1152
|
-
}
|
|
1153
981
|
function normalizeCompanySignalResult(params, data) {
|
|
1154
982
|
const rawSignals = data.signals ?? data.signal_feed ?? [];
|
|
1155
983
|
return {
|
|
@@ -1297,6 +1125,7 @@ function signalToCopyRequestBody(params) {
|
|
|
1297
1125
|
signal_run_id: params.signalRunId,
|
|
1298
1126
|
skip_cache: params.skipCache,
|
|
1299
1127
|
enable_deep_search: params.enableDeepSearch,
|
|
1128
|
+
max_wait_ms: params.maxWaitMs,
|
|
1300
1129
|
dry_run: params.dryRun,
|
|
1301
1130
|
idempotency_key: params.idempotencyKey
|
|
1302
1131
|
});
|
|
@@ -1343,11 +1172,10 @@ function normalizeSignalToCopyResult(data) {
|
|
|
1343
1172
|
function isPendingSignalResponse(data) {
|
|
1344
1173
|
return ["triggered", "queued", "processing", "pending", "pending_version", "waiting_for_deploy"].includes(String(data.status || "").toLowerCase());
|
|
1345
1174
|
}
|
|
1346
|
-
function
|
|
1347
|
-
|
|
1348
|
-
}
|
|
1349
|
-
|
|
1350
|
-
return ["failed", "error", "cancelled", "canceled", "crashed", "timed_out"].includes(String(data.status || "").toLowerCase());
|
|
1175
|
+
function assertTerminalSignalResponse(data, capability) {
|
|
1176
|
+
if (isPendingSignalResponse(data) || data.job_id) {
|
|
1177
|
+
throw new Error(`${capability} violated the synchronous response contract.`);
|
|
1178
|
+
}
|
|
1351
1179
|
}
|
|
1352
1180
|
function signalPollDelayMs(data, override) {
|
|
1353
1181
|
if (override !== void 0) return Math.max(250, override);
|
package/dist/mcp-config.mjs
CHANGED
package/package.json
CHANGED