@signaliz/sdk 1.0.30 → 1.0.32
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 +6 -3
- package/dist/{chunk-INM326KO.mjs → chunk-JO4MYKSK.mjs} +106 -19
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +106 -19
- package/dist/index.mjs +1 -1
- package/dist/mcp-config.js +106 -19
- package/dist/mcp-config.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,9 +77,12 @@ resumes long-running research through the same `/company-signals` endpoint;
|
|
|
77
77
|
callers never need an internal Trigger.dev status URL. The SDK follows the
|
|
78
78
|
server's adaptive polling hints by default and still honors `pollIntervalMs`
|
|
79
79
|
when a caller explicitly overrides the cadence.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
Signal
|
|
80
|
+
Exact duplicate tasks are single-flighted across each full batch without
|
|
81
|
+
changing input order or result cardinality. Find Email, Verify Email, and
|
|
82
|
+
Company Signal Enrichment use 25-row REST chunks. Signal to Copy batches larger
|
|
83
|
+
than 25 use one recoverable REST job when they can reuse available signal data;
|
|
84
|
+
fresh or deep-search requests keep the 25-row path. Signal to Copy also shares
|
|
85
|
+
company research across copy recipients.
|
|
83
86
|
|
|
84
87
|
Company Signal Enrichment defaults `online` and `enableDeepSearch` to `true`
|
|
85
88
|
unless the caller explicitly disables them. Signal to Copy AI returns three
|
|
@@ -511,9 +511,34 @@ var Signaliz = class {
|
|
|
511
511
|
async createSignalCopyBatch(requests, options) {
|
|
512
512
|
validateBatchSize(requests);
|
|
513
513
|
const startedAt = Date.now();
|
|
514
|
+
const deduplicated = dedupeExactBatchItems(requests, (params) => JSON.stringify({
|
|
515
|
+
request: signalToCopyRequestBody(params),
|
|
516
|
+
wait_for_result: params.waitForResult,
|
|
517
|
+
max_wait_ms: params.maxWaitMs,
|
|
518
|
+
poll_interval_ms: params.pollIntervalMs
|
|
519
|
+
}));
|
|
520
|
+
const uniqueRequests = deduplicated.uniqueItems;
|
|
521
|
+
const canUseRecoverableAvailableDataJob = uniqueRequests.length > 25 && uniqueRequests.every(
|
|
522
|
+
(params) => params.waitForResult !== false && params.skipCache !== true && params.enableDeepSearch !== true && params.maxWaitMs === void 0 && params.pollIntervalMs === void 0
|
|
523
|
+
);
|
|
524
|
+
const uniqueResults = canUseRecoverableAvailableDataJob ? await this.runAvailableSignalCopyBatchJob(uniqueRequests) : await this.runSignalCopyBatchChunks(uniqueRequests, options);
|
|
525
|
+
const results = requests.map((_, index) => ({
|
|
526
|
+
...uniqueResults[deduplicated.sourceIndexByInput[index]],
|
|
527
|
+
index
|
|
528
|
+
}));
|
|
529
|
+
const succeeded = results.filter((item) => item.success).length;
|
|
530
|
+
return {
|
|
531
|
+
total: requests.length,
|
|
532
|
+
succeeded,
|
|
533
|
+
failed: requests.length - succeeded,
|
|
534
|
+
durationMs: Date.now() - startedAt,
|
|
535
|
+
results
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
async runSignalCopyBatchChunks(uniqueRequests, options) {
|
|
514
539
|
const chunks = [];
|
|
515
|
-
for (let offset = 0; offset <
|
|
516
|
-
chunks.push({ offset, requests:
|
|
540
|
+
for (let offset = 0; offset < uniqueRequests.length; offset += 25) {
|
|
541
|
+
chunks.push({ offset, requests: uniqueRequests.slice(offset, offset + 25) });
|
|
517
542
|
}
|
|
518
543
|
const { serverConcurrency, chunkConcurrency } = batchConcurrencyPlan(options);
|
|
519
544
|
const chunkBatch = await runBatch(
|
|
@@ -521,12 +546,12 @@ var Signaliz = class {
|
|
|
521
546
|
(chunk) => this.runSignalCopyBatchChunk(chunk.requests, serverConcurrency),
|
|
522
547
|
{ concurrency: chunkConcurrency }
|
|
523
548
|
);
|
|
524
|
-
const
|
|
549
|
+
const uniqueResults = new Array(uniqueRequests.length);
|
|
525
550
|
for (const chunkResult of chunkBatch.results) {
|
|
526
551
|
const chunk = chunks[chunkResult.index];
|
|
527
552
|
if (!chunkResult.success || !chunkResult.data) {
|
|
528
553
|
for (let index = 0; index < chunk.requests.length; index += 1) {
|
|
529
|
-
|
|
554
|
+
uniqueResults[chunk.offset + index] = {
|
|
530
555
|
index: chunk.offset + index,
|
|
531
556
|
success: false,
|
|
532
557
|
error: chunkResult.error || "Signal to Copy batch request failed"
|
|
@@ -535,17 +560,58 @@ var Signaliz = class {
|
|
|
535
560
|
continue;
|
|
536
561
|
}
|
|
537
562
|
for (const item of chunkResult.data) {
|
|
538
|
-
|
|
563
|
+
uniqueResults[chunk.offset + item.index] = { ...item, index: chunk.offset + item.index };
|
|
539
564
|
}
|
|
540
565
|
}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
};
|
|
566
|
+
return uniqueResults;
|
|
567
|
+
}
|
|
568
|
+
async runAvailableSignalCopyBatchJob(requests) {
|
|
569
|
+
const startedAt = Date.now();
|
|
570
|
+
const maxWaitMs = 20 * 6e4;
|
|
571
|
+
let status = await this.client.post("api/v1/signal-to-copy", {
|
|
572
|
+
requests: requests.map(signalToCopyRequestBody)
|
|
573
|
+
});
|
|
574
|
+
const jobId = String(status.job_id || "").trim();
|
|
575
|
+
if (!jobId) throw new Error("Signal to Copy batch did not return a recoverable job_id");
|
|
576
|
+
while (!["completed", "partial", "failed"].includes(String(status.status || "").toLowerCase())) {
|
|
577
|
+
if (Date.now() - startedAt >= maxWaitMs) {
|
|
578
|
+
throw new Error(`Signal to Copy batch ${jobId} did not complete within ${maxWaitMs}ms`);
|
|
579
|
+
}
|
|
580
|
+
const retryAfterMs = Number(status.next_poll_after_seconds || 2) * 1e3;
|
|
581
|
+
await sleep2(Math.min(Math.max(250, retryAfterMs), maxWaitMs - (Date.now() - startedAt)));
|
|
582
|
+
status = await this.client.post("api/v1/signal-to-copy", {
|
|
583
|
+
job_id: jobId,
|
|
584
|
+
page: 1,
|
|
585
|
+
page_size: 500
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
const totalPages = Math.max(1, Number(status.total_pages || 1));
|
|
589
|
+
const pages = [Array.isArray(status.results) ? status.results : []];
|
|
590
|
+
if (totalPages > 1) {
|
|
591
|
+
const remainingPages = await Promise.all(Array.from(
|
|
592
|
+
{ length: totalPages - 1 },
|
|
593
|
+
(_, index) => this.client.post("api/v1/signal-to-copy", {
|
|
594
|
+
job_id: jobId,
|
|
595
|
+
page: index + 2,
|
|
596
|
+
page_size: 500
|
|
597
|
+
})
|
|
598
|
+
));
|
|
599
|
+
for (const page of remainingPages) pages.push(Array.isArray(page.results) ? page.results : []);
|
|
600
|
+
}
|
|
601
|
+
const rows = pages.flat();
|
|
602
|
+
if (rows.length !== requests.length) {
|
|
603
|
+
throw new Error(`Signal to Copy batch returned ${rows.length} results for ${requests.length} requests`);
|
|
604
|
+
}
|
|
605
|
+
const results = new Array(requests.length);
|
|
606
|
+
for (const row of rows) {
|
|
607
|
+
const index = Number(row.index);
|
|
608
|
+
if (!Number.isInteger(index) || index < 0 || index >= requests.length) {
|
|
609
|
+
throw new Error("Signal to Copy batch returned an invalid result index");
|
|
610
|
+
}
|
|
611
|
+
results[index] = row.success === false ? { index, success: false, error: row.error || row.message || "Signal to Copy failed" } : { index, success: true, data: normalizeSignalToCopyResult(row) };
|
|
612
|
+
}
|
|
613
|
+
if (results.some((item) => !item)) throw new Error("Signal to Copy batch returned incomplete indexed results");
|
|
614
|
+
return results;
|
|
549
615
|
}
|
|
550
616
|
async runSignalCopyBatchChunk(requests, concurrency) {
|
|
551
617
|
const startedAt = Date.now();
|
|
@@ -611,9 +677,11 @@ var Signaliz = class {
|
|
|
611
677
|
}
|
|
612
678
|
async runCoreBatchRound(path, tasks, options) {
|
|
613
679
|
const { serverConcurrency, chunkConcurrency } = batchConcurrencyPlan(options);
|
|
680
|
+
const deduplicated = dedupeExactBatchItems(tasks, (task) => JSON.stringify(task.request));
|
|
681
|
+
const uniqueTasks = deduplicated.uniqueItems;
|
|
614
682
|
const chunks = [];
|
|
615
|
-
for (let offset = 0; offset <
|
|
616
|
-
chunks.push({ offset, tasks:
|
|
683
|
+
for (let offset = 0; offset < uniqueTasks.length; offset += 25) {
|
|
684
|
+
chunks.push({ offset, tasks: uniqueTasks.slice(offset, offset + 25) });
|
|
617
685
|
}
|
|
618
686
|
const chunkBatch = await runBatch(chunks, async (chunk) => {
|
|
619
687
|
const data = await this.client.post(path, {
|
|
@@ -628,12 +696,12 @@ var Signaliz = class {
|
|
|
628
696
|
}
|
|
629
697
|
return data.results;
|
|
630
698
|
}, { concurrency: chunkConcurrency });
|
|
631
|
-
const
|
|
699
|
+
const uniqueResults = new Array(uniqueTasks.length);
|
|
632
700
|
for (const chunkResult of chunkBatch.results) {
|
|
633
701
|
const chunk = chunks[chunkResult.index];
|
|
634
702
|
if (!chunkResult.success || !chunkResult.data) {
|
|
635
703
|
for (let index = 0; index < chunk.tasks.length; index += 1) {
|
|
636
|
-
|
|
704
|
+
uniqueResults[chunk.offset + index] = {
|
|
637
705
|
index: chunk.tasks[index].index,
|
|
638
706
|
success: false,
|
|
639
707
|
error: chunkResult.error || `${path} batch request failed`
|
|
@@ -643,7 +711,7 @@ var Signaliz = class {
|
|
|
643
711
|
}
|
|
644
712
|
for (let index = 0; index < chunkResult.data.length; index += 1) {
|
|
645
713
|
const raw = chunkResult.data[index];
|
|
646
|
-
|
|
714
|
+
uniqueResults[chunk.offset + index] = {
|
|
647
715
|
index: chunk.tasks[index].index,
|
|
648
716
|
success: raw.success !== false,
|
|
649
717
|
raw,
|
|
@@ -651,7 +719,10 @@ var Signaliz = class {
|
|
|
651
719
|
};
|
|
652
720
|
}
|
|
653
721
|
}
|
|
654
|
-
return
|
|
722
|
+
return tasks.map((task, index) => ({
|
|
723
|
+
...uniqueResults[deduplicated.sourceIndexByInput[index]],
|
|
724
|
+
index: task.index
|
|
725
|
+
}));
|
|
655
726
|
}
|
|
656
727
|
async listTools() {
|
|
657
728
|
const result = await this.client.mcp("tools/list");
|
|
@@ -808,6 +879,22 @@ function batchConcurrencyPlan(options) {
|
|
|
808
879
|
chunkConcurrency: Math.max(1, Math.floor(concurrency / serverConcurrency))
|
|
809
880
|
};
|
|
810
881
|
}
|
|
882
|
+
function dedupeExactBatchItems(items, keyForItem) {
|
|
883
|
+
const uniqueItems = [];
|
|
884
|
+
const sourceIndexByInput = [];
|
|
885
|
+
const uniqueIndexByKey = /* @__PURE__ */ new Map();
|
|
886
|
+
for (const item of items) {
|
|
887
|
+
const key = keyForItem(item);
|
|
888
|
+
let uniqueIndex = uniqueIndexByKey.get(key);
|
|
889
|
+
if (uniqueIndex === void 0) {
|
|
890
|
+
uniqueIndex = uniqueItems.length;
|
|
891
|
+
uniqueIndexByKey.set(key, uniqueIndex);
|
|
892
|
+
uniqueItems.push(item);
|
|
893
|
+
}
|
|
894
|
+
sourceIndexByInput.push(uniqueIndex);
|
|
895
|
+
}
|
|
896
|
+
return { uniqueItems, sourceIndexByInput };
|
|
897
|
+
}
|
|
811
898
|
function finalizeCoreBatch(total, startedAt, round, normalize) {
|
|
812
899
|
const results = new Array(total);
|
|
813
900
|
for (const item of round) {
|
package/dist/index.d.mts
CHANGED
|
@@ -203,6 +203,8 @@ declare class Signaliz {
|
|
|
203
203
|
enrichCompanies(companies: CompanySignalEnrichmentParams[], options?: BatchOptions): Promise<BatchResult<CompanySignalEnrichmentResult>>;
|
|
204
204
|
signalToCopy(params: SignalToCopyParams): Promise<SignalToCopyResult>;
|
|
205
205
|
createSignalCopyBatch(requests: SignalToCopyParams[], options?: BatchOptions): Promise<BatchResult<SignalToCopyResult>>;
|
|
206
|
+
private runSignalCopyBatchChunks;
|
|
207
|
+
private runAvailableSignalCopyBatchJob;
|
|
206
208
|
private runSignalCopyBatchChunk;
|
|
207
209
|
private runCoreBatchRound;
|
|
208
210
|
listTools(): Promise<MCPToolInfo[]>;
|
package/dist/index.d.ts
CHANGED
|
@@ -203,6 +203,8 @@ declare class Signaliz {
|
|
|
203
203
|
enrichCompanies(companies: CompanySignalEnrichmentParams[], options?: BatchOptions): Promise<BatchResult<CompanySignalEnrichmentResult>>;
|
|
204
204
|
signalToCopy(params: SignalToCopyParams): Promise<SignalToCopyResult>;
|
|
205
205
|
createSignalCopyBatch(requests: SignalToCopyParams[], options?: BatchOptions): Promise<BatchResult<SignalToCopyResult>>;
|
|
206
|
+
private runSignalCopyBatchChunks;
|
|
207
|
+
private runAvailableSignalCopyBatchJob;
|
|
206
208
|
private runSignalCopyBatchChunk;
|
|
207
209
|
private runCoreBatchRound;
|
|
208
210
|
listTools(): Promise<MCPToolInfo[]>;
|
package/dist/index.js
CHANGED
|
@@ -538,9 +538,34 @@ var Signaliz = class {
|
|
|
538
538
|
async createSignalCopyBatch(requests, options) {
|
|
539
539
|
validateBatchSize(requests);
|
|
540
540
|
const startedAt = Date.now();
|
|
541
|
+
const deduplicated = dedupeExactBatchItems(requests, (params) => JSON.stringify({
|
|
542
|
+
request: signalToCopyRequestBody(params),
|
|
543
|
+
wait_for_result: params.waitForResult,
|
|
544
|
+
max_wait_ms: params.maxWaitMs,
|
|
545
|
+
poll_interval_ms: params.pollIntervalMs
|
|
546
|
+
}));
|
|
547
|
+
const uniqueRequests = deduplicated.uniqueItems;
|
|
548
|
+
const canUseRecoverableAvailableDataJob = uniqueRequests.length > 25 && uniqueRequests.every(
|
|
549
|
+
(params) => params.waitForResult !== false && params.skipCache !== true && params.enableDeepSearch !== true && params.maxWaitMs === void 0 && params.pollIntervalMs === void 0
|
|
550
|
+
);
|
|
551
|
+
const uniqueResults = canUseRecoverableAvailableDataJob ? await this.runAvailableSignalCopyBatchJob(uniqueRequests) : await this.runSignalCopyBatchChunks(uniqueRequests, options);
|
|
552
|
+
const results = requests.map((_, index) => ({
|
|
553
|
+
...uniqueResults[deduplicated.sourceIndexByInput[index]],
|
|
554
|
+
index
|
|
555
|
+
}));
|
|
556
|
+
const succeeded = results.filter((item) => item.success).length;
|
|
557
|
+
return {
|
|
558
|
+
total: requests.length,
|
|
559
|
+
succeeded,
|
|
560
|
+
failed: requests.length - succeeded,
|
|
561
|
+
durationMs: Date.now() - startedAt,
|
|
562
|
+
results
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
async runSignalCopyBatchChunks(uniqueRequests, options) {
|
|
541
566
|
const chunks = [];
|
|
542
|
-
for (let offset = 0; offset <
|
|
543
|
-
chunks.push({ offset, requests:
|
|
567
|
+
for (let offset = 0; offset < uniqueRequests.length; offset += 25) {
|
|
568
|
+
chunks.push({ offset, requests: uniqueRequests.slice(offset, offset + 25) });
|
|
544
569
|
}
|
|
545
570
|
const { serverConcurrency, chunkConcurrency } = batchConcurrencyPlan(options);
|
|
546
571
|
const chunkBatch = await runBatch(
|
|
@@ -548,12 +573,12 @@ var Signaliz = class {
|
|
|
548
573
|
(chunk) => this.runSignalCopyBatchChunk(chunk.requests, serverConcurrency),
|
|
549
574
|
{ concurrency: chunkConcurrency }
|
|
550
575
|
);
|
|
551
|
-
const
|
|
576
|
+
const uniqueResults = new Array(uniqueRequests.length);
|
|
552
577
|
for (const chunkResult of chunkBatch.results) {
|
|
553
578
|
const chunk = chunks[chunkResult.index];
|
|
554
579
|
if (!chunkResult.success || !chunkResult.data) {
|
|
555
580
|
for (let index = 0; index < chunk.requests.length; index += 1) {
|
|
556
|
-
|
|
581
|
+
uniqueResults[chunk.offset + index] = {
|
|
557
582
|
index: chunk.offset + index,
|
|
558
583
|
success: false,
|
|
559
584
|
error: chunkResult.error || "Signal to Copy batch request failed"
|
|
@@ -562,17 +587,58 @@ var Signaliz = class {
|
|
|
562
587
|
continue;
|
|
563
588
|
}
|
|
564
589
|
for (const item of chunkResult.data) {
|
|
565
|
-
|
|
590
|
+
uniqueResults[chunk.offset + item.index] = { ...item, index: chunk.offset + item.index };
|
|
566
591
|
}
|
|
567
592
|
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
};
|
|
593
|
+
return uniqueResults;
|
|
594
|
+
}
|
|
595
|
+
async runAvailableSignalCopyBatchJob(requests) {
|
|
596
|
+
const startedAt = Date.now();
|
|
597
|
+
const maxWaitMs = 20 * 6e4;
|
|
598
|
+
let status = await this.client.post("api/v1/signal-to-copy", {
|
|
599
|
+
requests: requests.map(signalToCopyRequestBody)
|
|
600
|
+
});
|
|
601
|
+
const jobId = String(status.job_id || "").trim();
|
|
602
|
+
if (!jobId) throw new Error("Signal to Copy batch did not return a recoverable job_id");
|
|
603
|
+
while (!["completed", "partial", "failed"].includes(String(status.status || "").toLowerCase())) {
|
|
604
|
+
if (Date.now() - startedAt >= maxWaitMs) {
|
|
605
|
+
throw new Error(`Signal to Copy batch ${jobId} did not complete within ${maxWaitMs}ms`);
|
|
606
|
+
}
|
|
607
|
+
const retryAfterMs = Number(status.next_poll_after_seconds || 2) * 1e3;
|
|
608
|
+
await sleep2(Math.min(Math.max(250, retryAfterMs), maxWaitMs - (Date.now() - startedAt)));
|
|
609
|
+
status = await this.client.post("api/v1/signal-to-copy", {
|
|
610
|
+
job_id: jobId,
|
|
611
|
+
page: 1,
|
|
612
|
+
page_size: 500
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
const totalPages = Math.max(1, Number(status.total_pages || 1));
|
|
616
|
+
const pages = [Array.isArray(status.results) ? status.results : []];
|
|
617
|
+
if (totalPages > 1) {
|
|
618
|
+
const remainingPages = await Promise.all(Array.from(
|
|
619
|
+
{ length: totalPages - 1 },
|
|
620
|
+
(_, index) => this.client.post("api/v1/signal-to-copy", {
|
|
621
|
+
job_id: jobId,
|
|
622
|
+
page: index + 2,
|
|
623
|
+
page_size: 500
|
|
624
|
+
})
|
|
625
|
+
));
|
|
626
|
+
for (const page of remainingPages) pages.push(Array.isArray(page.results) ? page.results : []);
|
|
627
|
+
}
|
|
628
|
+
const rows = pages.flat();
|
|
629
|
+
if (rows.length !== requests.length) {
|
|
630
|
+
throw new Error(`Signal to Copy batch returned ${rows.length} results for ${requests.length} requests`);
|
|
631
|
+
}
|
|
632
|
+
const results = new Array(requests.length);
|
|
633
|
+
for (const row of rows) {
|
|
634
|
+
const index = Number(row.index);
|
|
635
|
+
if (!Number.isInteger(index) || index < 0 || index >= requests.length) {
|
|
636
|
+
throw new Error("Signal to Copy batch returned an invalid result index");
|
|
637
|
+
}
|
|
638
|
+
results[index] = row.success === false ? { index, success: false, error: row.error || row.message || "Signal to Copy failed" } : { index, success: true, data: normalizeSignalToCopyResult(row) };
|
|
639
|
+
}
|
|
640
|
+
if (results.some((item) => !item)) throw new Error("Signal to Copy batch returned incomplete indexed results");
|
|
641
|
+
return results;
|
|
576
642
|
}
|
|
577
643
|
async runSignalCopyBatchChunk(requests, concurrency) {
|
|
578
644
|
const startedAt = Date.now();
|
|
@@ -638,9 +704,11 @@ var Signaliz = class {
|
|
|
638
704
|
}
|
|
639
705
|
async runCoreBatchRound(path, tasks, options) {
|
|
640
706
|
const { serverConcurrency, chunkConcurrency } = batchConcurrencyPlan(options);
|
|
707
|
+
const deduplicated = dedupeExactBatchItems(tasks, (task) => JSON.stringify(task.request));
|
|
708
|
+
const uniqueTasks = deduplicated.uniqueItems;
|
|
641
709
|
const chunks = [];
|
|
642
|
-
for (let offset = 0; offset <
|
|
643
|
-
chunks.push({ offset, tasks:
|
|
710
|
+
for (let offset = 0; offset < uniqueTasks.length; offset += 25) {
|
|
711
|
+
chunks.push({ offset, tasks: uniqueTasks.slice(offset, offset + 25) });
|
|
644
712
|
}
|
|
645
713
|
const chunkBatch = await runBatch(chunks, async (chunk) => {
|
|
646
714
|
const data = await this.client.post(path, {
|
|
@@ -655,12 +723,12 @@ var Signaliz = class {
|
|
|
655
723
|
}
|
|
656
724
|
return data.results;
|
|
657
725
|
}, { concurrency: chunkConcurrency });
|
|
658
|
-
const
|
|
726
|
+
const uniqueResults = new Array(uniqueTasks.length);
|
|
659
727
|
for (const chunkResult of chunkBatch.results) {
|
|
660
728
|
const chunk = chunks[chunkResult.index];
|
|
661
729
|
if (!chunkResult.success || !chunkResult.data) {
|
|
662
730
|
for (let index = 0; index < chunk.tasks.length; index += 1) {
|
|
663
|
-
|
|
731
|
+
uniqueResults[chunk.offset + index] = {
|
|
664
732
|
index: chunk.tasks[index].index,
|
|
665
733
|
success: false,
|
|
666
734
|
error: chunkResult.error || `${path} batch request failed`
|
|
@@ -670,7 +738,7 @@ var Signaliz = class {
|
|
|
670
738
|
}
|
|
671
739
|
for (let index = 0; index < chunkResult.data.length; index += 1) {
|
|
672
740
|
const raw = chunkResult.data[index];
|
|
673
|
-
|
|
741
|
+
uniqueResults[chunk.offset + index] = {
|
|
674
742
|
index: chunk.tasks[index].index,
|
|
675
743
|
success: raw.success !== false,
|
|
676
744
|
raw,
|
|
@@ -678,7 +746,10 @@ var Signaliz = class {
|
|
|
678
746
|
};
|
|
679
747
|
}
|
|
680
748
|
}
|
|
681
|
-
return
|
|
749
|
+
return tasks.map((task, index) => ({
|
|
750
|
+
...uniqueResults[deduplicated.sourceIndexByInput[index]],
|
|
751
|
+
index: task.index
|
|
752
|
+
}));
|
|
682
753
|
}
|
|
683
754
|
async listTools() {
|
|
684
755
|
const result = await this.client.mcp("tools/list");
|
|
@@ -835,6 +906,22 @@ function batchConcurrencyPlan(options) {
|
|
|
835
906
|
chunkConcurrency: Math.max(1, Math.floor(concurrency / serverConcurrency))
|
|
836
907
|
};
|
|
837
908
|
}
|
|
909
|
+
function dedupeExactBatchItems(items, keyForItem) {
|
|
910
|
+
const uniqueItems = [];
|
|
911
|
+
const sourceIndexByInput = [];
|
|
912
|
+
const uniqueIndexByKey = /* @__PURE__ */ new Map();
|
|
913
|
+
for (const item of items) {
|
|
914
|
+
const key = keyForItem(item);
|
|
915
|
+
let uniqueIndex = uniqueIndexByKey.get(key);
|
|
916
|
+
if (uniqueIndex === void 0) {
|
|
917
|
+
uniqueIndex = uniqueItems.length;
|
|
918
|
+
uniqueIndexByKey.set(key, uniqueIndex);
|
|
919
|
+
uniqueItems.push(item);
|
|
920
|
+
}
|
|
921
|
+
sourceIndexByInput.push(uniqueIndex);
|
|
922
|
+
}
|
|
923
|
+
return { uniqueItems, sourceIndexByInput };
|
|
924
|
+
}
|
|
838
925
|
function finalizeCoreBatch(total, startedAt, round, normalize) {
|
|
839
926
|
const results = new Array(total);
|
|
840
927
|
for (const item of round) {
|
package/dist/index.mjs
CHANGED
package/dist/mcp-config.js
CHANGED
|
@@ -542,9 +542,34 @@ var Signaliz = class {
|
|
|
542
542
|
async createSignalCopyBatch(requests, options) {
|
|
543
543
|
validateBatchSize(requests);
|
|
544
544
|
const startedAt = Date.now();
|
|
545
|
+
const deduplicated = dedupeExactBatchItems(requests, (params) => JSON.stringify({
|
|
546
|
+
request: signalToCopyRequestBody(params),
|
|
547
|
+
wait_for_result: params.waitForResult,
|
|
548
|
+
max_wait_ms: params.maxWaitMs,
|
|
549
|
+
poll_interval_ms: params.pollIntervalMs
|
|
550
|
+
}));
|
|
551
|
+
const uniqueRequests = deduplicated.uniqueItems;
|
|
552
|
+
const canUseRecoverableAvailableDataJob = uniqueRequests.length > 25 && uniqueRequests.every(
|
|
553
|
+
(params) => params.waitForResult !== false && params.skipCache !== true && params.enableDeepSearch !== true && params.maxWaitMs === void 0 && params.pollIntervalMs === void 0
|
|
554
|
+
);
|
|
555
|
+
const uniqueResults = canUseRecoverableAvailableDataJob ? await this.runAvailableSignalCopyBatchJob(uniqueRequests) : await this.runSignalCopyBatchChunks(uniqueRequests, options);
|
|
556
|
+
const results = requests.map((_, index) => ({
|
|
557
|
+
...uniqueResults[deduplicated.sourceIndexByInput[index]],
|
|
558
|
+
index
|
|
559
|
+
}));
|
|
560
|
+
const succeeded = results.filter((item) => item.success).length;
|
|
561
|
+
return {
|
|
562
|
+
total: requests.length,
|
|
563
|
+
succeeded,
|
|
564
|
+
failed: requests.length - succeeded,
|
|
565
|
+
durationMs: Date.now() - startedAt,
|
|
566
|
+
results
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
async runSignalCopyBatchChunks(uniqueRequests, options) {
|
|
545
570
|
const chunks = [];
|
|
546
|
-
for (let offset = 0; offset <
|
|
547
|
-
chunks.push({ offset, requests:
|
|
571
|
+
for (let offset = 0; offset < uniqueRequests.length; offset += 25) {
|
|
572
|
+
chunks.push({ offset, requests: uniqueRequests.slice(offset, offset + 25) });
|
|
548
573
|
}
|
|
549
574
|
const { serverConcurrency, chunkConcurrency } = batchConcurrencyPlan(options);
|
|
550
575
|
const chunkBatch = await runBatch(
|
|
@@ -552,12 +577,12 @@ var Signaliz = class {
|
|
|
552
577
|
(chunk) => this.runSignalCopyBatchChunk(chunk.requests, serverConcurrency),
|
|
553
578
|
{ concurrency: chunkConcurrency }
|
|
554
579
|
);
|
|
555
|
-
const
|
|
580
|
+
const uniqueResults = new Array(uniqueRequests.length);
|
|
556
581
|
for (const chunkResult of chunkBatch.results) {
|
|
557
582
|
const chunk = chunks[chunkResult.index];
|
|
558
583
|
if (!chunkResult.success || !chunkResult.data) {
|
|
559
584
|
for (let index = 0; index < chunk.requests.length; index += 1) {
|
|
560
|
-
|
|
585
|
+
uniqueResults[chunk.offset + index] = {
|
|
561
586
|
index: chunk.offset + index,
|
|
562
587
|
success: false,
|
|
563
588
|
error: chunkResult.error || "Signal to Copy batch request failed"
|
|
@@ -566,17 +591,58 @@ var Signaliz = class {
|
|
|
566
591
|
continue;
|
|
567
592
|
}
|
|
568
593
|
for (const item of chunkResult.data) {
|
|
569
|
-
|
|
594
|
+
uniqueResults[chunk.offset + item.index] = { ...item, index: chunk.offset + item.index };
|
|
570
595
|
}
|
|
571
596
|
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
};
|
|
597
|
+
return uniqueResults;
|
|
598
|
+
}
|
|
599
|
+
async runAvailableSignalCopyBatchJob(requests) {
|
|
600
|
+
const startedAt = Date.now();
|
|
601
|
+
const maxWaitMs = 20 * 6e4;
|
|
602
|
+
let status = await this.client.post("api/v1/signal-to-copy", {
|
|
603
|
+
requests: requests.map(signalToCopyRequestBody)
|
|
604
|
+
});
|
|
605
|
+
const jobId = String(status.job_id || "").trim();
|
|
606
|
+
if (!jobId) throw new Error("Signal to Copy batch did not return a recoverable job_id");
|
|
607
|
+
while (!["completed", "partial", "failed"].includes(String(status.status || "").toLowerCase())) {
|
|
608
|
+
if (Date.now() - startedAt >= maxWaitMs) {
|
|
609
|
+
throw new Error(`Signal to Copy batch ${jobId} did not complete within ${maxWaitMs}ms`);
|
|
610
|
+
}
|
|
611
|
+
const retryAfterMs = Number(status.next_poll_after_seconds || 2) * 1e3;
|
|
612
|
+
await sleep2(Math.min(Math.max(250, retryAfterMs), maxWaitMs - (Date.now() - startedAt)));
|
|
613
|
+
status = await this.client.post("api/v1/signal-to-copy", {
|
|
614
|
+
job_id: jobId,
|
|
615
|
+
page: 1,
|
|
616
|
+
page_size: 500
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
const totalPages = Math.max(1, Number(status.total_pages || 1));
|
|
620
|
+
const pages = [Array.isArray(status.results) ? status.results : []];
|
|
621
|
+
if (totalPages > 1) {
|
|
622
|
+
const remainingPages = await Promise.all(Array.from(
|
|
623
|
+
{ length: totalPages - 1 },
|
|
624
|
+
(_, index) => this.client.post("api/v1/signal-to-copy", {
|
|
625
|
+
job_id: jobId,
|
|
626
|
+
page: index + 2,
|
|
627
|
+
page_size: 500
|
|
628
|
+
})
|
|
629
|
+
));
|
|
630
|
+
for (const page of remainingPages) pages.push(Array.isArray(page.results) ? page.results : []);
|
|
631
|
+
}
|
|
632
|
+
const rows = pages.flat();
|
|
633
|
+
if (rows.length !== requests.length) {
|
|
634
|
+
throw new Error(`Signal to Copy batch returned ${rows.length} results for ${requests.length} requests`);
|
|
635
|
+
}
|
|
636
|
+
const results = new Array(requests.length);
|
|
637
|
+
for (const row of rows) {
|
|
638
|
+
const index = Number(row.index);
|
|
639
|
+
if (!Number.isInteger(index) || index < 0 || index >= requests.length) {
|
|
640
|
+
throw new Error("Signal to Copy batch returned an invalid result index");
|
|
641
|
+
}
|
|
642
|
+
results[index] = row.success === false ? { index, success: false, error: row.error || row.message || "Signal to Copy failed" } : { index, success: true, data: normalizeSignalToCopyResult(row) };
|
|
643
|
+
}
|
|
644
|
+
if (results.some((item) => !item)) throw new Error("Signal to Copy batch returned incomplete indexed results");
|
|
645
|
+
return results;
|
|
580
646
|
}
|
|
581
647
|
async runSignalCopyBatchChunk(requests, concurrency) {
|
|
582
648
|
const startedAt = Date.now();
|
|
@@ -642,9 +708,11 @@ var Signaliz = class {
|
|
|
642
708
|
}
|
|
643
709
|
async runCoreBatchRound(path2, tasks, options) {
|
|
644
710
|
const { serverConcurrency, chunkConcurrency } = batchConcurrencyPlan(options);
|
|
711
|
+
const deduplicated = dedupeExactBatchItems(tasks, (task) => JSON.stringify(task.request));
|
|
712
|
+
const uniqueTasks = deduplicated.uniqueItems;
|
|
645
713
|
const chunks = [];
|
|
646
|
-
for (let offset = 0; offset <
|
|
647
|
-
chunks.push({ offset, tasks:
|
|
714
|
+
for (let offset = 0; offset < uniqueTasks.length; offset += 25) {
|
|
715
|
+
chunks.push({ offset, tasks: uniqueTasks.slice(offset, offset + 25) });
|
|
648
716
|
}
|
|
649
717
|
const chunkBatch = await runBatch(chunks, async (chunk) => {
|
|
650
718
|
const data = await this.client.post(path2, {
|
|
@@ -659,12 +727,12 @@ var Signaliz = class {
|
|
|
659
727
|
}
|
|
660
728
|
return data.results;
|
|
661
729
|
}, { concurrency: chunkConcurrency });
|
|
662
|
-
const
|
|
730
|
+
const uniqueResults = new Array(uniqueTasks.length);
|
|
663
731
|
for (const chunkResult of chunkBatch.results) {
|
|
664
732
|
const chunk = chunks[chunkResult.index];
|
|
665
733
|
if (!chunkResult.success || !chunkResult.data) {
|
|
666
734
|
for (let index = 0; index < chunk.tasks.length; index += 1) {
|
|
667
|
-
|
|
735
|
+
uniqueResults[chunk.offset + index] = {
|
|
668
736
|
index: chunk.tasks[index].index,
|
|
669
737
|
success: false,
|
|
670
738
|
error: chunkResult.error || `${path2} batch request failed`
|
|
@@ -674,7 +742,7 @@ var Signaliz = class {
|
|
|
674
742
|
}
|
|
675
743
|
for (let index = 0; index < chunkResult.data.length; index += 1) {
|
|
676
744
|
const raw = chunkResult.data[index];
|
|
677
|
-
|
|
745
|
+
uniqueResults[chunk.offset + index] = {
|
|
678
746
|
index: chunk.tasks[index].index,
|
|
679
747
|
success: raw.success !== false,
|
|
680
748
|
raw,
|
|
@@ -682,7 +750,10 @@ var Signaliz = class {
|
|
|
682
750
|
};
|
|
683
751
|
}
|
|
684
752
|
}
|
|
685
|
-
return
|
|
753
|
+
return tasks.map((task, index) => ({
|
|
754
|
+
...uniqueResults[deduplicated.sourceIndexByInput[index]],
|
|
755
|
+
index: task.index
|
|
756
|
+
}));
|
|
686
757
|
}
|
|
687
758
|
async listTools() {
|
|
688
759
|
const result = await this.client.mcp("tools/list");
|
|
@@ -839,6 +910,22 @@ function batchConcurrencyPlan(options) {
|
|
|
839
910
|
chunkConcurrency: Math.max(1, Math.floor(concurrency / serverConcurrency))
|
|
840
911
|
};
|
|
841
912
|
}
|
|
913
|
+
function dedupeExactBatchItems(items, keyForItem) {
|
|
914
|
+
const uniqueItems = [];
|
|
915
|
+
const sourceIndexByInput = [];
|
|
916
|
+
const uniqueIndexByKey = /* @__PURE__ */ new Map();
|
|
917
|
+
for (const item of items) {
|
|
918
|
+
const key = keyForItem(item);
|
|
919
|
+
let uniqueIndex = uniqueIndexByKey.get(key);
|
|
920
|
+
if (uniqueIndex === void 0) {
|
|
921
|
+
uniqueIndex = uniqueItems.length;
|
|
922
|
+
uniqueIndexByKey.set(key, uniqueIndex);
|
|
923
|
+
uniqueItems.push(item);
|
|
924
|
+
}
|
|
925
|
+
sourceIndexByInput.push(uniqueIndex);
|
|
926
|
+
}
|
|
927
|
+
return { uniqueItems, sourceIndexByInput };
|
|
928
|
+
}
|
|
842
929
|
function finalizeCoreBatch(total, startedAt, round, normalize) {
|
|
843
930
|
const results = new Array(total);
|
|
844
931
|
for (const item of round) {
|
package/dist/mcp-config.mjs
CHANGED
package/package.json
CHANGED