@signaliz/sdk 1.0.56 → 1.0.58

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 CHANGED
@@ -87,7 +87,8 @@ const copy = await signaliz.signalToCopy({
87
87
  });
88
88
 
89
89
  // Company Signals and Signal to Copy are hard synchronous contracts: these
90
- // methods return complete data or throw a terminal error in this same call.
90
+ // methods return complete data, an explicit success:false result, or throw a
91
+ // non-2xx terminal error in this same call.
91
92
  ```
92
93
 
93
94
  The four row-oriented products support bounded batch execution over the same REST endpoints.
@@ -112,6 +113,12 @@ Failed rows preserve `errorCode`, `retryEligible`, and `retryAfterSeconds`
112
113
  when the REST API supplies them, including after automatic row retries are
113
114
  exhausted.
114
115
 
116
+ Every single-result method treats an error payload as `success: false`, even if
117
+ an upstream HTTP 200 omits or contradicts the success flag. Find Email also
118
+ withholds any email from a contradictory error response. Verify Email, Company
119
+ Signals, and Signal to Copy expose normalized `error` and `errorCode` fields;
120
+ the original response remains available in `raw`.
121
+
115
122
  For an ambiguous single request or batch submission failure, retry with the
116
123
  same `idempotencyKey` to recover the original request, durable job, or provider
117
124
  run without duplicate work or spend. The key is portable across REST API, MCP,
@@ -532,9 +532,10 @@ var Signaliz = class {
532
532
  );
533
533
  }
534
534
  const startedAt = Date.now();
535
- const deduplicated = dedupeExactBatchItems(requests, (params) => JSON.stringify({
536
- request: signalToCopyRequestBody(params)
537
- }));
535
+ const deduplicated = dedupeExactBatchItems(
536
+ requests,
537
+ (params) => coreProductBatchRequestKey("api/v1/signal-to-copy", signalToCopyRequestBody(params))
538
+ );
538
539
  const uniqueRequests = deduplicated.uniqueItems;
539
540
  const uniqueInputIndices = new Array(uniqueRequests.length);
540
541
  deduplicated.sourceIndexByInput.forEach((uniqueIndex, inputIndex) => {
@@ -691,7 +692,7 @@ var Signaliz = class {
691
692
  }
692
693
  for (let index = 0; index < requests.length; index += 1) {
693
694
  const item = data.results[index];
694
- if (item.success === false) {
695
+ if (coreProductResponseFailed(item)) {
695
696
  if (rowRateLimitAttempt < MAX_ROW_RATE_LIMIT_RETRIES && isRetryableRowRateLimit({
696
697
  index,
697
698
  success: false,
@@ -700,7 +701,11 @@ var Signaliz = class {
700
701
  rateLimited.push({ index, params: requests[index], raw: item });
701
702
  continue;
702
703
  }
703
- results[index] = batchItemFailure(index, item.error || item.message || "Signal to Copy failed", item);
704
+ results[index] = batchItemFailure(
705
+ index,
706
+ coreProductErrorMessage(item) || "Signal to Copy failed",
707
+ item
708
+ );
704
709
  continue;
705
710
  }
706
711
  try {
@@ -731,7 +736,10 @@ var Signaliz = class {
731
736
  }
732
737
  async runCoreBatchRound(path, tasks, options, rowRateLimitAttempt = 0) {
733
738
  const { serverConcurrency, chunkConcurrency } = path === "api/v1/company-signals" ? batchConcurrencyPlan(options, 25, 25) : batchConcurrencyPlan(options);
734
- const deduplicated = dedupeExactBatchItems(tasks, (task) => JSON.stringify(task.request));
739
+ const deduplicated = dedupeExactBatchItems(
740
+ tasks,
741
+ (task) => coreProductBatchRequestKey(path, task.request)
742
+ );
735
743
  const uniqueTasks = deduplicated.uniqueItems;
736
744
  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;
737
745
  if (path !== "api/v1/company-signals" && recoverableBatch && uniqueTasks.length > 25) {
@@ -798,9 +806,9 @@ var Signaliz = class {
798
806
  const raw = chunkResult.data[index];
799
807
  uniqueResults[chunk.offset + index] = {
800
808
  index: chunk.tasks[index].index,
801
- success: raw.success !== false,
809
+ success: !coreProductResponseFailed(raw),
802
810
  raw,
803
- error: raw.success === false ? raw.error || raw.message || raw.error_code || `${path} item failed` : void 0
811
+ error: coreProductResponseFailed(raw) ? coreProductErrorMessage(raw) || coreProductErrorCode(raw) || `${path} item failed` : void 0
804
812
  };
805
813
  }
806
814
  }
@@ -870,7 +878,7 @@ function batchItemFailure(index, error, raw) {
870
878
  };
871
879
  }
872
880
  function recoverableJobRowFailed(row) {
873
- return row.success === false || ["failed", "skipped"].includes(String(row._status || "").toLowerCase());
881
+ return coreProductResponseFailed(row) || ["failed", "skipped"].includes(String(row._status || "").toLowerCase());
874
882
  }
875
883
  function newBatchIdempotencyKey(label) {
876
884
  const nonce = globalThis.crypto?.randomUUID?.() || `${Date.now()}-${Math.random().toString(16).slice(2)}`;
@@ -920,7 +928,9 @@ function normalizeCoreProductDryRunResult(data) {
920
928
  };
921
929
  }
922
930
  function normalizeFindEmailResult(data) {
923
- const email = typeof data.email === "string" && data.email.trim() ? data.email.trim() : null;
931
+ const failed = coreProductResponseFailed(data);
932
+ const rawEmail = typeof data.email === "string" && data.email.trim() ? data.email.trim() : null;
933
+ const email = failed ? null : rawEmail;
924
934
  const found = Boolean(email) && data.found !== false;
925
935
  const verificationStatus = data.verification_status ?? (data.is_valid === true ? "valid" : data.status ?? "unknown");
926
936
  const rawFreshness = String(data.verification_freshness ?? "").toLowerCase();
@@ -930,7 +940,7 @@ function normalizeFindEmailResult(data) {
930
940
  const verified = !explicitlyNotSendSafe && (data.is_valid === true || data.isValid === true || data.email_verified === true || data.verified_for_sending === true || ["valid", "deliverable"].includes(String(verificationStatus).toLowerCase()));
931
941
  const verificationAgeDays = typeof data.verification_age_days === "number" && Number.isFinite(data.verification_age_days) ? data.verification_age_days : null;
932
942
  return {
933
- success: data.success !== false && found,
943
+ success: !failed && found,
934
944
  found,
935
945
  email,
936
946
  firstName: data.first_name,
@@ -957,26 +967,29 @@ function normalizeFindEmailResult(data) {
957
967
  liveProviderCalled: data.live_provider_called,
958
968
  openrouterCalled: data.openrouter_called,
959
969
  byoOpenrouterUsed: data.byo_openrouter_used,
960
- error: found ? void 0 : data.error ?? "No verified email found",
961
- errorCode: found ? void 0 : data.error_code ?? "EMAIL_NOT_FOUND",
970
+ error: found ? void 0 : coreProductErrorMessage(data) ?? "No verified email found",
971
+ errorCode: found ? void 0 : coreProductErrorCode(data) ?? "EMAIL_NOT_FOUND",
962
972
  raw: data
963
973
  };
964
974
  }
965
975
  function normalizeVerifyEmailResult(email, data) {
976
+ const failed = coreProductResponseFailed(data);
966
977
  const verificationStatus = String(data.verification_status ?? "").toLowerCase();
967
- const verified = data.email_verified === true || ["valid", "deliverable"].includes(verificationStatus);
978
+ const verified = !failed && (data.email_verified === true || ["valid", "deliverable"].includes(verificationStatus));
968
979
  return {
969
- success: data.success !== false,
980
+ success: !failed,
981
+ error: failed ? coreProductErrorMessage(data) : void 0,
982
+ errorCode: failed ? coreProductErrorCode(data) : void 0,
970
983
  email: data.email ?? email,
971
- status: String(data.status || "").toLowerCase() === "processing" ? "processing" : "completed",
984
+ status: !failed && String(data.status || "").toLowerCase() === "processing" ? "processing" : "completed",
972
985
  verificationRunId: data.verification_run_id ?? data.run_id,
973
986
  retryAfterMs: data.retry_after_ms,
974
987
  nextPollAfterSeconds: data.next_poll_after_seconds,
975
- isValid: data.is_valid ?? data.valid ?? verified,
976
- isDeliverable: data.is_deliverable ?? data.deliverable ?? verified,
988
+ isValid: failed ? false : data.is_valid ?? data.valid ?? verified,
989
+ isDeliverable: failed ? false : data.is_deliverable ?? data.deliverable ?? verified,
977
990
  isMalformed: data.is_malformed === true || data.verification_verdict === "malformed" || data.verification_status === "malformed" || data.deliverability_status === "malformed",
978
991
  isCatchAll: data.email_is_catch_all ?? data.is_catch_all ?? data.catch_all ?? data.diagnostics?.is_catch_all ?? false,
979
- verifiedForSending: data.verified_for_sending === true,
992
+ verifiedForSending: !failed && data.verified_for_sending === true,
980
993
  verificationVerdict: data.verification_verdict ?? data.verification_status ?? "unknown",
981
994
  confidenceScore: data.confidence_score ?? data.confidence ?? data.diagnostics?.confidence_score ?? (verified ? 1 : 0),
982
995
  provider: data.provider,
@@ -1021,9 +1034,12 @@ function companySignalRequestBody(params) {
1021
1034
  });
1022
1035
  }
1023
1036
  function normalizeCompanySignalResult(params, data) {
1024
- const rawSignals = data.signals ?? data.signal_feed ?? [];
1037
+ const failed = coreProductResponseFailed(data);
1038
+ const rawSignals = failed ? [] : data.signals ?? data.signal_feed ?? [];
1025
1039
  return {
1026
- success: data.success ?? true,
1040
+ success: !failed,
1041
+ error: failed ? coreProductErrorMessage(data) : void 0,
1042
+ errorCode: failed ? coreProductErrorCode(data) : void 0,
1027
1043
  status: data.status,
1028
1044
  signalRunId: data.signal_run_id ?? data.run_id ?? params.signalRunId,
1029
1045
  company: {
@@ -1247,15 +1263,88 @@ function dedupeExactBatchItems(items, keyForItem) {
1247
1263
  }
1248
1264
  return { uniqueItems, sourceIndexByInput };
1249
1265
  }
1266
+ function normalizedBatchText(value) {
1267
+ return typeof value === "string" ? value.trim().toLowerCase().replace(/\s+/g, " ") : "";
1268
+ }
1269
+ function normalizedBatchDomain(value) {
1270
+ return normalizedBatchText(value).replace(/^https?:\/\//, "").replace(/^www\./, "").split(/[/?#]/, 1)[0].replace(/\.+$/, "");
1271
+ }
1272
+ function normalizedBatchLinkedIn(value) {
1273
+ return normalizedBatchText(value).replace(/\/+$/, "");
1274
+ }
1275
+ function normalizedBatchList(value) {
1276
+ return Array.isArray(value) ? value.map(normalizedBatchText).filter(Boolean).sort() : [];
1277
+ }
1278
+ function normalizedFindEmailBatchName(request) {
1279
+ const fullName = normalizedBatchText(request.full_name);
1280
+ const componentName = [normalizedBatchText(request.first_name), normalizedBatchText(request.last_name)].filter(Boolean).join(" ");
1281
+ if (!fullName || !componentName || fullName === componentName) return fullName || componentName;
1282
+ return JSON.stringify([fullName, componentName]);
1283
+ }
1284
+ function coreProductBatchRequestKey(path, request) {
1285
+ if (path === "api/v1/find-email") {
1286
+ return JSON.stringify([
1287
+ normalizedFindEmailBatchName(request),
1288
+ normalizedBatchDomain(request.company_domain),
1289
+ normalizedBatchLinkedIn(request.linkedin_url),
1290
+ normalizedBatchText(request.company_name),
1291
+ request.skip_cache === true || request.bypass_cache === true
1292
+ ]);
1293
+ }
1294
+ if (path === "api/v1/verify-email") {
1295
+ return JSON.stringify([
1296
+ normalizedBatchText(request.email),
1297
+ request.skip_cache === true || request.bypass_cache === true,
1298
+ request.skip_catch_all_verification === true,
1299
+ request.skip_esp_check === true
1300
+ ]);
1301
+ }
1302
+ if (path === "api/v1/company-signals") {
1303
+ const online = request.online !== false;
1304
+ const deepSearch = request.enable_deep_search === void 0 ? online : request.enable_deep_search !== false;
1305
+ return JSON.stringify([
1306
+ normalizedBatchText(request.signal_run_id),
1307
+ normalizedBatchDomain(request.company_domain || request.domain),
1308
+ normalizedBatchText(request.company_name),
1309
+ normalizedBatchText(request.company_id),
1310
+ normalizedBatchLinkedIn(request.linkedin_url),
1311
+ normalizedBatchText(request.industry),
1312
+ typeof request.research_prompt === "string" ? request.research_prompt.trim() : "",
1313
+ normalizedBatchList(request.signal_types),
1314
+ Number(request.target_signal_count) || null,
1315
+ Number(request.lookback_days) || null,
1316
+ online,
1317
+ deepSearch,
1318
+ normalizedBatchText(request.search_mode || "balanced"),
1319
+ request.enable_outreach_intelligence === true,
1320
+ request.enable_predictive_intelligence === true,
1321
+ request.skip_cache === true || request.bypass_cache === true
1322
+ ]);
1323
+ }
1324
+ return JSON.stringify([
1325
+ normalizedBatchDomain(request.company_domain),
1326
+ typeof request.person_name === "string" ? request.person_name.trim() : "",
1327
+ typeof request.title === "string" ? request.title.trim() : "",
1328
+ typeof request.campaign_offer === "string" ? request.campaign_offer.trim() : "",
1329
+ typeof request.research_prompt === "string" ? request.research_prompt.trim() : "",
1330
+ typeof request.signal_run_id === "string" ? request.signal_run_id.trim() : "",
1331
+ request.skip_cache === true,
1332
+ request.enable_deep_search === true
1333
+ ]);
1334
+ }
1250
1335
  function finalizeCoreBatch(total, startedAt, round, normalize, options) {
1251
1336
  const results = new Array(total);
1252
1337
  for (const item of round) {
1253
1338
  if (!item.success || !item.raw) {
1254
- results[item.index] = batchItemFailure(
1339
+ const failure = batchItemFailure(
1255
1340
  item.index,
1256
1341
  item.error || "Signaliz batch item failed",
1257
1342
  item.raw ?? item
1258
1343
  );
1344
+ if (item.raw?.is_malformed === true) {
1345
+ failure.data = normalize(item);
1346
+ }
1347
+ results[item.index] = failure;
1259
1348
  continue;
1260
1349
  }
1261
1350
  try {
@@ -1328,17 +1417,21 @@ function validateCoreProductMaxWaitMs(value) {
1328
1417
  }
1329
1418
  }
1330
1419
  function normalizeSignalToCopyResult(data) {
1420
+ const failed = coreProductResponseFailed(data);
1331
1421
  return {
1332
- success: data.success ?? true,
1422
+ success: !failed,
1423
+ error: failed ? coreProductErrorMessage(data) : void 0,
1424
+ errorCode: failed ? coreProductErrorCode(data) : void 0,
1333
1425
  status: data.status,
1334
- runId: data.signal_run_id ?? data.run_id,
1426
+ runId: data.run_id ?? data.signal_run_id,
1427
+ companySignalRunId: data.company_signal_run_id,
1335
1428
  resumeContextPersisted: data.resume_context_persisted,
1336
- strongestSignal: data.strongest_signal ?? "",
1337
- whyNow: data.why_now ?? "",
1338
- subjectLine: data.subject_line ?? "",
1339
- openingLine: data.opening_line ?? "",
1340
- confidence: data.confidence ?? 0,
1341
- evidenceUrl: data.evidence_url ?? "",
1429
+ strongestSignal: failed ? "" : data.strongest_signal ?? "",
1430
+ whyNow: failed ? "" : data.why_now ?? "",
1431
+ subjectLine: failed ? "" : data.subject_line ?? "",
1432
+ openingLine: failed ? "" : data.opening_line ?? "",
1433
+ confidence: failed ? 0 : data.confidence ?? 0,
1434
+ evidenceUrl: failed ? "" : data.evidence_url ?? "",
1342
1435
  researchPrompt: data.research_prompt,
1343
1436
  empty: data.empty,
1344
1437
  emptyReason: data.empty_reason,
@@ -1351,7 +1444,7 @@ function normalizeSignalToCopyResult(data) {
1351
1444
  liveProviderCalled: data.live_provider_called,
1352
1445
  aiProviderCalled: data.ai_provider_called,
1353
1446
  byoAiUsed: data.byo_ai_used,
1354
- variations: (data.variations ?? []).map((variation) => ({
1447
+ variations: (failed ? [] : data.variations ?? []).map((variation) => ({
1355
1448
  style: variation.style,
1356
1449
  subjectLine: variation.subject_line ?? "",
1357
1450
  openingLine: variation.opening_line ?? "",
@@ -1363,8 +1456,32 @@ function normalizeSignalToCopyResult(data) {
1363
1456
  };
1364
1457
  }
1365
1458
  function isPendingSignalResponse(data) {
1459
+ if (coreProductResponseFailed(data)) return false;
1366
1460
  return ["triggered", "queued", "processing", "pending", "pending_version", "waiting_for_deploy"].includes(String(data.status || "").toLowerCase());
1367
1461
  }
1462
+ function coreProductResponseFailed(data) {
1463
+ if (data.success === false) return true;
1464
+ if (typeof data.error_code === "string" && data.error_code.trim()) return true;
1465
+ if (typeof data.error === "string" && data.error.trim()) return true;
1466
+ if (data.error && typeof data.error === "object" && Object.keys(data.error).length > 0) return true;
1467
+ return ["failed", "error", "cancelled", "canceled"].includes(String(data.status || "").toLowerCase());
1468
+ }
1469
+ function coreProductErrorMessage(data) {
1470
+ const nested = data.error && typeof data.error === "object" ? data.error : void 0;
1471
+ const candidates = [nested?.message, data.message, typeof data.error === "string" ? data.error : void 0];
1472
+ for (const candidate of candidates) {
1473
+ if (typeof candidate === "string" && candidate.trim()) return candidate.trim();
1474
+ }
1475
+ return void 0;
1476
+ }
1477
+ function coreProductErrorCode(data) {
1478
+ const nested = data.error && typeof data.error === "object" ? data.error : void 0;
1479
+ const candidates = [data.error_code, nested?.code, data.code];
1480
+ for (const candidate of candidates) {
1481
+ if (typeof candidate === "string" && candidate.trim()) return candidate.trim();
1482
+ }
1483
+ return void 0;
1484
+ }
1368
1485
  function assertTerminalSignalResponse(data, capability) {
1369
1486
  if (isPendingSignalResponse(data) || data.job_id) {
1370
1487
  throw new Error(`${capability} violated the synchronous response contract.`);
package/dist/index.d.mts CHANGED
@@ -116,6 +116,8 @@ interface FindEmailResult {
116
116
  }
117
117
  interface VerifyEmailResult {
118
118
  success: boolean;
119
+ error?: string;
120
+ errorCode?: string;
119
121
  email: string;
120
122
  /** Execution state. Processing results are never send-safe. */
121
123
  status: 'processing' | 'completed';
@@ -216,6 +218,8 @@ interface CompanySignal {
216
218
  }
217
219
  interface CompanySignalEnrichmentResult {
218
220
  success: boolean;
221
+ error?: string;
222
+ errorCode?: string;
219
223
  status?: string;
220
224
  signalRunId?: string;
221
225
  company: {
@@ -353,12 +357,15 @@ interface SignalToCopyVariation {
353
357
  openingLine: string;
354
358
  cta: string;
355
359
  prediction?: string;
356
- email?: string;
360
+ email: string;
357
361
  }
358
362
  interface SignalToCopyResult {
359
363
  success: boolean;
364
+ error?: string;
365
+ errorCode?: string;
360
366
  status?: string;
361
367
  runId?: string;
368
+ companySignalRunId?: string;
362
369
  resumeContextPersisted?: boolean;
363
370
  strongestSignal: string;
364
371
  whyNow: string;
package/dist/index.d.ts CHANGED
@@ -116,6 +116,8 @@ interface FindEmailResult {
116
116
  }
117
117
  interface VerifyEmailResult {
118
118
  success: boolean;
119
+ error?: string;
120
+ errorCode?: string;
119
121
  email: string;
120
122
  /** Execution state. Processing results are never send-safe. */
121
123
  status: 'processing' | 'completed';
@@ -216,6 +218,8 @@ interface CompanySignal {
216
218
  }
217
219
  interface CompanySignalEnrichmentResult {
218
220
  success: boolean;
221
+ error?: string;
222
+ errorCode?: string;
219
223
  status?: string;
220
224
  signalRunId?: string;
221
225
  company: {
@@ -353,12 +357,15 @@ interface SignalToCopyVariation {
353
357
  openingLine: string;
354
358
  cta: string;
355
359
  prediction?: string;
356
- email?: string;
360
+ email: string;
357
361
  }
358
362
  interface SignalToCopyResult {
359
363
  success: boolean;
364
+ error?: string;
365
+ errorCode?: string;
360
366
  status?: string;
361
367
  runId?: string;
368
+ companySignalRunId?: string;
362
369
  resumeContextPersisted?: boolean;
363
370
  strongestSignal: string;
364
371
  whyNow: string;
package/dist/index.js CHANGED
@@ -559,9 +559,10 @@ var Signaliz = class {
559
559
  );
560
560
  }
561
561
  const startedAt = Date.now();
562
- const deduplicated = dedupeExactBatchItems(requests, (params) => JSON.stringify({
563
- request: signalToCopyRequestBody(params)
564
- }));
562
+ const deduplicated = dedupeExactBatchItems(
563
+ requests,
564
+ (params) => coreProductBatchRequestKey("api/v1/signal-to-copy", signalToCopyRequestBody(params))
565
+ );
565
566
  const uniqueRequests = deduplicated.uniqueItems;
566
567
  const uniqueInputIndices = new Array(uniqueRequests.length);
567
568
  deduplicated.sourceIndexByInput.forEach((uniqueIndex, inputIndex) => {
@@ -718,7 +719,7 @@ var Signaliz = class {
718
719
  }
719
720
  for (let index = 0; index < requests.length; index += 1) {
720
721
  const item = data.results[index];
721
- if (item.success === false) {
722
+ if (coreProductResponseFailed(item)) {
722
723
  if (rowRateLimitAttempt < MAX_ROW_RATE_LIMIT_RETRIES && isRetryableRowRateLimit({
723
724
  index,
724
725
  success: false,
@@ -727,7 +728,11 @@ var Signaliz = class {
727
728
  rateLimited.push({ index, params: requests[index], raw: item });
728
729
  continue;
729
730
  }
730
- results[index] = batchItemFailure(index, item.error || item.message || "Signal to Copy failed", item);
731
+ results[index] = batchItemFailure(
732
+ index,
733
+ coreProductErrorMessage(item) || "Signal to Copy failed",
734
+ item
735
+ );
731
736
  continue;
732
737
  }
733
738
  try {
@@ -758,7 +763,10 @@ var Signaliz = class {
758
763
  }
759
764
  async runCoreBatchRound(path, tasks, options, rowRateLimitAttempt = 0) {
760
765
  const { serverConcurrency, chunkConcurrency } = path === "api/v1/company-signals" ? batchConcurrencyPlan(options, 25, 25) : batchConcurrencyPlan(options);
761
- const deduplicated = dedupeExactBatchItems(tasks, (task) => JSON.stringify(task.request));
766
+ const deduplicated = dedupeExactBatchItems(
767
+ tasks,
768
+ (task) => coreProductBatchRequestKey(path, task.request)
769
+ );
762
770
  const uniqueTasks = deduplicated.uniqueItems;
763
771
  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;
764
772
  if (path !== "api/v1/company-signals" && recoverableBatch && uniqueTasks.length > 25) {
@@ -825,9 +833,9 @@ var Signaliz = class {
825
833
  const raw = chunkResult.data[index];
826
834
  uniqueResults[chunk.offset + index] = {
827
835
  index: chunk.tasks[index].index,
828
- success: raw.success !== false,
836
+ success: !coreProductResponseFailed(raw),
829
837
  raw,
830
- error: raw.success === false ? raw.error || raw.message || raw.error_code || `${path} item failed` : void 0
838
+ error: coreProductResponseFailed(raw) ? coreProductErrorMessage(raw) || coreProductErrorCode(raw) || `${path} item failed` : void 0
831
839
  };
832
840
  }
833
841
  }
@@ -897,7 +905,7 @@ function batchItemFailure(index, error, raw) {
897
905
  };
898
906
  }
899
907
  function recoverableJobRowFailed(row) {
900
- return row.success === false || ["failed", "skipped"].includes(String(row._status || "").toLowerCase());
908
+ return coreProductResponseFailed(row) || ["failed", "skipped"].includes(String(row._status || "").toLowerCase());
901
909
  }
902
910
  function newBatchIdempotencyKey(label) {
903
911
  const nonce = globalThis.crypto?.randomUUID?.() || `${Date.now()}-${Math.random().toString(16).slice(2)}`;
@@ -947,7 +955,9 @@ function normalizeCoreProductDryRunResult(data) {
947
955
  };
948
956
  }
949
957
  function normalizeFindEmailResult(data) {
950
- const email = typeof data.email === "string" && data.email.trim() ? data.email.trim() : null;
958
+ const failed = coreProductResponseFailed(data);
959
+ const rawEmail = typeof data.email === "string" && data.email.trim() ? data.email.trim() : null;
960
+ const email = failed ? null : rawEmail;
951
961
  const found = Boolean(email) && data.found !== false;
952
962
  const verificationStatus = data.verification_status ?? (data.is_valid === true ? "valid" : data.status ?? "unknown");
953
963
  const rawFreshness = String(data.verification_freshness ?? "").toLowerCase();
@@ -957,7 +967,7 @@ function normalizeFindEmailResult(data) {
957
967
  const verified = !explicitlyNotSendSafe && (data.is_valid === true || data.isValid === true || data.email_verified === true || data.verified_for_sending === true || ["valid", "deliverable"].includes(String(verificationStatus).toLowerCase()));
958
968
  const verificationAgeDays = typeof data.verification_age_days === "number" && Number.isFinite(data.verification_age_days) ? data.verification_age_days : null;
959
969
  return {
960
- success: data.success !== false && found,
970
+ success: !failed && found,
961
971
  found,
962
972
  email,
963
973
  firstName: data.first_name,
@@ -984,26 +994,29 @@ function normalizeFindEmailResult(data) {
984
994
  liveProviderCalled: data.live_provider_called,
985
995
  openrouterCalled: data.openrouter_called,
986
996
  byoOpenrouterUsed: data.byo_openrouter_used,
987
- error: found ? void 0 : data.error ?? "No verified email found",
988
- errorCode: found ? void 0 : data.error_code ?? "EMAIL_NOT_FOUND",
997
+ error: found ? void 0 : coreProductErrorMessage(data) ?? "No verified email found",
998
+ errorCode: found ? void 0 : coreProductErrorCode(data) ?? "EMAIL_NOT_FOUND",
989
999
  raw: data
990
1000
  };
991
1001
  }
992
1002
  function normalizeVerifyEmailResult(email, data) {
1003
+ const failed = coreProductResponseFailed(data);
993
1004
  const verificationStatus = String(data.verification_status ?? "").toLowerCase();
994
- const verified = data.email_verified === true || ["valid", "deliverable"].includes(verificationStatus);
1005
+ const verified = !failed && (data.email_verified === true || ["valid", "deliverable"].includes(verificationStatus));
995
1006
  return {
996
- success: data.success !== false,
1007
+ success: !failed,
1008
+ error: failed ? coreProductErrorMessage(data) : void 0,
1009
+ errorCode: failed ? coreProductErrorCode(data) : void 0,
997
1010
  email: data.email ?? email,
998
- status: String(data.status || "").toLowerCase() === "processing" ? "processing" : "completed",
1011
+ status: !failed && String(data.status || "").toLowerCase() === "processing" ? "processing" : "completed",
999
1012
  verificationRunId: data.verification_run_id ?? data.run_id,
1000
1013
  retryAfterMs: data.retry_after_ms,
1001
1014
  nextPollAfterSeconds: data.next_poll_after_seconds,
1002
- isValid: data.is_valid ?? data.valid ?? verified,
1003
- isDeliverable: data.is_deliverable ?? data.deliverable ?? verified,
1015
+ isValid: failed ? false : data.is_valid ?? data.valid ?? verified,
1016
+ isDeliverable: failed ? false : data.is_deliverable ?? data.deliverable ?? verified,
1004
1017
  isMalformed: data.is_malformed === true || data.verification_verdict === "malformed" || data.verification_status === "malformed" || data.deliverability_status === "malformed",
1005
1018
  isCatchAll: data.email_is_catch_all ?? data.is_catch_all ?? data.catch_all ?? data.diagnostics?.is_catch_all ?? false,
1006
- verifiedForSending: data.verified_for_sending === true,
1019
+ verifiedForSending: !failed && data.verified_for_sending === true,
1007
1020
  verificationVerdict: data.verification_verdict ?? data.verification_status ?? "unknown",
1008
1021
  confidenceScore: data.confidence_score ?? data.confidence ?? data.diagnostics?.confidence_score ?? (verified ? 1 : 0),
1009
1022
  provider: data.provider,
@@ -1048,9 +1061,12 @@ function companySignalRequestBody(params) {
1048
1061
  });
1049
1062
  }
1050
1063
  function normalizeCompanySignalResult(params, data) {
1051
- const rawSignals = data.signals ?? data.signal_feed ?? [];
1064
+ const failed = coreProductResponseFailed(data);
1065
+ const rawSignals = failed ? [] : data.signals ?? data.signal_feed ?? [];
1052
1066
  return {
1053
- success: data.success ?? true,
1067
+ success: !failed,
1068
+ error: failed ? coreProductErrorMessage(data) : void 0,
1069
+ errorCode: failed ? coreProductErrorCode(data) : void 0,
1054
1070
  status: data.status,
1055
1071
  signalRunId: data.signal_run_id ?? data.run_id ?? params.signalRunId,
1056
1072
  company: {
@@ -1274,15 +1290,88 @@ function dedupeExactBatchItems(items, keyForItem) {
1274
1290
  }
1275
1291
  return { uniqueItems, sourceIndexByInput };
1276
1292
  }
1293
+ function normalizedBatchText(value) {
1294
+ return typeof value === "string" ? value.trim().toLowerCase().replace(/\s+/g, " ") : "";
1295
+ }
1296
+ function normalizedBatchDomain(value) {
1297
+ return normalizedBatchText(value).replace(/^https?:\/\//, "").replace(/^www\./, "").split(/[/?#]/, 1)[0].replace(/\.+$/, "");
1298
+ }
1299
+ function normalizedBatchLinkedIn(value) {
1300
+ return normalizedBatchText(value).replace(/\/+$/, "");
1301
+ }
1302
+ function normalizedBatchList(value) {
1303
+ return Array.isArray(value) ? value.map(normalizedBatchText).filter(Boolean).sort() : [];
1304
+ }
1305
+ function normalizedFindEmailBatchName(request) {
1306
+ const fullName = normalizedBatchText(request.full_name);
1307
+ const componentName = [normalizedBatchText(request.first_name), normalizedBatchText(request.last_name)].filter(Boolean).join(" ");
1308
+ if (!fullName || !componentName || fullName === componentName) return fullName || componentName;
1309
+ return JSON.stringify([fullName, componentName]);
1310
+ }
1311
+ function coreProductBatchRequestKey(path, request) {
1312
+ if (path === "api/v1/find-email") {
1313
+ return JSON.stringify([
1314
+ normalizedFindEmailBatchName(request),
1315
+ normalizedBatchDomain(request.company_domain),
1316
+ normalizedBatchLinkedIn(request.linkedin_url),
1317
+ normalizedBatchText(request.company_name),
1318
+ request.skip_cache === true || request.bypass_cache === true
1319
+ ]);
1320
+ }
1321
+ if (path === "api/v1/verify-email") {
1322
+ return JSON.stringify([
1323
+ normalizedBatchText(request.email),
1324
+ request.skip_cache === true || request.bypass_cache === true,
1325
+ request.skip_catch_all_verification === true,
1326
+ request.skip_esp_check === true
1327
+ ]);
1328
+ }
1329
+ if (path === "api/v1/company-signals") {
1330
+ const online = request.online !== false;
1331
+ const deepSearch = request.enable_deep_search === void 0 ? online : request.enable_deep_search !== false;
1332
+ return JSON.stringify([
1333
+ normalizedBatchText(request.signal_run_id),
1334
+ normalizedBatchDomain(request.company_domain || request.domain),
1335
+ normalizedBatchText(request.company_name),
1336
+ normalizedBatchText(request.company_id),
1337
+ normalizedBatchLinkedIn(request.linkedin_url),
1338
+ normalizedBatchText(request.industry),
1339
+ typeof request.research_prompt === "string" ? request.research_prompt.trim() : "",
1340
+ normalizedBatchList(request.signal_types),
1341
+ Number(request.target_signal_count) || null,
1342
+ Number(request.lookback_days) || null,
1343
+ online,
1344
+ deepSearch,
1345
+ normalizedBatchText(request.search_mode || "balanced"),
1346
+ request.enable_outreach_intelligence === true,
1347
+ request.enable_predictive_intelligence === true,
1348
+ request.skip_cache === true || request.bypass_cache === true
1349
+ ]);
1350
+ }
1351
+ return JSON.stringify([
1352
+ normalizedBatchDomain(request.company_domain),
1353
+ typeof request.person_name === "string" ? request.person_name.trim() : "",
1354
+ typeof request.title === "string" ? request.title.trim() : "",
1355
+ typeof request.campaign_offer === "string" ? request.campaign_offer.trim() : "",
1356
+ typeof request.research_prompt === "string" ? request.research_prompt.trim() : "",
1357
+ typeof request.signal_run_id === "string" ? request.signal_run_id.trim() : "",
1358
+ request.skip_cache === true,
1359
+ request.enable_deep_search === true
1360
+ ]);
1361
+ }
1277
1362
  function finalizeCoreBatch(total, startedAt, round, normalize, options) {
1278
1363
  const results = new Array(total);
1279
1364
  for (const item of round) {
1280
1365
  if (!item.success || !item.raw) {
1281
- results[item.index] = batchItemFailure(
1366
+ const failure = batchItemFailure(
1282
1367
  item.index,
1283
1368
  item.error || "Signaliz batch item failed",
1284
1369
  item.raw ?? item
1285
1370
  );
1371
+ if (item.raw?.is_malformed === true) {
1372
+ failure.data = normalize(item);
1373
+ }
1374
+ results[item.index] = failure;
1286
1375
  continue;
1287
1376
  }
1288
1377
  try {
@@ -1355,17 +1444,21 @@ function validateCoreProductMaxWaitMs(value) {
1355
1444
  }
1356
1445
  }
1357
1446
  function normalizeSignalToCopyResult(data) {
1447
+ const failed = coreProductResponseFailed(data);
1358
1448
  return {
1359
- success: data.success ?? true,
1449
+ success: !failed,
1450
+ error: failed ? coreProductErrorMessage(data) : void 0,
1451
+ errorCode: failed ? coreProductErrorCode(data) : void 0,
1360
1452
  status: data.status,
1361
- runId: data.signal_run_id ?? data.run_id,
1453
+ runId: data.run_id ?? data.signal_run_id,
1454
+ companySignalRunId: data.company_signal_run_id,
1362
1455
  resumeContextPersisted: data.resume_context_persisted,
1363
- strongestSignal: data.strongest_signal ?? "",
1364
- whyNow: data.why_now ?? "",
1365
- subjectLine: data.subject_line ?? "",
1366
- openingLine: data.opening_line ?? "",
1367
- confidence: data.confidence ?? 0,
1368
- evidenceUrl: data.evidence_url ?? "",
1456
+ strongestSignal: failed ? "" : data.strongest_signal ?? "",
1457
+ whyNow: failed ? "" : data.why_now ?? "",
1458
+ subjectLine: failed ? "" : data.subject_line ?? "",
1459
+ openingLine: failed ? "" : data.opening_line ?? "",
1460
+ confidence: failed ? 0 : data.confidence ?? 0,
1461
+ evidenceUrl: failed ? "" : data.evidence_url ?? "",
1369
1462
  researchPrompt: data.research_prompt,
1370
1463
  empty: data.empty,
1371
1464
  emptyReason: data.empty_reason,
@@ -1378,7 +1471,7 @@ function normalizeSignalToCopyResult(data) {
1378
1471
  liveProviderCalled: data.live_provider_called,
1379
1472
  aiProviderCalled: data.ai_provider_called,
1380
1473
  byoAiUsed: data.byo_ai_used,
1381
- variations: (data.variations ?? []).map((variation) => ({
1474
+ variations: (failed ? [] : data.variations ?? []).map((variation) => ({
1382
1475
  style: variation.style,
1383
1476
  subjectLine: variation.subject_line ?? "",
1384
1477
  openingLine: variation.opening_line ?? "",
@@ -1390,8 +1483,32 @@ function normalizeSignalToCopyResult(data) {
1390
1483
  };
1391
1484
  }
1392
1485
  function isPendingSignalResponse(data) {
1486
+ if (coreProductResponseFailed(data)) return false;
1393
1487
  return ["triggered", "queued", "processing", "pending", "pending_version", "waiting_for_deploy"].includes(String(data.status || "").toLowerCase());
1394
1488
  }
1489
+ function coreProductResponseFailed(data) {
1490
+ if (data.success === false) return true;
1491
+ if (typeof data.error_code === "string" && data.error_code.trim()) return true;
1492
+ if (typeof data.error === "string" && data.error.trim()) return true;
1493
+ if (data.error && typeof data.error === "object" && Object.keys(data.error).length > 0) return true;
1494
+ return ["failed", "error", "cancelled", "canceled"].includes(String(data.status || "").toLowerCase());
1495
+ }
1496
+ function coreProductErrorMessage(data) {
1497
+ const nested = data.error && typeof data.error === "object" ? data.error : void 0;
1498
+ const candidates = [nested?.message, data.message, typeof data.error === "string" ? data.error : void 0];
1499
+ for (const candidate of candidates) {
1500
+ if (typeof candidate === "string" && candidate.trim()) return candidate.trim();
1501
+ }
1502
+ return void 0;
1503
+ }
1504
+ function coreProductErrorCode(data) {
1505
+ const nested = data.error && typeof data.error === "object" ? data.error : void 0;
1506
+ const candidates = [data.error_code, nested?.code, data.code];
1507
+ for (const candidate of candidates) {
1508
+ if (typeof candidate === "string" && candidate.trim()) return candidate.trim();
1509
+ }
1510
+ return void 0;
1511
+ }
1395
1512
  function assertTerminalSignalResponse(data, capability) {
1396
1513
  if (isPendingSignalResponse(data) || data.job_id) {
1397
1514
  throw new Error(`${capability} violated the synchronous response contract.`);
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  Signaliz,
3
3
  SignalizError
4
- } from "./chunk-K7RDDRMJ.mjs";
4
+ } from "./chunk-EAKP4DSS.mjs";
5
5
  export {
6
6
  Signaliz,
7
7
  SignalizError
@@ -563,9 +563,10 @@ var Signaliz = class {
563
563
  );
564
564
  }
565
565
  const startedAt = Date.now();
566
- const deduplicated = dedupeExactBatchItems(requests, (params) => JSON.stringify({
567
- request: signalToCopyRequestBody(params)
568
- }));
566
+ const deduplicated = dedupeExactBatchItems(
567
+ requests,
568
+ (params) => coreProductBatchRequestKey("api/v1/signal-to-copy", signalToCopyRequestBody(params))
569
+ );
569
570
  const uniqueRequests = deduplicated.uniqueItems;
570
571
  const uniqueInputIndices = new Array(uniqueRequests.length);
571
572
  deduplicated.sourceIndexByInput.forEach((uniqueIndex, inputIndex) => {
@@ -722,7 +723,7 @@ var Signaliz = class {
722
723
  }
723
724
  for (let index = 0; index < requests.length; index += 1) {
724
725
  const item = data.results[index];
725
- if (item.success === false) {
726
+ if (coreProductResponseFailed(item)) {
726
727
  if (rowRateLimitAttempt < MAX_ROW_RATE_LIMIT_RETRIES && isRetryableRowRateLimit({
727
728
  index,
728
729
  success: false,
@@ -731,7 +732,11 @@ var Signaliz = class {
731
732
  rateLimited.push({ index, params: requests[index], raw: item });
732
733
  continue;
733
734
  }
734
- results[index] = batchItemFailure(index, item.error || item.message || "Signal to Copy failed", item);
735
+ results[index] = batchItemFailure(
736
+ index,
737
+ coreProductErrorMessage(item) || "Signal to Copy failed",
738
+ item
739
+ );
735
740
  continue;
736
741
  }
737
742
  try {
@@ -762,7 +767,10 @@ var Signaliz = class {
762
767
  }
763
768
  async runCoreBatchRound(path2, tasks, options, rowRateLimitAttempt = 0) {
764
769
  const { serverConcurrency, chunkConcurrency } = path2 === "api/v1/company-signals" ? batchConcurrencyPlan(options, 25, 25) : batchConcurrencyPlan(options);
765
- const deduplicated = dedupeExactBatchItems(tasks, (task) => JSON.stringify(task.request));
770
+ const deduplicated = dedupeExactBatchItems(
771
+ tasks,
772
+ (task) => coreProductBatchRequestKey(path2, task.request)
773
+ );
766
774
  const uniqueTasks = deduplicated.uniqueItems;
767
775
  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;
768
776
  if (path2 !== "api/v1/company-signals" && recoverableBatch && uniqueTasks.length > 25) {
@@ -829,9 +837,9 @@ var Signaliz = class {
829
837
  const raw = chunkResult.data[index];
830
838
  uniqueResults[chunk.offset + index] = {
831
839
  index: chunk.tasks[index].index,
832
- success: raw.success !== false,
840
+ success: !coreProductResponseFailed(raw),
833
841
  raw,
834
- error: raw.success === false ? raw.error || raw.message || raw.error_code || `${path2} item failed` : void 0
842
+ error: coreProductResponseFailed(raw) ? coreProductErrorMessage(raw) || coreProductErrorCode(raw) || `${path2} item failed` : void 0
835
843
  };
836
844
  }
837
845
  }
@@ -901,7 +909,7 @@ function batchItemFailure(index, error, raw) {
901
909
  };
902
910
  }
903
911
  function recoverableJobRowFailed(row) {
904
- return row.success === false || ["failed", "skipped"].includes(String(row._status || "").toLowerCase());
912
+ return coreProductResponseFailed(row) || ["failed", "skipped"].includes(String(row._status || "").toLowerCase());
905
913
  }
906
914
  function newBatchIdempotencyKey(label) {
907
915
  const nonce = globalThis.crypto?.randomUUID?.() || `${Date.now()}-${Math.random().toString(16).slice(2)}`;
@@ -951,7 +959,9 @@ function normalizeCoreProductDryRunResult(data) {
951
959
  };
952
960
  }
953
961
  function normalizeFindEmailResult(data) {
954
- const email = typeof data.email === "string" && data.email.trim() ? data.email.trim() : null;
962
+ const failed = coreProductResponseFailed(data);
963
+ const rawEmail = typeof data.email === "string" && data.email.trim() ? data.email.trim() : null;
964
+ const email = failed ? null : rawEmail;
955
965
  const found = Boolean(email) && data.found !== false;
956
966
  const verificationStatus = data.verification_status ?? (data.is_valid === true ? "valid" : data.status ?? "unknown");
957
967
  const rawFreshness = String(data.verification_freshness ?? "").toLowerCase();
@@ -961,7 +971,7 @@ function normalizeFindEmailResult(data) {
961
971
  const verified = !explicitlyNotSendSafe && (data.is_valid === true || data.isValid === true || data.email_verified === true || data.verified_for_sending === true || ["valid", "deliverable"].includes(String(verificationStatus).toLowerCase()));
962
972
  const verificationAgeDays = typeof data.verification_age_days === "number" && Number.isFinite(data.verification_age_days) ? data.verification_age_days : null;
963
973
  return {
964
- success: data.success !== false && found,
974
+ success: !failed && found,
965
975
  found,
966
976
  email,
967
977
  firstName: data.first_name,
@@ -988,26 +998,29 @@ function normalizeFindEmailResult(data) {
988
998
  liveProviderCalled: data.live_provider_called,
989
999
  openrouterCalled: data.openrouter_called,
990
1000
  byoOpenrouterUsed: data.byo_openrouter_used,
991
- error: found ? void 0 : data.error ?? "No verified email found",
992
- errorCode: found ? void 0 : data.error_code ?? "EMAIL_NOT_FOUND",
1001
+ error: found ? void 0 : coreProductErrorMessage(data) ?? "No verified email found",
1002
+ errorCode: found ? void 0 : coreProductErrorCode(data) ?? "EMAIL_NOT_FOUND",
993
1003
  raw: data
994
1004
  };
995
1005
  }
996
1006
  function normalizeVerifyEmailResult(email, data) {
1007
+ const failed = coreProductResponseFailed(data);
997
1008
  const verificationStatus = String(data.verification_status ?? "").toLowerCase();
998
- const verified = data.email_verified === true || ["valid", "deliverable"].includes(verificationStatus);
1009
+ const verified = !failed && (data.email_verified === true || ["valid", "deliverable"].includes(verificationStatus));
999
1010
  return {
1000
- success: data.success !== false,
1011
+ success: !failed,
1012
+ error: failed ? coreProductErrorMessage(data) : void 0,
1013
+ errorCode: failed ? coreProductErrorCode(data) : void 0,
1001
1014
  email: data.email ?? email,
1002
- status: String(data.status || "").toLowerCase() === "processing" ? "processing" : "completed",
1015
+ status: !failed && String(data.status || "").toLowerCase() === "processing" ? "processing" : "completed",
1003
1016
  verificationRunId: data.verification_run_id ?? data.run_id,
1004
1017
  retryAfterMs: data.retry_after_ms,
1005
1018
  nextPollAfterSeconds: data.next_poll_after_seconds,
1006
- isValid: data.is_valid ?? data.valid ?? verified,
1007
- isDeliverable: data.is_deliverable ?? data.deliverable ?? verified,
1019
+ isValid: failed ? false : data.is_valid ?? data.valid ?? verified,
1020
+ isDeliverable: failed ? false : data.is_deliverable ?? data.deliverable ?? verified,
1008
1021
  isMalformed: data.is_malformed === true || data.verification_verdict === "malformed" || data.verification_status === "malformed" || data.deliverability_status === "malformed",
1009
1022
  isCatchAll: data.email_is_catch_all ?? data.is_catch_all ?? data.catch_all ?? data.diagnostics?.is_catch_all ?? false,
1010
- verifiedForSending: data.verified_for_sending === true,
1023
+ verifiedForSending: !failed && data.verified_for_sending === true,
1011
1024
  verificationVerdict: data.verification_verdict ?? data.verification_status ?? "unknown",
1012
1025
  confidenceScore: data.confidence_score ?? data.confidence ?? data.diagnostics?.confidence_score ?? (verified ? 1 : 0),
1013
1026
  provider: data.provider,
@@ -1052,9 +1065,12 @@ function companySignalRequestBody(params) {
1052
1065
  });
1053
1066
  }
1054
1067
  function normalizeCompanySignalResult(params, data) {
1055
- const rawSignals = data.signals ?? data.signal_feed ?? [];
1068
+ const failed = coreProductResponseFailed(data);
1069
+ const rawSignals = failed ? [] : data.signals ?? data.signal_feed ?? [];
1056
1070
  return {
1057
- success: data.success ?? true,
1071
+ success: !failed,
1072
+ error: failed ? coreProductErrorMessage(data) : void 0,
1073
+ errorCode: failed ? coreProductErrorCode(data) : void 0,
1058
1074
  status: data.status,
1059
1075
  signalRunId: data.signal_run_id ?? data.run_id ?? params.signalRunId,
1060
1076
  company: {
@@ -1278,15 +1294,88 @@ function dedupeExactBatchItems(items, keyForItem) {
1278
1294
  }
1279
1295
  return { uniqueItems, sourceIndexByInput };
1280
1296
  }
1297
+ function normalizedBatchText(value) {
1298
+ return typeof value === "string" ? value.trim().toLowerCase().replace(/\s+/g, " ") : "";
1299
+ }
1300
+ function normalizedBatchDomain(value) {
1301
+ return normalizedBatchText(value).replace(/^https?:\/\//, "").replace(/^www\./, "").split(/[/?#]/, 1)[0].replace(/\.+$/, "");
1302
+ }
1303
+ function normalizedBatchLinkedIn(value) {
1304
+ return normalizedBatchText(value).replace(/\/+$/, "");
1305
+ }
1306
+ function normalizedBatchList(value) {
1307
+ return Array.isArray(value) ? value.map(normalizedBatchText).filter(Boolean).sort() : [];
1308
+ }
1309
+ function normalizedFindEmailBatchName(request) {
1310
+ const fullName = normalizedBatchText(request.full_name);
1311
+ const componentName = [normalizedBatchText(request.first_name), normalizedBatchText(request.last_name)].filter(Boolean).join(" ");
1312
+ if (!fullName || !componentName || fullName === componentName) return fullName || componentName;
1313
+ return JSON.stringify([fullName, componentName]);
1314
+ }
1315
+ function coreProductBatchRequestKey(path2, request) {
1316
+ if (path2 === "api/v1/find-email") {
1317
+ return JSON.stringify([
1318
+ normalizedFindEmailBatchName(request),
1319
+ normalizedBatchDomain(request.company_domain),
1320
+ normalizedBatchLinkedIn(request.linkedin_url),
1321
+ normalizedBatchText(request.company_name),
1322
+ request.skip_cache === true || request.bypass_cache === true
1323
+ ]);
1324
+ }
1325
+ if (path2 === "api/v1/verify-email") {
1326
+ return JSON.stringify([
1327
+ normalizedBatchText(request.email),
1328
+ request.skip_cache === true || request.bypass_cache === true,
1329
+ request.skip_catch_all_verification === true,
1330
+ request.skip_esp_check === true
1331
+ ]);
1332
+ }
1333
+ if (path2 === "api/v1/company-signals") {
1334
+ const online = request.online !== false;
1335
+ const deepSearch = request.enable_deep_search === void 0 ? online : request.enable_deep_search !== false;
1336
+ return JSON.stringify([
1337
+ normalizedBatchText(request.signal_run_id),
1338
+ normalizedBatchDomain(request.company_domain || request.domain),
1339
+ normalizedBatchText(request.company_name),
1340
+ normalizedBatchText(request.company_id),
1341
+ normalizedBatchLinkedIn(request.linkedin_url),
1342
+ normalizedBatchText(request.industry),
1343
+ typeof request.research_prompt === "string" ? request.research_prompt.trim() : "",
1344
+ normalizedBatchList(request.signal_types),
1345
+ Number(request.target_signal_count) || null,
1346
+ Number(request.lookback_days) || null,
1347
+ online,
1348
+ deepSearch,
1349
+ normalizedBatchText(request.search_mode || "balanced"),
1350
+ request.enable_outreach_intelligence === true,
1351
+ request.enable_predictive_intelligence === true,
1352
+ request.skip_cache === true || request.bypass_cache === true
1353
+ ]);
1354
+ }
1355
+ return JSON.stringify([
1356
+ normalizedBatchDomain(request.company_domain),
1357
+ typeof request.person_name === "string" ? request.person_name.trim() : "",
1358
+ typeof request.title === "string" ? request.title.trim() : "",
1359
+ typeof request.campaign_offer === "string" ? request.campaign_offer.trim() : "",
1360
+ typeof request.research_prompt === "string" ? request.research_prompt.trim() : "",
1361
+ typeof request.signal_run_id === "string" ? request.signal_run_id.trim() : "",
1362
+ request.skip_cache === true,
1363
+ request.enable_deep_search === true
1364
+ ]);
1365
+ }
1281
1366
  function finalizeCoreBatch(total, startedAt, round, normalize, options) {
1282
1367
  const results = new Array(total);
1283
1368
  for (const item of round) {
1284
1369
  if (!item.success || !item.raw) {
1285
- results[item.index] = batchItemFailure(
1370
+ const failure = batchItemFailure(
1286
1371
  item.index,
1287
1372
  item.error || "Signaliz batch item failed",
1288
1373
  item.raw ?? item
1289
1374
  );
1375
+ if (item.raw?.is_malformed === true) {
1376
+ failure.data = normalize(item);
1377
+ }
1378
+ results[item.index] = failure;
1290
1379
  continue;
1291
1380
  }
1292
1381
  try {
@@ -1359,17 +1448,21 @@ function validateCoreProductMaxWaitMs(value) {
1359
1448
  }
1360
1449
  }
1361
1450
  function normalizeSignalToCopyResult(data) {
1451
+ const failed = coreProductResponseFailed(data);
1362
1452
  return {
1363
- success: data.success ?? true,
1453
+ success: !failed,
1454
+ error: failed ? coreProductErrorMessage(data) : void 0,
1455
+ errorCode: failed ? coreProductErrorCode(data) : void 0,
1364
1456
  status: data.status,
1365
- runId: data.signal_run_id ?? data.run_id,
1457
+ runId: data.run_id ?? data.signal_run_id,
1458
+ companySignalRunId: data.company_signal_run_id,
1366
1459
  resumeContextPersisted: data.resume_context_persisted,
1367
- strongestSignal: data.strongest_signal ?? "",
1368
- whyNow: data.why_now ?? "",
1369
- subjectLine: data.subject_line ?? "",
1370
- openingLine: data.opening_line ?? "",
1371
- confidence: data.confidence ?? 0,
1372
- evidenceUrl: data.evidence_url ?? "",
1460
+ strongestSignal: failed ? "" : data.strongest_signal ?? "",
1461
+ whyNow: failed ? "" : data.why_now ?? "",
1462
+ subjectLine: failed ? "" : data.subject_line ?? "",
1463
+ openingLine: failed ? "" : data.opening_line ?? "",
1464
+ confidence: failed ? 0 : data.confidence ?? 0,
1465
+ evidenceUrl: failed ? "" : data.evidence_url ?? "",
1373
1466
  researchPrompt: data.research_prompt,
1374
1467
  empty: data.empty,
1375
1468
  emptyReason: data.empty_reason,
@@ -1382,7 +1475,7 @@ function normalizeSignalToCopyResult(data) {
1382
1475
  liveProviderCalled: data.live_provider_called,
1383
1476
  aiProviderCalled: data.ai_provider_called,
1384
1477
  byoAiUsed: data.byo_ai_used,
1385
- variations: (data.variations ?? []).map((variation) => ({
1478
+ variations: (failed ? [] : data.variations ?? []).map((variation) => ({
1386
1479
  style: variation.style,
1387
1480
  subjectLine: variation.subject_line ?? "",
1388
1481
  openingLine: variation.opening_line ?? "",
@@ -1394,8 +1487,32 @@ function normalizeSignalToCopyResult(data) {
1394
1487
  };
1395
1488
  }
1396
1489
  function isPendingSignalResponse(data) {
1490
+ if (coreProductResponseFailed(data)) return false;
1397
1491
  return ["triggered", "queued", "processing", "pending", "pending_version", "waiting_for_deploy"].includes(String(data.status || "").toLowerCase());
1398
1492
  }
1493
+ function coreProductResponseFailed(data) {
1494
+ if (data.success === false) return true;
1495
+ if (typeof data.error_code === "string" && data.error_code.trim()) return true;
1496
+ if (typeof data.error === "string" && data.error.trim()) return true;
1497
+ if (data.error && typeof data.error === "object" && Object.keys(data.error).length > 0) return true;
1498
+ return ["failed", "error", "cancelled", "canceled"].includes(String(data.status || "").toLowerCase());
1499
+ }
1500
+ function coreProductErrorMessage(data) {
1501
+ const nested = data.error && typeof data.error === "object" ? data.error : void 0;
1502
+ const candidates = [nested?.message, data.message, typeof data.error === "string" ? data.error : void 0];
1503
+ for (const candidate of candidates) {
1504
+ if (typeof candidate === "string" && candidate.trim()) return candidate.trim();
1505
+ }
1506
+ return void 0;
1507
+ }
1508
+ function coreProductErrorCode(data) {
1509
+ const nested = data.error && typeof data.error === "object" ? data.error : void 0;
1510
+ const candidates = [data.error_code, nested?.code, data.code];
1511
+ for (const candidate of candidates) {
1512
+ if (typeof candidate === "string" && candidate.trim()) return candidate.trim();
1513
+ }
1514
+ return void 0;
1515
+ }
1399
1516
  function assertTerminalSignalResponse(data, capability) {
1400
1517
  if (isPendingSignalResponse(data) || data.job_id) {
1401
1518
  throw new Error(`${capability} violated the synchronous response contract.`);
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  Signaliz
4
- } from "./chunk-K7RDDRMJ.mjs";
4
+ } from "./chunk-EAKP4DSS.mjs";
5
5
 
6
6
  // src/mcp-config.ts
7
7
  import * as fs from "fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signaliz/sdk",
3
- "version": "1.0.56",
3
+ "version": "1.0.58",
4
4
  "description": "Signaliz SDK for Signals Everything, Find Email, Verify Email, Company Signal Enrichment, and Signal to Copy AI.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",