@signaliz/sdk 1.0.39 → 1.0.42
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 +11 -0
- package/dist/{chunk-UVW5N4LW.mjs → chunk-B4OMGBD5.mjs} +48 -13
- package/dist/index.d.mts +19 -4
- package/dist/index.d.ts +19 -4
- package/dist/index.js +48 -13
- package/dist/index.mjs +1 -1
- package/dist/mcp-config.js +48 -13
- package/dist/mcp-config.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -69,6 +69,17 @@ const copy = await signaliz.signalToCopy({
|
|
|
69
69
|
skipCache: false,
|
|
70
70
|
enableDeepSearch: false,
|
|
71
71
|
});
|
|
72
|
+
|
|
73
|
+
// Persist a queued copy ID and resume with that ID alone. Signaliz restores
|
|
74
|
+
// the recipient, title, offer, prompt, and underlying research run.
|
|
75
|
+
const queuedCopy = await signaliz.signalToCopy({
|
|
76
|
+
companyDomain: 'example.com',
|
|
77
|
+
personName: 'Jane Doe',
|
|
78
|
+
title: 'VP Sales',
|
|
79
|
+
campaignOffer: 'pipeline intelligence',
|
|
80
|
+
waitForResult: false,
|
|
81
|
+
});
|
|
82
|
+
const resumedCopy = await signaliz.signalToCopy({ signalRunId: queuedCopy.runId });
|
|
72
83
|
```
|
|
73
84
|
|
|
74
85
|
All four products support bounded batch execution over the same REST endpoints.
|
|
@@ -32,7 +32,7 @@ function parseError(status, body) {
|
|
|
32
32
|
}
|
|
33
33
|
function mapErrorType(code, status) {
|
|
34
34
|
if (code === "RATE_LIMITED" || status === 429) return "rate_limited";
|
|
35
|
-
if (code === "VALIDATION_ERROR" || status === 400) return "validation";
|
|
35
|
+
if (code === "VALIDATION_ERROR" || code === "SIGNAL_RUN_COMPANY_MISMATCH" || status === 400) return "validation";
|
|
36
36
|
if (code === "NOT_FOUND" || status === 404) return "not_found";
|
|
37
37
|
if (code === "NO_SUPPORTED_SIGNAL") return "not_found";
|
|
38
38
|
if (code === "AUTH_EXPIRED" || status === 401) return "auth_expired";
|
|
@@ -60,6 +60,7 @@ var HttpClient = class {
|
|
|
60
60
|
}
|
|
61
61
|
async request(functionName, body, method = "POST") {
|
|
62
62
|
let lastError;
|
|
63
|
+
const idempotencyKey = method === "POST" ? requestIdempotencyKey(body) : void 0;
|
|
63
64
|
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
64
65
|
let timer;
|
|
65
66
|
try {
|
|
@@ -77,7 +78,8 @@ var HttpClient = class {
|
|
|
77
78
|
method,
|
|
78
79
|
headers: {
|
|
79
80
|
"Content-Type": "application/json",
|
|
80
|
-
Authorization: `Bearer ${token}
|
|
81
|
+
Authorization: `Bearer ${token}`,
|
|
82
|
+
...idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {}
|
|
81
83
|
},
|
|
82
84
|
signal: controller.signal
|
|
83
85
|
};
|
|
@@ -242,6 +244,11 @@ var HttpClient = class {
|
|
|
242
244
|
return this.accessTokenPromise;
|
|
243
245
|
}
|
|
244
246
|
};
|
|
247
|
+
function requestIdempotencyKey(body) {
|
|
248
|
+
const requested = typeof body.idempotency_key === "string" ? body.idempotency_key.trim() : "";
|
|
249
|
+
const nonce = globalThis.crypto?.randomUUID?.() || `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
250
|
+
return requested || `sdk_${nonce}`;
|
|
251
|
+
}
|
|
245
252
|
function sleep(ms) {
|
|
246
253
|
return new Promise((r) => setTimeout(r, ms));
|
|
247
254
|
}
|
|
@@ -342,7 +349,7 @@ function mapMcpErrorType(error) {
|
|
|
342
349
|
function mapErrorTypeFromCode(code) {
|
|
343
350
|
if (!code) return "unknown";
|
|
344
351
|
if (code === "RATE_LIMITED") return "rate_limited";
|
|
345
|
-
if (code === "INVALID_ARGUMENT" || code === "VALIDATION_ERROR" || code === "VALIDATION_001" || code === "APPROVAL_REQUIRED" || code === "WEBHOOK_APPROVAL_REQUIRED" || code === "TARGET_LIMIT_EXCEEDED") return "validation";
|
|
352
|
+
if (code === "INVALID_ARGUMENT" || code === "VALIDATION_ERROR" || code === "VALIDATION_001" || code === "SIGNAL_RUN_COMPANY_MISMATCH" || code === "APPROVAL_REQUIRED" || code === "WEBHOOK_APPROVAL_REQUIRED" || code === "TARGET_LIMIT_EXCEEDED") return "validation";
|
|
346
353
|
if (code === "AUTH_REQUIRED" || code === "AUTH_001") return "auth_expired";
|
|
347
354
|
if (code === "QUOTA_EXCEEDED") return "insufficient_credits";
|
|
348
355
|
if (code === "BUILD_NOT_READY" || code === "ARTIFACT_NOT_READY") return "not_found";
|
|
@@ -521,17 +528,16 @@ var Signaliz = class {
|
|
|
521
528
|
};
|
|
522
529
|
}
|
|
523
530
|
async signalToCopy(params) {
|
|
531
|
+
validateSignalToCopyParams(params);
|
|
524
532
|
const request = signalToCopyRequestBody(params);
|
|
525
533
|
let data = await this.client.post("api/v1/signal-to-copy", request);
|
|
526
|
-
if (params.waitForResult !== false && data.run_id && isPendingSignalResponse(data)) {
|
|
534
|
+
if (params.waitForResult !== false && (data.signal_run_id || data.run_id) && isPendingSignalResponse(data)) {
|
|
527
535
|
const maxWaitMs = Math.max(1e3, params.maxWaitMs ?? 20 * 6e4);
|
|
528
536
|
const startedAt = Date.now();
|
|
529
537
|
while (Date.now() - startedAt < maxWaitMs) {
|
|
530
538
|
if (!await waitForNextSignalPoll(data, params.pollIntervalMs, startedAt, maxWaitMs)) break;
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
signal_run_id: data.run_id
|
|
534
|
-
});
|
|
539
|
+
const signalRunId = data.signal_run_id || data.run_id;
|
|
540
|
+
data = await this.client.post("api/v1/signal-to-copy", data.resume_context_persisted === true ? { signal_run_id: signalRunId } : { ...request, signal_run_id: signalRunId });
|
|
535
541
|
if (!isPendingSignalResponse(data)) break;
|
|
536
542
|
}
|
|
537
543
|
if (isPendingSignalResponse(data)) {
|
|
@@ -542,6 +548,7 @@ var Signaliz = class {
|
|
|
542
548
|
}
|
|
543
549
|
async createSignalCopyBatch(requests, options) {
|
|
544
550
|
validateBatchSize(requests);
|
|
551
|
+
requests.forEach(validateSignalToCopyParams);
|
|
545
552
|
const startedAt = Date.now();
|
|
546
553
|
const deduplicated = dedupeExactBatchItems(requests, (params) => JSON.stringify({
|
|
547
554
|
request: signalToCopyRequestBody(params),
|
|
@@ -551,7 +558,7 @@ var Signaliz = class {
|
|
|
551
558
|
}));
|
|
552
559
|
const uniqueRequests = deduplicated.uniqueItems;
|
|
553
560
|
const canUseRecoverableAvailableDataJob = uniqueRequests.length > 25 && uniqueRequests.every(
|
|
554
|
-
(params) => params.waitForResult !== false && params.skipCache !== true && params.enableDeepSearch !== true && params.maxWaitMs === void 0 && params.pollIntervalMs === void 0
|
|
561
|
+
(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
|
|
555
562
|
);
|
|
556
563
|
const uniqueResults = canUseRecoverableAvailableDataJob ? await this.runAvailableSignalCopyBatchJob(uniqueRequests, options) : await this.runSignalCopyBatchChunks(uniqueRequests, options);
|
|
557
564
|
const results = requests.map((_, index) => ({
|
|
@@ -738,7 +745,7 @@ var Signaliz = class {
|
|
|
738
745
|
);
|
|
739
746
|
nextPending.push({
|
|
740
747
|
...task,
|
|
741
|
-
request: { ...task.request, signal_run_id: signalRunId }
|
|
748
|
+
request: item.resume_context_persisted === true ? { signal_run_id: signalRunId } : { ...task.request, signal_run_id: signalRunId }
|
|
742
749
|
});
|
|
743
750
|
}
|
|
744
751
|
pending = nextPending;
|
|
@@ -944,15 +951,16 @@ function companySignalRecoverableBatchOptions(companies, tasks) {
|
|
|
944
951
|
return { label: "Company Signals", pageSize: 25, maxWaitMs };
|
|
945
952
|
}
|
|
946
953
|
function normalizeCompanySignalResult(params, data) {
|
|
954
|
+
const rawSignals = data.signals ?? data.signal_feed ?? [];
|
|
947
955
|
return {
|
|
948
956
|
success: data.success ?? true,
|
|
949
957
|
status: data.status,
|
|
950
|
-
signalRunId: data.signal_run_id ?? data.run_id,
|
|
958
|
+
signalRunId: data.signal_run_id ?? data.run_id ?? params.signalRunId,
|
|
951
959
|
company: {
|
|
952
960
|
name: data.company?.name ?? params.companyName ?? null,
|
|
953
961
|
domain: data.company?.domain ?? params.companyDomain ?? null
|
|
954
962
|
},
|
|
955
|
-
signals:
|
|
963
|
+
signals: rawSignals.map((signal) => {
|
|
956
964
|
const metadata = signal.metadata && typeof signal.metadata === "object" && !Array.isArray(signal.metadata) ? signal.metadata : void 0;
|
|
957
965
|
return {
|
|
958
966
|
id: signal.id,
|
|
@@ -976,9 +984,20 @@ function normalizeCompanySignalResult(params, data) {
|
|
|
976
984
|
metadata
|
|
977
985
|
};
|
|
978
986
|
}),
|
|
979
|
-
signalCount: data.signal_count ?? data.total_signals ??
|
|
987
|
+
signalCount: data.signal_count ?? data.total_signals ?? rawSignals.length,
|
|
988
|
+
signalSummary: data.signal_summary ?? null,
|
|
989
|
+
signalSummarySource: data.signal_summary_source,
|
|
980
990
|
intelligence: data.intelligence ?? null,
|
|
991
|
+
copyFuel: data.copy_fuel ?? null,
|
|
992
|
+
evidenceValidation: data.evidence_validation,
|
|
993
|
+
evidenceSources: data.evidence_sources,
|
|
981
994
|
credits: data.credits,
|
|
995
|
+
creditsUsed: data.credits_used,
|
|
996
|
+
costUsd: data.cost_usd,
|
|
997
|
+
billingMetadata: data.billing_metadata,
|
|
998
|
+
resultReturnedFrom: data.result_returned_from,
|
|
999
|
+
cacheHit: data.cache_hit,
|
|
1000
|
+
liveProviderCalled: data.live_provider_called,
|
|
982
1001
|
metadata: data.metadata,
|
|
983
1002
|
raw: data
|
|
984
1003
|
};
|
|
@@ -1076,11 +1095,24 @@ function signalToCopyRequestBody(params) {
|
|
|
1076
1095
|
enable_deep_search: params.enableDeepSearch
|
|
1077
1096
|
});
|
|
1078
1097
|
}
|
|
1098
|
+
function validateSignalToCopyParams(params) {
|
|
1099
|
+
if (typeof params.signalRunId === "string" && params.signalRunId.trim()) return;
|
|
1100
|
+
const missing = [
|
|
1101
|
+
["companyDomain", params.companyDomain],
|
|
1102
|
+
["personName", params.personName],
|
|
1103
|
+
["title", params.title],
|
|
1104
|
+
["campaignOffer", params.campaignOffer]
|
|
1105
|
+
].filter(([, value]) => typeof value !== "string" || !value.trim()).map(([field]) => field);
|
|
1106
|
+
if (missing.length > 0) {
|
|
1107
|
+
throw new TypeError(`Signal to Copy requires signalRunId or: ${missing.join(", ")}`);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1079
1110
|
function normalizeSignalToCopyResult(data) {
|
|
1080
1111
|
return {
|
|
1081
1112
|
success: data.success ?? true,
|
|
1082
1113
|
status: data.status,
|
|
1083
1114
|
runId: data.signal_run_id ?? data.run_id,
|
|
1115
|
+
resumeContextPersisted: data.resume_context_persisted,
|
|
1084
1116
|
strongestSignal: data.strongest_signal ?? "",
|
|
1085
1117
|
whyNow: data.why_now ?? "",
|
|
1086
1118
|
subjectLine: data.subject_line ?? "",
|
|
@@ -1088,6 +1120,9 @@ function normalizeSignalToCopyResult(data) {
|
|
|
1088
1120
|
confidence: data.confidence ?? 0,
|
|
1089
1121
|
evidenceUrl: data.evidence_url ?? "",
|
|
1090
1122
|
researchPrompt: data.research_prompt,
|
|
1123
|
+
empty: data.empty,
|
|
1124
|
+
emptyReason: data.empty_reason,
|
|
1125
|
+
researchMetadata: data.research_metadata,
|
|
1091
1126
|
variations: (data.variations ?? []).map((variation) => ({
|
|
1092
1127
|
style: variation.style,
|
|
1093
1128
|
subjectLine: variation.subject_line ?? "",
|
package/dist/index.d.mts
CHANGED
|
@@ -150,16 +150,27 @@ interface CompanySignalEnrichmentResult {
|
|
|
150
150
|
};
|
|
151
151
|
signals: CompanySignal[];
|
|
152
152
|
signalCount: number;
|
|
153
|
+
signalSummary: string | null;
|
|
154
|
+
signalSummarySource?: string;
|
|
153
155
|
intelligence?: Record<string, unknown> | null;
|
|
156
|
+
copyFuel?: Record<string, unknown> | null;
|
|
157
|
+
evidenceValidation?: Record<string, unknown>;
|
|
158
|
+
evidenceSources?: Record<string, unknown>[];
|
|
154
159
|
credits?: Record<string, unknown>;
|
|
160
|
+
creditsUsed?: number;
|
|
161
|
+
costUsd?: number;
|
|
162
|
+
billingMetadata?: Record<string, unknown>;
|
|
163
|
+
resultReturnedFrom?: string;
|
|
164
|
+
cacheHit?: boolean;
|
|
165
|
+
liveProviderCalled?: boolean;
|
|
155
166
|
metadata?: Record<string, unknown>;
|
|
156
167
|
raw: Record<string, unknown>;
|
|
157
168
|
}
|
|
158
169
|
interface SignalToCopyParams {
|
|
159
|
-
companyDomain
|
|
160
|
-
personName
|
|
161
|
-
title
|
|
162
|
-
campaignOffer
|
|
170
|
+
companyDomain?: string;
|
|
171
|
+
personName?: string;
|
|
172
|
+
title?: string;
|
|
173
|
+
campaignOffer?: string;
|
|
163
174
|
researchPrompt?: string;
|
|
164
175
|
signalRunId?: string;
|
|
165
176
|
/** Bypass cached company signals and start fresh research. */
|
|
@@ -182,6 +193,7 @@ interface SignalToCopyResult {
|
|
|
182
193
|
success: boolean;
|
|
183
194
|
status?: string;
|
|
184
195
|
runId?: string;
|
|
196
|
+
resumeContextPersisted?: boolean;
|
|
185
197
|
strongestSignal: string;
|
|
186
198
|
whyNow: string;
|
|
187
199
|
subjectLine: string;
|
|
@@ -189,6 +201,9 @@ interface SignalToCopyResult {
|
|
|
189
201
|
confidence: number;
|
|
190
202
|
evidenceUrl: string;
|
|
191
203
|
researchPrompt?: string;
|
|
204
|
+
empty?: boolean;
|
|
205
|
+
emptyReason?: string;
|
|
206
|
+
researchMetadata?: Record<string, unknown>;
|
|
192
207
|
variations: SignalToCopyVariation[];
|
|
193
208
|
raw: Record<string, unknown>;
|
|
194
209
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -150,16 +150,27 @@ interface CompanySignalEnrichmentResult {
|
|
|
150
150
|
};
|
|
151
151
|
signals: CompanySignal[];
|
|
152
152
|
signalCount: number;
|
|
153
|
+
signalSummary: string | null;
|
|
154
|
+
signalSummarySource?: string;
|
|
153
155
|
intelligence?: Record<string, unknown> | null;
|
|
156
|
+
copyFuel?: Record<string, unknown> | null;
|
|
157
|
+
evidenceValidation?: Record<string, unknown>;
|
|
158
|
+
evidenceSources?: Record<string, unknown>[];
|
|
154
159
|
credits?: Record<string, unknown>;
|
|
160
|
+
creditsUsed?: number;
|
|
161
|
+
costUsd?: number;
|
|
162
|
+
billingMetadata?: Record<string, unknown>;
|
|
163
|
+
resultReturnedFrom?: string;
|
|
164
|
+
cacheHit?: boolean;
|
|
165
|
+
liveProviderCalled?: boolean;
|
|
155
166
|
metadata?: Record<string, unknown>;
|
|
156
167
|
raw: Record<string, unknown>;
|
|
157
168
|
}
|
|
158
169
|
interface SignalToCopyParams {
|
|
159
|
-
companyDomain
|
|
160
|
-
personName
|
|
161
|
-
title
|
|
162
|
-
campaignOffer
|
|
170
|
+
companyDomain?: string;
|
|
171
|
+
personName?: string;
|
|
172
|
+
title?: string;
|
|
173
|
+
campaignOffer?: string;
|
|
163
174
|
researchPrompt?: string;
|
|
164
175
|
signalRunId?: string;
|
|
165
176
|
/** Bypass cached company signals and start fresh research. */
|
|
@@ -182,6 +193,7 @@ interface SignalToCopyResult {
|
|
|
182
193
|
success: boolean;
|
|
183
194
|
status?: string;
|
|
184
195
|
runId?: string;
|
|
196
|
+
resumeContextPersisted?: boolean;
|
|
185
197
|
strongestSignal: string;
|
|
186
198
|
whyNow: string;
|
|
187
199
|
subjectLine: string;
|
|
@@ -189,6 +201,9 @@ interface SignalToCopyResult {
|
|
|
189
201
|
confidence: number;
|
|
190
202
|
evidenceUrl: string;
|
|
191
203
|
researchPrompt?: string;
|
|
204
|
+
empty?: boolean;
|
|
205
|
+
emptyReason?: string;
|
|
206
|
+
researchMetadata?: Record<string, unknown>;
|
|
192
207
|
variations: SignalToCopyVariation[];
|
|
193
208
|
raw: Record<string, unknown>;
|
|
194
209
|
}
|
package/dist/index.js
CHANGED
|
@@ -59,7 +59,7 @@ function parseError(status, body) {
|
|
|
59
59
|
}
|
|
60
60
|
function mapErrorType(code, status) {
|
|
61
61
|
if (code === "RATE_LIMITED" || status === 429) return "rate_limited";
|
|
62
|
-
if (code === "VALIDATION_ERROR" || status === 400) return "validation";
|
|
62
|
+
if (code === "VALIDATION_ERROR" || code === "SIGNAL_RUN_COMPANY_MISMATCH" || status === 400) return "validation";
|
|
63
63
|
if (code === "NOT_FOUND" || status === 404) return "not_found";
|
|
64
64
|
if (code === "NO_SUPPORTED_SIGNAL") return "not_found";
|
|
65
65
|
if (code === "AUTH_EXPIRED" || status === 401) return "auth_expired";
|
|
@@ -87,6 +87,7 @@ var HttpClient = class {
|
|
|
87
87
|
}
|
|
88
88
|
async request(functionName, body, method = "POST") {
|
|
89
89
|
let lastError;
|
|
90
|
+
const idempotencyKey = method === "POST" ? requestIdempotencyKey(body) : void 0;
|
|
90
91
|
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
91
92
|
let timer;
|
|
92
93
|
try {
|
|
@@ -104,7 +105,8 @@ var HttpClient = class {
|
|
|
104
105
|
method,
|
|
105
106
|
headers: {
|
|
106
107
|
"Content-Type": "application/json",
|
|
107
|
-
Authorization: `Bearer ${token}
|
|
108
|
+
Authorization: `Bearer ${token}`,
|
|
109
|
+
...idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {}
|
|
108
110
|
},
|
|
109
111
|
signal: controller.signal
|
|
110
112
|
};
|
|
@@ -269,6 +271,11 @@ var HttpClient = class {
|
|
|
269
271
|
return this.accessTokenPromise;
|
|
270
272
|
}
|
|
271
273
|
};
|
|
274
|
+
function requestIdempotencyKey(body) {
|
|
275
|
+
const requested = typeof body.idempotency_key === "string" ? body.idempotency_key.trim() : "";
|
|
276
|
+
const nonce = globalThis.crypto?.randomUUID?.() || `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
277
|
+
return requested || `sdk_${nonce}`;
|
|
278
|
+
}
|
|
272
279
|
function sleep(ms) {
|
|
273
280
|
return new Promise((r) => setTimeout(r, ms));
|
|
274
281
|
}
|
|
@@ -369,7 +376,7 @@ function mapMcpErrorType(error) {
|
|
|
369
376
|
function mapErrorTypeFromCode(code) {
|
|
370
377
|
if (!code) return "unknown";
|
|
371
378
|
if (code === "RATE_LIMITED") return "rate_limited";
|
|
372
|
-
if (code === "INVALID_ARGUMENT" || code === "VALIDATION_ERROR" || code === "VALIDATION_001" || code === "APPROVAL_REQUIRED" || code === "WEBHOOK_APPROVAL_REQUIRED" || code === "TARGET_LIMIT_EXCEEDED") return "validation";
|
|
379
|
+
if (code === "INVALID_ARGUMENT" || code === "VALIDATION_ERROR" || code === "VALIDATION_001" || code === "SIGNAL_RUN_COMPANY_MISMATCH" || code === "APPROVAL_REQUIRED" || code === "WEBHOOK_APPROVAL_REQUIRED" || code === "TARGET_LIMIT_EXCEEDED") return "validation";
|
|
373
380
|
if (code === "AUTH_REQUIRED" || code === "AUTH_001") return "auth_expired";
|
|
374
381
|
if (code === "QUOTA_EXCEEDED") return "insufficient_credits";
|
|
375
382
|
if (code === "BUILD_NOT_READY" || code === "ARTIFACT_NOT_READY") return "not_found";
|
|
@@ -548,17 +555,16 @@ var Signaliz = class {
|
|
|
548
555
|
};
|
|
549
556
|
}
|
|
550
557
|
async signalToCopy(params) {
|
|
558
|
+
validateSignalToCopyParams(params);
|
|
551
559
|
const request = signalToCopyRequestBody(params);
|
|
552
560
|
let data = await this.client.post("api/v1/signal-to-copy", request);
|
|
553
|
-
if (params.waitForResult !== false && data.run_id && isPendingSignalResponse(data)) {
|
|
561
|
+
if (params.waitForResult !== false && (data.signal_run_id || data.run_id) && isPendingSignalResponse(data)) {
|
|
554
562
|
const maxWaitMs = Math.max(1e3, params.maxWaitMs ?? 20 * 6e4);
|
|
555
563
|
const startedAt = Date.now();
|
|
556
564
|
while (Date.now() - startedAt < maxWaitMs) {
|
|
557
565
|
if (!await waitForNextSignalPoll(data, params.pollIntervalMs, startedAt, maxWaitMs)) break;
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
signal_run_id: data.run_id
|
|
561
|
-
});
|
|
566
|
+
const signalRunId = data.signal_run_id || data.run_id;
|
|
567
|
+
data = await this.client.post("api/v1/signal-to-copy", data.resume_context_persisted === true ? { signal_run_id: signalRunId } : { ...request, signal_run_id: signalRunId });
|
|
562
568
|
if (!isPendingSignalResponse(data)) break;
|
|
563
569
|
}
|
|
564
570
|
if (isPendingSignalResponse(data)) {
|
|
@@ -569,6 +575,7 @@ var Signaliz = class {
|
|
|
569
575
|
}
|
|
570
576
|
async createSignalCopyBatch(requests, options) {
|
|
571
577
|
validateBatchSize(requests);
|
|
578
|
+
requests.forEach(validateSignalToCopyParams);
|
|
572
579
|
const startedAt = Date.now();
|
|
573
580
|
const deduplicated = dedupeExactBatchItems(requests, (params) => JSON.stringify({
|
|
574
581
|
request: signalToCopyRequestBody(params),
|
|
@@ -578,7 +585,7 @@ var Signaliz = class {
|
|
|
578
585
|
}));
|
|
579
586
|
const uniqueRequests = deduplicated.uniqueItems;
|
|
580
587
|
const canUseRecoverableAvailableDataJob = uniqueRequests.length > 25 && uniqueRequests.every(
|
|
581
|
-
(params) => params.waitForResult !== false && params.skipCache !== true && params.enableDeepSearch !== true && params.maxWaitMs === void 0 && params.pollIntervalMs === void 0
|
|
588
|
+
(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
|
|
582
589
|
);
|
|
583
590
|
const uniqueResults = canUseRecoverableAvailableDataJob ? await this.runAvailableSignalCopyBatchJob(uniqueRequests, options) : await this.runSignalCopyBatchChunks(uniqueRequests, options);
|
|
584
591
|
const results = requests.map((_, index) => ({
|
|
@@ -765,7 +772,7 @@ var Signaliz = class {
|
|
|
765
772
|
);
|
|
766
773
|
nextPending.push({
|
|
767
774
|
...task,
|
|
768
|
-
request: { ...task.request, signal_run_id: signalRunId }
|
|
775
|
+
request: item.resume_context_persisted === true ? { signal_run_id: signalRunId } : { ...task.request, signal_run_id: signalRunId }
|
|
769
776
|
});
|
|
770
777
|
}
|
|
771
778
|
pending = nextPending;
|
|
@@ -971,15 +978,16 @@ function companySignalRecoverableBatchOptions(companies, tasks) {
|
|
|
971
978
|
return { label: "Company Signals", pageSize: 25, maxWaitMs };
|
|
972
979
|
}
|
|
973
980
|
function normalizeCompanySignalResult(params, data) {
|
|
981
|
+
const rawSignals = data.signals ?? data.signal_feed ?? [];
|
|
974
982
|
return {
|
|
975
983
|
success: data.success ?? true,
|
|
976
984
|
status: data.status,
|
|
977
|
-
signalRunId: data.signal_run_id ?? data.run_id,
|
|
985
|
+
signalRunId: data.signal_run_id ?? data.run_id ?? params.signalRunId,
|
|
978
986
|
company: {
|
|
979
987
|
name: data.company?.name ?? params.companyName ?? null,
|
|
980
988
|
domain: data.company?.domain ?? params.companyDomain ?? null
|
|
981
989
|
},
|
|
982
|
-
signals:
|
|
990
|
+
signals: rawSignals.map((signal) => {
|
|
983
991
|
const metadata = signal.metadata && typeof signal.metadata === "object" && !Array.isArray(signal.metadata) ? signal.metadata : void 0;
|
|
984
992
|
return {
|
|
985
993
|
id: signal.id,
|
|
@@ -1003,9 +1011,20 @@ function normalizeCompanySignalResult(params, data) {
|
|
|
1003
1011
|
metadata
|
|
1004
1012
|
};
|
|
1005
1013
|
}),
|
|
1006
|
-
signalCount: data.signal_count ?? data.total_signals ??
|
|
1014
|
+
signalCount: data.signal_count ?? data.total_signals ?? rawSignals.length,
|
|
1015
|
+
signalSummary: data.signal_summary ?? null,
|
|
1016
|
+
signalSummarySource: data.signal_summary_source,
|
|
1007
1017
|
intelligence: data.intelligence ?? null,
|
|
1018
|
+
copyFuel: data.copy_fuel ?? null,
|
|
1019
|
+
evidenceValidation: data.evidence_validation,
|
|
1020
|
+
evidenceSources: data.evidence_sources,
|
|
1008
1021
|
credits: data.credits,
|
|
1022
|
+
creditsUsed: data.credits_used,
|
|
1023
|
+
costUsd: data.cost_usd,
|
|
1024
|
+
billingMetadata: data.billing_metadata,
|
|
1025
|
+
resultReturnedFrom: data.result_returned_from,
|
|
1026
|
+
cacheHit: data.cache_hit,
|
|
1027
|
+
liveProviderCalled: data.live_provider_called,
|
|
1009
1028
|
metadata: data.metadata,
|
|
1010
1029
|
raw: data
|
|
1011
1030
|
};
|
|
@@ -1103,11 +1122,24 @@ function signalToCopyRequestBody(params) {
|
|
|
1103
1122
|
enable_deep_search: params.enableDeepSearch
|
|
1104
1123
|
});
|
|
1105
1124
|
}
|
|
1125
|
+
function validateSignalToCopyParams(params) {
|
|
1126
|
+
if (typeof params.signalRunId === "string" && params.signalRunId.trim()) return;
|
|
1127
|
+
const missing = [
|
|
1128
|
+
["companyDomain", params.companyDomain],
|
|
1129
|
+
["personName", params.personName],
|
|
1130
|
+
["title", params.title],
|
|
1131
|
+
["campaignOffer", params.campaignOffer]
|
|
1132
|
+
].filter(([, value]) => typeof value !== "string" || !value.trim()).map(([field]) => field);
|
|
1133
|
+
if (missing.length > 0) {
|
|
1134
|
+
throw new TypeError(`Signal to Copy requires signalRunId or: ${missing.join(", ")}`);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1106
1137
|
function normalizeSignalToCopyResult(data) {
|
|
1107
1138
|
return {
|
|
1108
1139
|
success: data.success ?? true,
|
|
1109
1140
|
status: data.status,
|
|
1110
1141
|
runId: data.signal_run_id ?? data.run_id,
|
|
1142
|
+
resumeContextPersisted: data.resume_context_persisted,
|
|
1111
1143
|
strongestSignal: data.strongest_signal ?? "",
|
|
1112
1144
|
whyNow: data.why_now ?? "",
|
|
1113
1145
|
subjectLine: data.subject_line ?? "",
|
|
@@ -1115,6 +1147,9 @@ function normalizeSignalToCopyResult(data) {
|
|
|
1115
1147
|
confidence: data.confidence ?? 0,
|
|
1116
1148
|
evidenceUrl: data.evidence_url ?? "",
|
|
1117
1149
|
researchPrompt: data.research_prompt,
|
|
1150
|
+
empty: data.empty,
|
|
1151
|
+
emptyReason: data.empty_reason,
|
|
1152
|
+
researchMetadata: data.research_metadata,
|
|
1118
1153
|
variations: (data.variations ?? []).map((variation) => ({
|
|
1119
1154
|
style: variation.style,
|
|
1120
1155
|
subjectLine: variation.subject_line ?? "",
|
package/dist/index.mjs
CHANGED
package/dist/mcp-config.js
CHANGED
|
@@ -63,7 +63,7 @@ function parseError(status, body) {
|
|
|
63
63
|
}
|
|
64
64
|
function mapErrorType(code, status) {
|
|
65
65
|
if (code === "RATE_LIMITED" || status === 429) return "rate_limited";
|
|
66
|
-
if (code === "VALIDATION_ERROR" || status === 400) return "validation";
|
|
66
|
+
if (code === "VALIDATION_ERROR" || code === "SIGNAL_RUN_COMPANY_MISMATCH" || status === 400) return "validation";
|
|
67
67
|
if (code === "NOT_FOUND" || status === 404) return "not_found";
|
|
68
68
|
if (code === "NO_SUPPORTED_SIGNAL") return "not_found";
|
|
69
69
|
if (code === "AUTH_EXPIRED" || status === 401) return "auth_expired";
|
|
@@ -91,6 +91,7 @@ var HttpClient = class {
|
|
|
91
91
|
}
|
|
92
92
|
async request(functionName, body, method = "POST") {
|
|
93
93
|
let lastError;
|
|
94
|
+
const idempotencyKey = method === "POST" ? requestIdempotencyKey(body) : void 0;
|
|
94
95
|
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
95
96
|
let timer;
|
|
96
97
|
try {
|
|
@@ -108,7 +109,8 @@ var HttpClient = class {
|
|
|
108
109
|
method,
|
|
109
110
|
headers: {
|
|
110
111
|
"Content-Type": "application/json",
|
|
111
|
-
Authorization: `Bearer ${token}
|
|
112
|
+
Authorization: `Bearer ${token}`,
|
|
113
|
+
...idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {}
|
|
112
114
|
},
|
|
113
115
|
signal: controller.signal
|
|
114
116
|
};
|
|
@@ -273,6 +275,11 @@ var HttpClient = class {
|
|
|
273
275
|
return this.accessTokenPromise;
|
|
274
276
|
}
|
|
275
277
|
};
|
|
278
|
+
function requestIdempotencyKey(body) {
|
|
279
|
+
const requested = typeof body.idempotency_key === "string" ? body.idempotency_key.trim() : "";
|
|
280
|
+
const nonce = globalThis.crypto?.randomUUID?.() || `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
281
|
+
return requested || `sdk_${nonce}`;
|
|
282
|
+
}
|
|
276
283
|
function sleep(ms) {
|
|
277
284
|
return new Promise((r) => setTimeout(r, ms));
|
|
278
285
|
}
|
|
@@ -373,7 +380,7 @@ function mapMcpErrorType(error) {
|
|
|
373
380
|
function mapErrorTypeFromCode(code) {
|
|
374
381
|
if (!code) return "unknown";
|
|
375
382
|
if (code === "RATE_LIMITED") return "rate_limited";
|
|
376
|
-
if (code === "INVALID_ARGUMENT" || code === "VALIDATION_ERROR" || code === "VALIDATION_001" || code === "APPROVAL_REQUIRED" || code === "WEBHOOK_APPROVAL_REQUIRED" || code === "TARGET_LIMIT_EXCEEDED") return "validation";
|
|
383
|
+
if (code === "INVALID_ARGUMENT" || code === "VALIDATION_ERROR" || code === "VALIDATION_001" || code === "SIGNAL_RUN_COMPANY_MISMATCH" || code === "APPROVAL_REQUIRED" || code === "WEBHOOK_APPROVAL_REQUIRED" || code === "TARGET_LIMIT_EXCEEDED") return "validation";
|
|
377
384
|
if (code === "AUTH_REQUIRED" || code === "AUTH_001") return "auth_expired";
|
|
378
385
|
if (code === "QUOTA_EXCEEDED") return "insufficient_credits";
|
|
379
386
|
if (code === "BUILD_NOT_READY" || code === "ARTIFACT_NOT_READY") return "not_found";
|
|
@@ -552,17 +559,16 @@ var Signaliz = class {
|
|
|
552
559
|
};
|
|
553
560
|
}
|
|
554
561
|
async signalToCopy(params) {
|
|
562
|
+
validateSignalToCopyParams(params);
|
|
555
563
|
const request = signalToCopyRequestBody(params);
|
|
556
564
|
let data = await this.client.post("api/v1/signal-to-copy", request);
|
|
557
|
-
if (params.waitForResult !== false && data.run_id && isPendingSignalResponse(data)) {
|
|
565
|
+
if (params.waitForResult !== false && (data.signal_run_id || data.run_id) && isPendingSignalResponse(data)) {
|
|
558
566
|
const maxWaitMs = Math.max(1e3, params.maxWaitMs ?? 20 * 6e4);
|
|
559
567
|
const startedAt = Date.now();
|
|
560
568
|
while (Date.now() - startedAt < maxWaitMs) {
|
|
561
569
|
if (!await waitForNextSignalPoll(data, params.pollIntervalMs, startedAt, maxWaitMs)) break;
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
signal_run_id: data.run_id
|
|
565
|
-
});
|
|
570
|
+
const signalRunId = data.signal_run_id || data.run_id;
|
|
571
|
+
data = await this.client.post("api/v1/signal-to-copy", data.resume_context_persisted === true ? { signal_run_id: signalRunId } : { ...request, signal_run_id: signalRunId });
|
|
566
572
|
if (!isPendingSignalResponse(data)) break;
|
|
567
573
|
}
|
|
568
574
|
if (isPendingSignalResponse(data)) {
|
|
@@ -573,6 +579,7 @@ var Signaliz = class {
|
|
|
573
579
|
}
|
|
574
580
|
async createSignalCopyBatch(requests, options) {
|
|
575
581
|
validateBatchSize(requests);
|
|
582
|
+
requests.forEach(validateSignalToCopyParams);
|
|
576
583
|
const startedAt = Date.now();
|
|
577
584
|
const deduplicated = dedupeExactBatchItems(requests, (params) => JSON.stringify({
|
|
578
585
|
request: signalToCopyRequestBody(params),
|
|
@@ -582,7 +589,7 @@ var Signaliz = class {
|
|
|
582
589
|
}));
|
|
583
590
|
const uniqueRequests = deduplicated.uniqueItems;
|
|
584
591
|
const canUseRecoverableAvailableDataJob = uniqueRequests.length > 25 && uniqueRequests.every(
|
|
585
|
-
(params) => params.waitForResult !== false && params.skipCache !== true && params.enableDeepSearch !== true && params.maxWaitMs === void 0 && params.pollIntervalMs === void 0
|
|
592
|
+
(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
|
|
586
593
|
);
|
|
587
594
|
const uniqueResults = canUseRecoverableAvailableDataJob ? await this.runAvailableSignalCopyBatchJob(uniqueRequests, options) : await this.runSignalCopyBatchChunks(uniqueRequests, options);
|
|
588
595
|
const results = requests.map((_, index) => ({
|
|
@@ -769,7 +776,7 @@ var Signaliz = class {
|
|
|
769
776
|
);
|
|
770
777
|
nextPending.push({
|
|
771
778
|
...task,
|
|
772
|
-
request: { ...task.request, signal_run_id: signalRunId }
|
|
779
|
+
request: item.resume_context_persisted === true ? { signal_run_id: signalRunId } : { ...task.request, signal_run_id: signalRunId }
|
|
773
780
|
});
|
|
774
781
|
}
|
|
775
782
|
pending = nextPending;
|
|
@@ -975,15 +982,16 @@ function companySignalRecoverableBatchOptions(companies, tasks) {
|
|
|
975
982
|
return { label: "Company Signals", pageSize: 25, maxWaitMs };
|
|
976
983
|
}
|
|
977
984
|
function normalizeCompanySignalResult(params, data) {
|
|
985
|
+
const rawSignals = data.signals ?? data.signal_feed ?? [];
|
|
978
986
|
return {
|
|
979
987
|
success: data.success ?? true,
|
|
980
988
|
status: data.status,
|
|
981
|
-
signalRunId: data.signal_run_id ?? data.run_id,
|
|
989
|
+
signalRunId: data.signal_run_id ?? data.run_id ?? params.signalRunId,
|
|
982
990
|
company: {
|
|
983
991
|
name: data.company?.name ?? params.companyName ?? null,
|
|
984
992
|
domain: data.company?.domain ?? params.companyDomain ?? null
|
|
985
993
|
},
|
|
986
|
-
signals:
|
|
994
|
+
signals: rawSignals.map((signal) => {
|
|
987
995
|
const metadata = signal.metadata && typeof signal.metadata === "object" && !Array.isArray(signal.metadata) ? signal.metadata : void 0;
|
|
988
996
|
return {
|
|
989
997
|
id: signal.id,
|
|
@@ -1007,9 +1015,20 @@ function normalizeCompanySignalResult(params, data) {
|
|
|
1007
1015
|
metadata
|
|
1008
1016
|
};
|
|
1009
1017
|
}),
|
|
1010
|
-
signalCount: data.signal_count ?? data.total_signals ??
|
|
1018
|
+
signalCount: data.signal_count ?? data.total_signals ?? rawSignals.length,
|
|
1019
|
+
signalSummary: data.signal_summary ?? null,
|
|
1020
|
+
signalSummarySource: data.signal_summary_source,
|
|
1011
1021
|
intelligence: data.intelligence ?? null,
|
|
1022
|
+
copyFuel: data.copy_fuel ?? null,
|
|
1023
|
+
evidenceValidation: data.evidence_validation,
|
|
1024
|
+
evidenceSources: data.evidence_sources,
|
|
1012
1025
|
credits: data.credits,
|
|
1026
|
+
creditsUsed: data.credits_used,
|
|
1027
|
+
costUsd: data.cost_usd,
|
|
1028
|
+
billingMetadata: data.billing_metadata,
|
|
1029
|
+
resultReturnedFrom: data.result_returned_from,
|
|
1030
|
+
cacheHit: data.cache_hit,
|
|
1031
|
+
liveProviderCalled: data.live_provider_called,
|
|
1013
1032
|
metadata: data.metadata,
|
|
1014
1033
|
raw: data
|
|
1015
1034
|
};
|
|
@@ -1107,11 +1126,24 @@ function signalToCopyRequestBody(params) {
|
|
|
1107
1126
|
enable_deep_search: params.enableDeepSearch
|
|
1108
1127
|
});
|
|
1109
1128
|
}
|
|
1129
|
+
function validateSignalToCopyParams(params) {
|
|
1130
|
+
if (typeof params.signalRunId === "string" && params.signalRunId.trim()) return;
|
|
1131
|
+
const missing = [
|
|
1132
|
+
["companyDomain", params.companyDomain],
|
|
1133
|
+
["personName", params.personName],
|
|
1134
|
+
["title", params.title],
|
|
1135
|
+
["campaignOffer", params.campaignOffer]
|
|
1136
|
+
].filter(([, value]) => typeof value !== "string" || !value.trim()).map(([field]) => field);
|
|
1137
|
+
if (missing.length > 0) {
|
|
1138
|
+
throw new TypeError(`Signal to Copy requires signalRunId or: ${missing.join(", ")}`);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1110
1141
|
function normalizeSignalToCopyResult(data) {
|
|
1111
1142
|
return {
|
|
1112
1143
|
success: data.success ?? true,
|
|
1113
1144
|
status: data.status,
|
|
1114
1145
|
runId: data.signal_run_id ?? data.run_id,
|
|
1146
|
+
resumeContextPersisted: data.resume_context_persisted,
|
|
1115
1147
|
strongestSignal: data.strongest_signal ?? "",
|
|
1116
1148
|
whyNow: data.why_now ?? "",
|
|
1117
1149
|
subjectLine: data.subject_line ?? "",
|
|
@@ -1119,6 +1151,9 @@ function normalizeSignalToCopyResult(data) {
|
|
|
1119
1151
|
confidence: data.confidence ?? 0,
|
|
1120
1152
|
evidenceUrl: data.evidence_url ?? "",
|
|
1121
1153
|
researchPrompt: data.research_prompt,
|
|
1154
|
+
empty: data.empty,
|
|
1155
|
+
emptyReason: data.empty_reason,
|
|
1156
|
+
researchMetadata: data.research_metadata,
|
|
1122
1157
|
variations: (data.variations ?? []).map((variation) => ({
|
|
1123
1158
|
style: variation.style,
|
|
1124
1159
|
subjectLine: variation.subject_line ?? "",
|
package/dist/mcp-config.mjs
CHANGED
package/package.json
CHANGED