@signaliz/sdk 1.0.64 → 1.0.66
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 +5 -0
- package/dist/{chunk-PDOG4IUP.mjs → chunk-ZXSNNBID.mjs} +100 -18
- package/dist/index.d.mts +39 -7
- package/dist/index.d.ts +39 -7
- package/dist/index.js +100 -18
- package/dist/index.mjs +1 -1
- package/dist/mcp-config.js +100 -18
- package/dist/mcp-config.mjs +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -39,6 +39,11 @@ const found = await signaliz.findEmail({
|
|
|
39
39
|
skipCache: true,
|
|
40
40
|
});
|
|
41
41
|
|
|
42
|
+
// An HTTPS LinkedIn person profile URL (/in/<slug>) is also sufficient on its own.
|
|
43
|
+
const foundFromLinkedIn = await signaliz.findEmail({
|
|
44
|
+
linkedinUrl: 'https://www.linkedin.com/in/jane-doe',
|
|
45
|
+
});
|
|
46
|
+
|
|
42
47
|
const verified = await signaliz.verifyEmail(found.email!, {
|
|
43
48
|
// Optional: bypass cached verification proof for a fresh-provider check.
|
|
44
49
|
skipCache: true,
|
|
@@ -47,6 +47,8 @@ function publicRetryDetails(body) {
|
|
|
47
47
|
...body?.retry_strategy !== void 0 ? { retry_strategy: body.retry_strategy } : {},
|
|
48
48
|
...body?.credits_used !== void 0 ? { credits_used: body.credits_used } : {},
|
|
49
49
|
...body?.credits_charged !== void 0 ? { credits_charged: body.credits_charged } : {},
|
|
50
|
+
...body?.live_provider_called !== void 0 ? { live_provider_called: body.live_provider_called } : {},
|
|
51
|
+
...body?.estimated_external_cost_usd !== void 0 ? { estimated_external_cost_usd: body.estimated_external_cost_usd } : {},
|
|
50
52
|
...body?.job_id !== void 0 ? { job_id: body.job_id } : {},
|
|
51
53
|
...body?.idempotency_key !== void 0 ? { idempotency_key: body.idempotency_key } : {},
|
|
52
54
|
...body?.verification_run_id !== void 0 ? { verification_run_id: body.verification_run_id } : {},
|
|
@@ -131,7 +133,8 @@ var HttpClient = class {
|
|
|
131
133
|
const err = parseError(res.status, errBody);
|
|
132
134
|
if (err.isRetryable && attempt < this.maxRetries) {
|
|
133
135
|
const retryWithNewKey = err.details?.retry_strategy === "new_idempotency_key" && err.details?.credits_used === 0 && err.details?.credits_charged === 0;
|
|
134
|
-
|
|
136
|
+
const recoverSameRun = err.details?.retry_strategy === "same_run_recovery";
|
|
137
|
+
if (retryWithNewKey || recoverSameRun) throw err;
|
|
135
138
|
const wait = err.retryAfter !== void 0 ? err.retryAfter * 1e3 : Math.min(1e3 * Math.pow(2, attempt), 1e4);
|
|
136
139
|
await sleep(wait);
|
|
137
140
|
lastError = err;
|
|
@@ -203,6 +206,7 @@ var HttpClient = class {
|
|
|
203
206
|
if (!res.ok) {
|
|
204
207
|
const err = parseError(res.status, data ?? { message: text });
|
|
205
208
|
if (err.isRetryable && attempt < this.maxRetries) {
|
|
209
|
+
if (err.details?.retry_strategy === "same_run_recovery") throw err;
|
|
206
210
|
lastError = err;
|
|
207
211
|
await sleep(err.retryAfter ? err.retryAfter * 1e3 : Math.min(1e3 * Math.pow(2, attempt), 1e4));
|
|
208
212
|
continue;
|
|
@@ -227,6 +231,7 @@ var HttpClient = class {
|
|
|
227
231
|
details: isRecord(responseError.data) ? responseError.data : void 0
|
|
228
232
|
});
|
|
229
233
|
if (err.isRetryable && attempt < this.maxRetries) {
|
|
234
|
+
if (err.details?.retry_strategy === "same_run_recovery") throw err;
|
|
230
235
|
lastError = err;
|
|
231
236
|
await sleep(err.retryAfter ? err.retryAfter * 1e3 : Math.min(1e3 * Math.pow(2, attempt), 1e4));
|
|
232
237
|
continue;
|
|
@@ -235,7 +240,10 @@ var HttpClient = class {
|
|
|
235
240
|
}
|
|
236
241
|
return unwrapMcpResponse(data);
|
|
237
242
|
} catch (e) {
|
|
238
|
-
if (e instanceof SignalizError
|
|
243
|
+
if (e instanceof SignalizError) {
|
|
244
|
+
if (e.details?.retry_strategy === "same_run_recovery") throw e;
|
|
245
|
+
if (!e.isRetryable) throw e;
|
|
246
|
+
}
|
|
239
247
|
if (e.name === "AbortError") {
|
|
240
248
|
lastError = new SignalizError({
|
|
241
249
|
code: "TIMEOUT",
|
|
@@ -346,15 +354,25 @@ function unwrapMcpPayload(payload) {
|
|
|
346
354
|
return unwrapMcpPayload(payload.result);
|
|
347
355
|
}
|
|
348
356
|
if (payload.ok === false) {
|
|
357
|
+
if (isRecord(payload.result) && (payload.result.success === false || payload.result.ok === false)) {
|
|
358
|
+
return unwrapMcpPayload(payload.result);
|
|
359
|
+
}
|
|
349
360
|
const first = firstPayloadError(payload);
|
|
350
|
-
const
|
|
361
|
+
const firstDetails = isRecord(first.details) ? first.details : {};
|
|
362
|
+
const code = firstString(
|
|
363
|
+
firstDetails.error_code,
|
|
364
|
+
firstDetails.legacy_error_code,
|
|
365
|
+
first.code,
|
|
366
|
+
payload.error_code,
|
|
367
|
+
payload.code
|
|
368
|
+
) || (payload.approval_required ? "APPROVAL_REQUIRED" : "MCP_ERROR");
|
|
351
369
|
throw new SignalizError({
|
|
352
370
|
code,
|
|
353
371
|
message: firstString(first.message, payload.message, payload.summary, payload.error) || "MCP request failed",
|
|
354
372
|
errorType: mapErrorTypeFromCode(code),
|
|
355
373
|
details: {
|
|
356
374
|
...payload,
|
|
357
|
-
...
|
|
375
|
+
...firstDetails
|
|
358
376
|
}
|
|
359
377
|
});
|
|
360
378
|
}
|
|
@@ -363,14 +381,20 @@ function unwrapMcpPayload(payload) {
|
|
|
363
381
|
}
|
|
364
382
|
if (payload.success === false) {
|
|
365
383
|
const first = firstPayloadError(payload);
|
|
366
|
-
const
|
|
384
|
+
const firstDetails = isRecord(first.details) ? first.details : {};
|
|
385
|
+
const code = firstString(
|
|
386
|
+
firstDetails.error_code,
|
|
387
|
+
firstDetails.legacy_error_code,
|
|
388
|
+
first.code,
|
|
389
|
+
payload.error_code
|
|
390
|
+
) || (payload.approval_required ? "APPROVAL_REQUIRED" : "MCP_ERROR");
|
|
367
391
|
throw new SignalizError({
|
|
368
392
|
code,
|
|
369
393
|
message: firstString(first.message, payload.message, payload.summary) || "MCP request failed",
|
|
370
394
|
errorType: mapErrorTypeFromCode(code),
|
|
371
395
|
details: {
|
|
372
396
|
...payload,
|
|
373
|
-
...
|
|
397
|
+
...firstDetails
|
|
374
398
|
}
|
|
375
399
|
});
|
|
376
400
|
}
|
|
@@ -560,6 +584,31 @@ function assertLargeCoreProductInputBounds(path, body) {
|
|
|
560
584
|
);
|
|
561
585
|
}
|
|
562
586
|
|
|
587
|
+
// ../../supabase/functions/_shared/find-email-identity.ts
|
|
588
|
+
var LINKEDIN_PERSON_PROFILE_URL_PATTERN = "^[hH][tT][tT][pP][sS]://(?:[A-Za-z0-9-]+\\.)*[lL][iI][nN][kK][eE][dD][iI][nN]\\.[cC][oO][mM]/[iI][nN]/[^/?#]+/?(?:[?#].*)?$";
|
|
589
|
+
var LINKEDIN_PERSON_PROFILE_URL_REGEX = new RegExp(LINKEDIN_PERSON_PROFILE_URL_PATTERN);
|
|
590
|
+
function nonEmptyText(value) {
|
|
591
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
592
|
+
}
|
|
593
|
+
function isLinkedInPersonProfileUrl(value) {
|
|
594
|
+
if (!nonEmptyText(value)) return false;
|
|
595
|
+
const normalized = String(value).trim();
|
|
596
|
+
if (!LINKEDIN_PERSON_PROFILE_URL_REGEX.test(normalized)) return false;
|
|
597
|
+
try {
|
|
598
|
+
const url = new URL(normalized);
|
|
599
|
+
const hostname = url.hostname.toLowerCase();
|
|
600
|
+
return url.protocol === "https:" && !url.username && !url.password && !url.port && (hostname === "linkedin.com" || hostname.endsWith(".linkedin.com")) && /^\/in\/[^/]+\/?$/i.test(url.pathname);
|
|
601
|
+
} catch {
|
|
602
|
+
return false;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
function hasFindEmailIdentity(input) {
|
|
606
|
+
if (isLinkedInPersonProfileUrl(input.linkedin_url)) return true;
|
|
607
|
+
const hasName = nonEmptyText(input.full_name) || nonEmptyText(input.first_name) && nonEmptyText(input.last_name);
|
|
608
|
+
return hasName && nonEmptyText(input.company_domain);
|
|
609
|
+
}
|
|
610
|
+
var FIND_EMAIL_IDENTITY_REQUIREMENT = "Provide an HTTPS LinkedIn person profile URL (/in/<slug>), or provide company_domain with full_name or first_name and last_name.";
|
|
611
|
+
|
|
563
612
|
// src/index.ts
|
|
564
613
|
var MAX_ROW_RATE_LIMIT_RETRIES = 2;
|
|
565
614
|
var Signaliz = class {
|
|
@@ -567,22 +616,28 @@ var Signaliz = class {
|
|
|
567
616
|
this.client = new HttpClient(config);
|
|
568
617
|
}
|
|
569
618
|
async findEmail(params) {
|
|
570
|
-
const
|
|
619
|
+
const request = findEmailRequestBody(params);
|
|
620
|
+
assertFindEmailRequestIdentity(request);
|
|
621
|
+
const data = await this.client.post("api/v1/find-email", request);
|
|
571
622
|
return isCoreProductDryRun(data) ? normalizeCoreProductDryRunResult(data) : normalizeFindEmailResult(data);
|
|
572
623
|
}
|
|
573
624
|
async findEmails(params, options) {
|
|
574
625
|
validateBatchSize(params);
|
|
626
|
+
const requests = params.map(findEmailRequestBody);
|
|
627
|
+
if (!requests.some(hasFindEmailRequestIdentity)) {
|
|
628
|
+
throw new TypeError(`Find Email batch must include at least one valid identity. ${FIND_EMAIL_IDENTITY_REQUIREMENT}`);
|
|
629
|
+
}
|
|
575
630
|
if (options?.dryRun === true) {
|
|
576
631
|
return this.runCoreProductDryRun(
|
|
577
632
|
"api/v1/find-email",
|
|
578
|
-
|
|
633
|
+
requests,
|
|
579
634
|
options.idempotencyKey
|
|
580
635
|
);
|
|
581
636
|
}
|
|
582
637
|
const startedAt = Date.now();
|
|
583
638
|
const round = await this.runCoreBatchRound(
|
|
584
639
|
"api/v1/find-email",
|
|
585
|
-
|
|
640
|
+
requests.map((request, index) => ({ index, request })),
|
|
586
641
|
options
|
|
587
642
|
);
|
|
588
643
|
return finalizeCoreBatch(
|
|
@@ -1408,6 +1463,8 @@ function batchItemFailure(index, error, raw) {
|
|
|
1408
1463
|
const retryStrategy = raw?.retry_strategy ?? raw?.retryStrategy;
|
|
1409
1464
|
const creditsUsed = raw?.credits_used ?? raw?.creditsUsed;
|
|
1410
1465
|
const creditsCharged = raw?.credits_charged ?? raw?.creditsCharged;
|
|
1466
|
+
const liveProviderCalled = raw?.live_provider_called ?? raw?.liveProviderCalled;
|
|
1467
|
+
const estimatedExternalCostUsd = raw?.estimated_external_cost_usd ?? raw?.estimatedExternalCostUsd;
|
|
1411
1468
|
const runId = [raw?.run_id, raw?.runId, raw?.signal_run_id, raw?.signalRunId].find((value) => typeof value === "string" && value.trim());
|
|
1412
1469
|
const verificationRunId = raw?.verification_run_id ?? raw?.verificationRunId;
|
|
1413
1470
|
const jobId = raw?.job_id ?? raw?.jobId;
|
|
@@ -1419,13 +1476,18 @@ function batchItemFailure(index, error, raw) {
|
|
|
1419
1476
|
...errorCode ? { errorCode } : {},
|
|
1420
1477
|
...typeof retryEligible === "boolean" ? { retryEligible } : {},
|
|
1421
1478
|
...Number.isFinite(retryAfterSeconds2) && retryAfterSeconds2 >= 0 ? { retryAfterSeconds: retryAfterSeconds2 } : {},
|
|
1422
|
-
...
|
|
1479
|
+
...["new_idempotency_key", "same_run_recovery"].includes(String(retryStrategy)) ? { retryStrategy } : {},
|
|
1423
1480
|
...creditsUsed === 0 ? { creditsUsed: 0 } : {},
|
|
1424
1481
|
...creditsCharged === 0 ? { creditsCharged: 0 } : {},
|
|
1482
|
+
...liveProviderCalled === false ? { liveProviderCalled: false } : {},
|
|
1483
|
+
...estimatedExternalCostUsd === 0 ? { estimatedExternalCostUsd: 0 } : {},
|
|
1425
1484
|
...typeof runId === "string" && runId.trim() ? { runId: runId.trim() } : {},
|
|
1426
1485
|
...typeof verificationRunId === "string" && verificationRunId.trim() ? { verificationRunId: verificationRunId.trim() } : {},
|
|
1427
1486
|
...typeof jobId === "string" && jobId.trim() ? { jobId: jobId.trim() } : {},
|
|
1428
|
-
...typeof suggestedAction === "string" && suggestedAction.trim() ? { suggestedAction: suggestedAction.trim() } : {}
|
|
1487
|
+
...typeof suggestedAction === "string" && suggestedAction.trim() ? { suggestedAction: suggestedAction.trim() } : {},
|
|
1488
|
+
...raw?.do_not_auto_resubmit === true ? { doNotAutoResubmit: true } : {},
|
|
1489
|
+
...raw?.recovery_mode === "same_run" ? { recoveryMode: "same_run" } : {},
|
|
1490
|
+
...["pending", "completed"].includes(String(raw?.recovery_status)) ? { recoveryStatus: raw?.recovery_status } : {}
|
|
1429
1491
|
};
|
|
1430
1492
|
}
|
|
1431
1493
|
function recoverableJobRowFailed(row) {
|
|
@@ -1488,6 +1550,14 @@ function findEmailRequestBody(params) {
|
|
|
1488
1550
|
idempotency_key: params.idempotencyKey
|
|
1489
1551
|
});
|
|
1490
1552
|
}
|
|
1553
|
+
function hasFindEmailRequestIdentity(request) {
|
|
1554
|
+
return typeof request.run_id === "string" && request.run_id.trim().length > 0 || hasFindEmailIdentity(request);
|
|
1555
|
+
}
|
|
1556
|
+
function assertFindEmailRequestIdentity(request) {
|
|
1557
|
+
if (!hasFindEmailRequestIdentity(request)) {
|
|
1558
|
+
throw new TypeError(`Find Email requires a valid identity. ${FIND_EMAIL_IDENTITY_REQUIREMENT}`);
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1491
1561
|
function verifyEmailBatchRequestBody(input, options) {
|
|
1492
1562
|
if (typeof input === "string") {
|
|
1493
1563
|
return compact({ email: input, skip_cache: options?.skipCache });
|
|
@@ -1566,6 +1636,7 @@ function normalizeFindEmailResult(data) {
|
|
|
1566
1636
|
verificationObservedAt: typeof data.verification_observed_at === "string" ? data.verification_observed_at : void 0,
|
|
1567
1637
|
failureReason: data.failure_reason ?? (failed || !found ? "no_verified_email_found" : "none"),
|
|
1568
1638
|
creditsUsed: data.credits_used ?? billingMetadata?.credits_used,
|
|
1639
|
+
creditsCharged: data.credits_charged ?? billingMetadata?.credits_charged,
|
|
1569
1640
|
estimatedExternalCostUsd: data.estimated_external_cost_usd ?? billingMetadata?.estimated_external_cost_usd,
|
|
1570
1641
|
billingMetadata,
|
|
1571
1642
|
historicalBillingMetadata: data.historical_billing_metadata,
|
|
@@ -1584,6 +1655,11 @@ function normalizeFindEmailResult(data) {
|
|
|
1584
1655
|
runId: data.run_id,
|
|
1585
1656
|
nextPollAfterSeconds: data.next_poll_after_seconds,
|
|
1586
1657
|
suggestedAction: data.suggested_action,
|
|
1658
|
+
retryEligible: data.retry_eligible,
|
|
1659
|
+
retryStrategy: ["new_idempotency_key", "same_run_recovery"].includes(data.retry_strategy) ? data.retry_strategy : void 0,
|
|
1660
|
+
doNotAutoResubmit: data.do_not_auto_resubmit === true,
|
|
1661
|
+
recoveryMode: data.recovery_mode === "same_run" ? "same_run" : void 0,
|
|
1662
|
+
recoveryStatus: ["pending", "completed"].includes(String(data.recovery_status)) ? data.recovery_status : void 0,
|
|
1587
1663
|
cachePublicationStatus: data.cache_publication_status,
|
|
1588
1664
|
cachePublicationRetryEligible: data.cache_publication_retry_eligible,
|
|
1589
1665
|
raw: data
|
|
@@ -1911,6 +1987,16 @@ function normalizeSignalDiscoverySignal(value) {
|
|
|
1911
1987
|
if (!companyName || !companyDomain) {
|
|
1912
1988
|
throw new Error("Signals Everything response violated the company attribution contract.");
|
|
1913
1989
|
}
|
|
1990
|
+
const eventDate = String(signal.event_date ?? signal.date ?? signal.signal_date ?? "").trim();
|
|
1991
|
+
const sourceUrl = String(signal.source_url ?? signal.url ?? "").trim();
|
|
1992
|
+
const evidence = Array.isArray(signal.evidence) ? signal.evidence.map((item) => ({
|
|
1993
|
+
url: String(item?.url ?? "").trim(),
|
|
1994
|
+
publishedAt: String(item?.published_at ?? item?.publishedAt ?? "").trim(),
|
|
1995
|
+
source: String(item?.source ?? "").trim()
|
|
1996
|
+
})).filter((item) => Boolean(item.url)) : [];
|
|
1997
|
+
if (!eventDate || !sourceUrl || !evidence.some((item) => item.url === sourceUrl && item.publishedAt === eventDate)) {
|
|
1998
|
+
throw new Error("Signals Everything response violated the dated-evidence and source-URL contract.");
|
|
1999
|
+
}
|
|
1914
2000
|
return {
|
|
1915
2001
|
id: signal.id,
|
|
1916
2002
|
company: {
|
|
@@ -1921,16 +2007,12 @@ function normalizeSignalDiscoverySignal(value) {
|
|
|
1921
2007
|
title: signal.title ?? "",
|
|
1922
2008
|
type: signal.type ?? signal.signal_type ?? "unknown",
|
|
1923
2009
|
summary: signal.summary ?? signal.content ?? signal.description ?? "",
|
|
1924
|
-
eventDate
|
|
1925
|
-
evidence
|
|
1926
|
-
url: String(item?.url ?? ""),
|
|
1927
|
-
publishedAt: String(item?.published_at ?? item?.publishedAt ?? ""),
|
|
1928
|
-
source: String(item?.source ?? "")
|
|
1929
|
-
})).filter((item) => Boolean(item.url)) : [],
|
|
2010
|
+
eventDate,
|
|
2011
|
+
evidence,
|
|
1930
2012
|
content: signal.summary ?? signal.content ?? signal.description ?? "",
|
|
1931
2013
|
date: signal.event_date ?? signal.date ?? signal.signal_date ?? null,
|
|
1932
2014
|
detectedAt: signal.event_date ?? signal.detected_at ?? null,
|
|
1933
|
-
sourceUrl
|
|
2015
|
+
sourceUrl,
|
|
1934
2016
|
sourceType: signal.source_type ?? null,
|
|
1935
2017
|
confidence: signal.confidence ?? signal.confidence_score ?? null,
|
|
1936
2018
|
classification: signal.signal_classification ?? signal.classification ?? null,
|
package/dist/index.d.mts
CHANGED
|
@@ -56,11 +56,15 @@ interface BatchItemResult<T> {
|
|
|
56
56
|
/** Server-provided delay before retrying the failed row. */
|
|
57
57
|
retryAfterSeconds?: number;
|
|
58
58
|
/** Explicit recovery strategy. A fresh key can repeat provider work and is never automatic. */
|
|
59
|
-
retryStrategy?: 'new_idempotency_key';
|
|
59
|
+
retryStrategy?: 'new_idempotency_key' | 'same_run_recovery';
|
|
60
60
|
/** Present only when the server proves the failed row consumed zero Signaliz credits. */
|
|
61
61
|
creditsUsed?: 0;
|
|
62
62
|
/** Present only when the server proves the failed row charged zero Signaliz credits. */
|
|
63
63
|
creditsCharged?: 0;
|
|
64
|
+
/** Present only when the server proves no live provider was called for the failed row. */
|
|
65
|
+
liveProviderCalled?: false;
|
|
66
|
+
/** Present only when the server proves the failed row had no external provider cost. */
|
|
67
|
+
estimatedExternalCostUsd?: 0;
|
|
64
68
|
/** Existing provider run that can be resumed without dispatching new work. */
|
|
65
69
|
runId?: string;
|
|
66
70
|
/** Existing Verify Email run that can be resumed without dispatching new work. */
|
|
@@ -69,6 +73,9 @@ interface BatchItemResult<T> {
|
|
|
69
73
|
jobId?: string;
|
|
70
74
|
/** Machine-readable recovery action returned by Signaliz. */
|
|
71
75
|
suggestedAction?: string;
|
|
76
|
+
doNotAutoResubmit?: boolean;
|
|
77
|
+
recoveryMode?: 'same_run';
|
|
78
|
+
recoveryStatus?: 'pending' | 'completed';
|
|
72
79
|
cachePublicationStatus?: 'completed' | 'pending' | 'pending_safe_retry' | 'superseded_by_newer_verdict';
|
|
73
80
|
cachePublicationRetryEligible?: boolean;
|
|
74
81
|
/** Zero-based input index containing the full result for this exact duplicate. */
|
|
@@ -111,10 +118,6 @@ interface CoreProductDryRunResult {
|
|
|
111
118
|
raw: Record<string, unknown>;
|
|
112
119
|
}
|
|
113
120
|
interface FindEmailCommonParams {
|
|
114
|
-
fullName?: string;
|
|
115
|
-
firstName?: string;
|
|
116
|
-
lastName?: string;
|
|
117
|
-
linkedinUrl?: string;
|
|
118
121
|
companyName?: string;
|
|
119
122
|
/** Bypass cached email and verification data for a fresh-provider run. */
|
|
120
123
|
skipCache?: boolean;
|
|
@@ -124,13 +127,35 @@ interface FindEmailCommonParams {
|
|
|
124
127
|
idempotencyKey?: string;
|
|
125
128
|
}
|
|
126
129
|
type FindEmailParams = FindEmailCommonParams & ({
|
|
130
|
+
/** Start a new lookup using only the contact's LinkedIn profile. */
|
|
131
|
+
linkedinUrl: string;
|
|
132
|
+
companyDomain?: string;
|
|
133
|
+
fullName?: string;
|
|
134
|
+
firstName?: string;
|
|
135
|
+
lastName?: string;
|
|
136
|
+
/** Omit for a new lookup. */
|
|
137
|
+
runId?: undefined;
|
|
138
|
+
} | ({
|
|
127
139
|
companyDomain: string;
|
|
140
|
+
linkedinUrl?: string;
|
|
128
141
|
/** Omit for a new lookup. */
|
|
129
142
|
runId?: undefined;
|
|
143
|
+
} & ({
|
|
144
|
+
fullName: string;
|
|
145
|
+
firstName?: string;
|
|
146
|
+
lastName?: string;
|
|
130
147
|
} | {
|
|
148
|
+
fullName?: string;
|
|
149
|
+
firstName: string;
|
|
150
|
+
lastName: string;
|
|
151
|
+
})) | {
|
|
131
152
|
/** Resume one existing Find Email run without dispatching a new finder. */
|
|
132
153
|
runId: string;
|
|
133
154
|
companyDomain?: string;
|
|
155
|
+
linkedinUrl?: string;
|
|
156
|
+
fullName?: string;
|
|
157
|
+
firstName?: string;
|
|
158
|
+
lastName?: string;
|
|
134
159
|
});
|
|
135
160
|
interface FindEmailResult {
|
|
136
161
|
success: boolean;
|
|
@@ -156,6 +181,7 @@ interface FindEmailResult {
|
|
|
156
181
|
verificationObservedAt?: string;
|
|
157
182
|
failureReason: string;
|
|
158
183
|
creditsUsed?: number;
|
|
184
|
+
creditsCharged?: number;
|
|
159
185
|
estimatedExternalCostUsd?: number;
|
|
160
186
|
billingMetadata?: Record<string, unknown>;
|
|
161
187
|
/** Original provider-work billing receipt when this request only recovered a completed run. */
|
|
@@ -179,6 +205,12 @@ interface FindEmailResult {
|
|
|
179
205
|
runId?: string;
|
|
180
206
|
nextPollAfterSeconds?: number;
|
|
181
207
|
suggestedAction?: string;
|
|
208
|
+
/** True only for same-run recovery, or a fresh idempotency key with explicit zero-spend proof; never retry automatically. */
|
|
209
|
+
retryEligible?: boolean;
|
|
210
|
+
retryStrategy?: 'new_idempotency_key' | 'same_run_recovery';
|
|
211
|
+
doNotAutoResubmit?: boolean;
|
|
212
|
+
recoveryMode?: 'same_run';
|
|
213
|
+
recoveryStatus?: 'pending' | 'completed';
|
|
182
214
|
cachePublicationStatus?: 'completed' | 'pending' | 'pending_safe_retry' | 'superseded_by_newer_verdict';
|
|
183
215
|
cachePublicationRetryEligible?: boolean;
|
|
184
216
|
raw: Record<string, unknown>;
|
|
@@ -373,7 +405,7 @@ interface SignalDiscoverySignal {
|
|
|
373
405
|
title: string;
|
|
374
406
|
type: string;
|
|
375
407
|
summary: string;
|
|
376
|
-
eventDate
|
|
408
|
+
eventDate: string;
|
|
377
409
|
evidence: Array<{
|
|
378
410
|
url: string;
|
|
379
411
|
publishedAt: string;
|
|
@@ -384,7 +416,7 @@ interface SignalDiscoverySignal {
|
|
|
384
416
|
/** Compatibility alias for eventDate. */
|
|
385
417
|
date?: string | null;
|
|
386
418
|
detectedAt?: string | null;
|
|
387
|
-
sourceUrl
|
|
419
|
+
sourceUrl: string;
|
|
388
420
|
sourceType?: string | null;
|
|
389
421
|
confidence?: number | null;
|
|
390
422
|
classification?: Record<string, unknown> | string | null;
|
package/dist/index.d.ts
CHANGED
|
@@ -56,11 +56,15 @@ interface BatchItemResult<T> {
|
|
|
56
56
|
/** Server-provided delay before retrying the failed row. */
|
|
57
57
|
retryAfterSeconds?: number;
|
|
58
58
|
/** Explicit recovery strategy. A fresh key can repeat provider work and is never automatic. */
|
|
59
|
-
retryStrategy?: 'new_idempotency_key';
|
|
59
|
+
retryStrategy?: 'new_idempotency_key' | 'same_run_recovery';
|
|
60
60
|
/** Present only when the server proves the failed row consumed zero Signaliz credits. */
|
|
61
61
|
creditsUsed?: 0;
|
|
62
62
|
/** Present only when the server proves the failed row charged zero Signaliz credits. */
|
|
63
63
|
creditsCharged?: 0;
|
|
64
|
+
/** Present only when the server proves no live provider was called for the failed row. */
|
|
65
|
+
liveProviderCalled?: false;
|
|
66
|
+
/** Present only when the server proves the failed row had no external provider cost. */
|
|
67
|
+
estimatedExternalCostUsd?: 0;
|
|
64
68
|
/** Existing provider run that can be resumed without dispatching new work. */
|
|
65
69
|
runId?: string;
|
|
66
70
|
/** Existing Verify Email run that can be resumed without dispatching new work. */
|
|
@@ -69,6 +73,9 @@ interface BatchItemResult<T> {
|
|
|
69
73
|
jobId?: string;
|
|
70
74
|
/** Machine-readable recovery action returned by Signaliz. */
|
|
71
75
|
suggestedAction?: string;
|
|
76
|
+
doNotAutoResubmit?: boolean;
|
|
77
|
+
recoveryMode?: 'same_run';
|
|
78
|
+
recoveryStatus?: 'pending' | 'completed';
|
|
72
79
|
cachePublicationStatus?: 'completed' | 'pending' | 'pending_safe_retry' | 'superseded_by_newer_verdict';
|
|
73
80
|
cachePublicationRetryEligible?: boolean;
|
|
74
81
|
/** Zero-based input index containing the full result for this exact duplicate. */
|
|
@@ -111,10 +118,6 @@ interface CoreProductDryRunResult {
|
|
|
111
118
|
raw: Record<string, unknown>;
|
|
112
119
|
}
|
|
113
120
|
interface FindEmailCommonParams {
|
|
114
|
-
fullName?: string;
|
|
115
|
-
firstName?: string;
|
|
116
|
-
lastName?: string;
|
|
117
|
-
linkedinUrl?: string;
|
|
118
121
|
companyName?: string;
|
|
119
122
|
/** Bypass cached email and verification data for a fresh-provider run. */
|
|
120
123
|
skipCache?: boolean;
|
|
@@ -124,13 +127,35 @@ interface FindEmailCommonParams {
|
|
|
124
127
|
idempotencyKey?: string;
|
|
125
128
|
}
|
|
126
129
|
type FindEmailParams = FindEmailCommonParams & ({
|
|
130
|
+
/** Start a new lookup using only the contact's LinkedIn profile. */
|
|
131
|
+
linkedinUrl: string;
|
|
132
|
+
companyDomain?: string;
|
|
133
|
+
fullName?: string;
|
|
134
|
+
firstName?: string;
|
|
135
|
+
lastName?: string;
|
|
136
|
+
/** Omit for a new lookup. */
|
|
137
|
+
runId?: undefined;
|
|
138
|
+
} | ({
|
|
127
139
|
companyDomain: string;
|
|
140
|
+
linkedinUrl?: string;
|
|
128
141
|
/** Omit for a new lookup. */
|
|
129
142
|
runId?: undefined;
|
|
143
|
+
} & ({
|
|
144
|
+
fullName: string;
|
|
145
|
+
firstName?: string;
|
|
146
|
+
lastName?: string;
|
|
130
147
|
} | {
|
|
148
|
+
fullName?: string;
|
|
149
|
+
firstName: string;
|
|
150
|
+
lastName: string;
|
|
151
|
+
})) | {
|
|
131
152
|
/** Resume one existing Find Email run without dispatching a new finder. */
|
|
132
153
|
runId: string;
|
|
133
154
|
companyDomain?: string;
|
|
155
|
+
linkedinUrl?: string;
|
|
156
|
+
fullName?: string;
|
|
157
|
+
firstName?: string;
|
|
158
|
+
lastName?: string;
|
|
134
159
|
});
|
|
135
160
|
interface FindEmailResult {
|
|
136
161
|
success: boolean;
|
|
@@ -156,6 +181,7 @@ interface FindEmailResult {
|
|
|
156
181
|
verificationObservedAt?: string;
|
|
157
182
|
failureReason: string;
|
|
158
183
|
creditsUsed?: number;
|
|
184
|
+
creditsCharged?: number;
|
|
159
185
|
estimatedExternalCostUsd?: number;
|
|
160
186
|
billingMetadata?: Record<string, unknown>;
|
|
161
187
|
/** Original provider-work billing receipt when this request only recovered a completed run. */
|
|
@@ -179,6 +205,12 @@ interface FindEmailResult {
|
|
|
179
205
|
runId?: string;
|
|
180
206
|
nextPollAfterSeconds?: number;
|
|
181
207
|
suggestedAction?: string;
|
|
208
|
+
/** True only for same-run recovery, or a fresh idempotency key with explicit zero-spend proof; never retry automatically. */
|
|
209
|
+
retryEligible?: boolean;
|
|
210
|
+
retryStrategy?: 'new_idempotency_key' | 'same_run_recovery';
|
|
211
|
+
doNotAutoResubmit?: boolean;
|
|
212
|
+
recoveryMode?: 'same_run';
|
|
213
|
+
recoveryStatus?: 'pending' | 'completed';
|
|
182
214
|
cachePublicationStatus?: 'completed' | 'pending' | 'pending_safe_retry' | 'superseded_by_newer_verdict';
|
|
183
215
|
cachePublicationRetryEligible?: boolean;
|
|
184
216
|
raw: Record<string, unknown>;
|
|
@@ -373,7 +405,7 @@ interface SignalDiscoverySignal {
|
|
|
373
405
|
title: string;
|
|
374
406
|
type: string;
|
|
375
407
|
summary: string;
|
|
376
|
-
eventDate
|
|
408
|
+
eventDate: string;
|
|
377
409
|
evidence: Array<{
|
|
378
410
|
url: string;
|
|
379
411
|
publishedAt: string;
|
|
@@ -384,7 +416,7 @@ interface SignalDiscoverySignal {
|
|
|
384
416
|
/** Compatibility alias for eventDate. */
|
|
385
417
|
date?: string | null;
|
|
386
418
|
detectedAt?: string | null;
|
|
387
|
-
sourceUrl
|
|
419
|
+
sourceUrl: string;
|
|
388
420
|
sourceType?: string | null;
|
|
389
421
|
confidence?: number | null;
|
|
390
422
|
classification?: Record<string, unknown> | string | null;
|
package/dist/index.js
CHANGED
|
@@ -74,6 +74,8 @@ function publicRetryDetails(body) {
|
|
|
74
74
|
...body?.retry_strategy !== void 0 ? { retry_strategy: body.retry_strategy } : {},
|
|
75
75
|
...body?.credits_used !== void 0 ? { credits_used: body.credits_used } : {},
|
|
76
76
|
...body?.credits_charged !== void 0 ? { credits_charged: body.credits_charged } : {},
|
|
77
|
+
...body?.live_provider_called !== void 0 ? { live_provider_called: body.live_provider_called } : {},
|
|
78
|
+
...body?.estimated_external_cost_usd !== void 0 ? { estimated_external_cost_usd: body.estimated_external_cost_usd } : {},
|
|
77
79
|
...body?.job_id !== void 0 ? { job_id: body.job_id } : {},
|
|
78
80
|
...body?.idempotency_key !== void 0 ? { idempotency_key: body.idempotency_key } : {},
|
|
79
81
|
...body?.verification_run_id !== void 0 ? { verification_run_id: body.verification_run_id } : {},
|
|
@@ -158,7 +160,8 @@ var HttpClient = class {
|
|
|
158
160
|
const err = parseError(res.status, errBody);
|
|
159
161
|
if (err.isRetryable && attempt < this.maxRetries) {
|
|
160
162
|
const retryWithNewKey = err.details?.retry_strategy === "new_idempotency_key" && err.details?.credits_used === 0 && err.details?.credits_charged === 0;
|
|
161
|
-
|
|
163
|
+
const recoverSameRun = err.details?.retry_strategy === "same_run_recovery";
|
|
164
|
+
if (retryWithNewKey || recoverSameRun) throw err;
|
|
162
165
|
const wait = err.retryAfter !== void 0 ? err.retryAfter * 1e3 : Math.min(1e3 * Math.pow(2, attempt), 1e4);
|
|
163
166
|
await sleep(wait);
|
|
164
167
|
lastError = err;
|
|
@@ -230,6 +233,7 @@ var HttpClient = class {
|
|
|
230
233
|
if (!res.ok) {
|
|
231
234
|
const err = parseError(res.status, data ?? { message: text });
|
|
232
235
|
if (err.isRetryable && attempt < this.maxRetries) {
|
|
236
|
+
if (err.details?.retry_strategy === "same_run_recovery") throw err;
|
|
233
237
|
lastError = err;
|
|
234
238
|
await sleep(err.retryAfter ? err.retryAfter * 1e3 : Math.min(1e3 * Math.pow(2, attempt), 1e4));
|
|
235
239
|
continue;
|
|
@@ -254,6 +258,7 @@ var HttpClient = class {
|
|
|
254
258
|
details: isRecord(responseError.data) ? responseError.data : void 0
|
|
255
259
|
});
|
|
256
260
|
if (err.isRetryable && attempt < this.maxRetries) {
|
|
261
|
+
if (err.details?.retry_strategy === "same_run_recovery") throw err;
|
|
257
262
|
lastError = err;
|
|
258
263
|
await sleep(err.retryAfter ? err.retryAfter * 1e3 : Math.min(1e3 * Math.pow(2, attempt), 1e4));
|
|
259
264
|
continue;
|
|
@@ -262,7 +267,10 @@ var HttpClient = class {
|
|
|
262
267
|
}
|
|
263
268
|
return unwrapMcpResponse(data);
|
|
264
269
|
} catch (e) {
|
|
265
|
-
if (e instanceof SignalizError
|
|
270
|
+
if (e instanceof SignalizError) {
|
|
271
|
+
if (e.details?.retry_strategy === "same_run_recovery") throw e;
|
|
272
|
+
if (!e.isRetryable) throw e;
|
|
273
|
+
}
|
|
266
274
|
if (e.name === "AbortError") {
|
|
267
275
|
lastError = new SignalizError({
|
|
268
276
|
code: "TIMEOUT",
|
|
@@ -373,15 +381,25 @@ function unwrapMcpPayload(payload) {
|
|
|
373
381
|
return unwrapMcpPayload(payload.result);
|
|
374
382
|
}
|
|
375
383
|
if (payload.ok === false) {
|
|
384
|
+
if (isRecord(payload.result) && (payload.result.success === false || payload.result.ok === false)) {
|
|
385
|
+
return unwrapMcpPayload(payload.result);
|
|
386
|
+
}
|
|
376
387
|
const first = firstPayloadError(payload);
|
|
377
|
-
const
|
|
388
|
+
const firstDetails = isRecord(first.details) ? first.details : {};
|
|
389
|
+
const code = firstString(
|
|
390
|
+
firstDetails.error_code,
|
|
391
|
+
firstDetails.legacy_error_code,
|
|
392
|
+
first.code,
|
|
393
|
+
payload.error_code,
|
|
394
|
+
payload.code
|
|
395
|
+
) || (payload.approval_required ? "APPROVAL_REQUIRED" : "MCP_ERROR");
|
|
378
396
|
throw new SignalizError({
|
|
379
397
|
code,
|
|
380
398
|
message: firstString(first.message, payload.message, payload.summary, payload.error) || "MCP request failed",
|
|
381
399
|
errorType: mapErrorTypeFromCode(code),
|
|
382
400
|
details: {
|
|
383
401
|
...payload,
|
|
384
|
-
...
|
|
402
|
+
...firstDetails
|
|
385
403
|
}
|
|
386
404
|
});
|
|
387
405
|
}
|
|
@@ -390,14 +408,20 @@ function unwrapMcpPayload(payload) {
|
|
|
390
408
|
}
|
|
391
409
|
if (payload.success === false) {
|
|
392
410
|
const first = firstPayloadError(payload);
|
|
393
|
-
const
|
|
411
|
+
const firstDetails = isRecord(first.details) ? first.details : {};
|
|
412
|
+
const code = firstString(
|
|
413
|
+
firstDetails.error_code,
|
|
414
|
+
firstDetails.legacy_error_code,
|
|
415
|
+
first.code,
|
|
416
|
+
payload.error_code
|
|
417
|
+
) || (payload.approval_required ? "APPROVAL_REQUIRED" : "MCP_ERROR");
|
|
394
418
|
throw new SignalizError({
|
|
395
419
|
code,
|
|
396
420
|
message: firstString(first.message, payload.message, payload.summary) || "MCP request failed",
|
|
397
421
|
errorType: mapErrorTypeFromCode(code),
|
|
398
422
|
details: {
|
|
399
423
|
...payload,
|
|
400
|
-
...
|
|
424
|
+
...firstDetails
|
|
401
425
|
}
|
|
402
426
|
});
|
|
403
427
|
}
|
|
@@ -587,6 +611,31 @@ function assertLargeCoreProductInputBounds(path, body) {
|
|
|
587
611
|
);
|
|
588
612
|
}
|
|
589
613
|
|
|
614
|
+
// ../../supabase/functions/_shared/find-email-identity.ts
|
|
615
|
+
var LINKEDIN_PERSON_PROFILE_URL_PATTERN = "^[hH][tT][tT][pP][sS]://(?:[A-Za-z0-9-]+\\.)*[lL][iI][nN][kK][eE][dD][iI][nN]\\.[cC][oO][mM]/[iI][nN]/[^/?#]+/?(?:[?#].*)?$";
|
|
616
|
+
var LINKEDIN_PERSON_PROFILE_URL_REGEX = new RegExp(LINKEDIN_PERSON_PROFILE_URL_PATTERN);
|
|
617
|
+
function nonEmptyText(value) {
|
|
618
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
619
|
+
}
|
|
620
|
+
function isLinkedInPersonProfileUrl(value) {
|
|
621
|
+
if (!nonEmptyText(value)) return false;
|
|
622
|
+
const normalized = String(value).trim();
|
|
623
|
+
if (!LINKEDIN_PERSON_PROFILE_URL_REGEX.test(normalized)) return false;
|
|
624
|
+
try {
|
|
625
|
+
const url = new URL(normalized);
|
|
626
|
+
const hostname = url.hostname.toLowerCase();
|
|
627
|
+
return url.protocol === "https:" && !url.username && !url.password && !url.port && (hostname === "linkedin.com" || hostname.endsWith(".linkedin.com")) && /^\/in\/[^/]+\/?$/i.test(url.pathname);
|
|
628
|
+
} catch {
|
|
629
|
+
return false;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
function hasFindEmailIdentity(input) {
|
|
633
|
+
if (isLinkedInPersonProfileUrl(input.linkedin_url)) return true;
|
|
634
|
+
const hasName = nonEmptyText(input.full_name) || nonEmptyText(input.first_name) && nonEmptyText(input.last_name);
|
|
635
|
+
return hasName && nonEmptyText(input.company_domain);
|
|
636
|
+
}
|
|
637
|
+
var FIND_EMAIL_IDENTITY_REQUIREMENT = "Provide an HTTPS LinkedIn person profile URL (/in/<slug>), or provide company_domain with full_name or first_name and last_name.";
|
|
638
|
+
|
|
590
639
|
// src/index.ts
|
|
591
640
|
var MAX_ROW_RATE_LIMIT_RETRIES = 2;
|
|
592
641
|
var Signaliz = class {
|
|
@@ -594,22 +643,28 @@ var Signaliz = class {
|
|
|
594
643
|
this.client = new HttpClient(config);
|
|
595
644
|
}
|
|
596
645
|
async findEmail(params) {
|
|
597
|
-
const
|
|
646
|
+
const request = findEmailRequestBody(params);
|
|
647
|
+
assertFindEmailRequestIdentity(request);
|
|
648
|
+
const data = await this.client.post("api/v1/find-email", request);
|
|
598
649
|
return isCoreProductDryRun(data) ? normalizeCoreProductDryRunResult(data) : normalizeFindEmailResult(data);
|
|
599
650
|
}
|
|
600
651
|
async findEmails(params, options) {
|
|
601
652
|
validateBatchSize(params);
|
|
653
|
+
const requests = params.map(findEmailRequestBody);
|
|
654
|
+
if (!requests.some(hasFindEmailRequestIdentity)) {
|
|
655
|
+
throw new TypeError(`Find Email batch must include at least one valid identity. ${FIND_EMAIL_IDENTITY_REQUIREMENT}`);
|
|
656
|
+
}
|
|
602
657
|
if (options?.dryRun === true) {
|
|
603
658
|
return this.runCoreProductDryRun(
|
|
604
659
|
"api/v1/find-email",
|
|
605
|
-
|
|
660
|
+
requests,
|
|
606
661
|
options.idempotencyKey
|
|
607
662
|
);
|
|
608
663
|
}
|
|
609
664
|
const startedAt = Date.now();
|
|
610
665
|
const round = await this.runCoreBatchRound(
|
|
611
666
|
"api/v1/find-email",
|
|
612
|
-
|
|
667
|
+
requests.map((request, index) => ({ index, request })),
|
|
613
668
|
options
|
|
614
669
|
);
|
|
615
670
|
return finalizeCoreBatch(
|
|
@@ -1435,6 +1490,8 @@ function batchItemFailure(index, error, raw) {
|
|
|
1435
1490
|
const retryStrategy = raw?.retry_strategy ?? raw?.retryStrategy;
|
|
1436
1491
|
const creditsUsed = raw?.credits_used ?? raw?.creditsUsed;
|
|
1437
1492
|
const creditsCharged = raw?.credits_charged ?? raw?.creditsCharged;
|
|
1493
|
+
const liveProviderCalled = raw?.live_provider_called ?? raw?.liveProviderCalled;
|
|
1494
|
+
const estimatedExternalCostUsd = raw?.estimated_external_cost_usd ?? raw?.estimatedExternalCostUsd;
|
|
1438
1495
|
const runId = [raw?.run_id, raw?.runId, raw?.signal_run_id, raw?.signalRunId].find((value) => typeof value === "string" && value.trim());
|
|
1439
1496
|
const verificationRunId = raw?.verification_run_id ?? raw?.verificationRunId;
|
|
1440
1497
|
const jobId = raw?.job_id ?? raw?.jobId;
|
|
@@ -1446,13 +1503,18 @@ function batchItemFailure(index, error, raw) {
|
|
|
1446
1503
|
...errorCode ? { errorCode } : {},
|
|
1447
1504
|
...typeof retryEligible === "boolean" ? { retryEligible } : {},
|
|
1448
1505
|
...Number.isFinite(retryAfterSeconds2) && retryAfterSeconds2 >= 0 ? { retryAfterSeconds: retryAfterSeconds2 } : {},
|
|
1449
|
-
...
|
|
1506
|
+
...["new_idempotency_key", "same_run_recovery"].includes(String(retryStrategy)) ? { retryStrategy } : {},
|
|
1450
1507
|
...creditsUsed === 0 ? { creditsUsed: 0 } : {},
|
|
1451
1508
|
...creditsCharged === 0 ? { creditsCharged: 0 } : {},
|
|
1509
|
+
...liveProviderCalled === false ? { liveProviderCalled: false } : {},
|
|
1510
|
+
...estimatedExternalCostUsd === 0 ? { estimatedExternalCostUsd: 0 } : {},
|
|
1452
1511
|
...typeof runId === "string" && runId.trim() ? { runId: runId.trim() } : {},
|
|
1453
1512
|
...typeof verificationRunId === "string" && verificationRunId.trim() ? { verificationRunId: verificationRunId.trim() } : {},
|
|
1454
1513
|
...typeof jobId === "string" && jobId.trim() ? { jobId: jobId.trim() } : {},
|
|
1455
|
-
...typeof suggestedAction === "string" && suggestedAction.trim() ? { suggestedAction: suggestedAction.trim() } : {}
|
|
1514
|
+
...typeof suggestedAction === "string" && suggestedAction.trim() ? { suggestedAction: suggestedAction.trim() } : {},
|
|
1515
|
+
...raw?.do_not_auto_resubmit === true ? { doNotAutoResubmit: true } : {},
|
|
1516
|
+
...raw?.recovery_mode === "same_run" ? { recoveryMode: "same_run" } : {},
|
|
1517
|
+
...["pending", "completed"].includes(String(raw?.recovery_status)) ? { recoveryStatus: raw?.recovery_status } : {}
|
|
1456
1518
|
};
|
|
1457
1519
|
}
|
|
1458
1520
|
function recoverableJobRowFailed(row) {
|
|
@@ -1515,6 +1577,14 @@ function findEmailRequestBody(params) {
|
|
|
1515
1577
|
idempotency_key: params.idempotencyKey
|
|
1516
1578
|
});
|
|
1517
1579
|
}
|
|
1580
|
+
function hasFindEmailRequestIdentity(request) {
|
|
1581
|
+
return typeof request.run_id === "string" && request.run_id.trim().length > 0 || hasFindEmailIdentity(request);
|
|
1582
|
+
}
|
|
1583
|
+
function assertFindEmailRequestIdentity(request) {
|
|
1584
|
+
if (!hasFindEmailRequestIdentity(request)) {
|
|
1585
|
+
throw new TypeError(`Find Email requires a valid identity. ${FIND_EMAIL_IDENTITY_REQUIREMENT}`);
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1518
1588
|
function verifyEmailBatchRequestBody(input, options) {
|
|
1519
1589
|
if (typeof input === "string") {
|
|
1520
1590
|
return compact({ email: input, skip_cache: options?.skipCache });
|
|
@@ -1593,6 +1663,7 @@ function normalizeFindEmailResult(data) {
|
|
|
1593
1663
|
verificationObservedAt: typeof data.verification_observed_at === "string" ? data.verification_observed_at : void 0,
|
|
1594
1664
|
failureReason: data.failure_reason ?? (failed || !found ? "no_verified_email_found" : "none"),
|
|
1595
1665
|
creditsUsed: data.credits_used ?? billingMetadata?.credits_used,
|
|
1666
|
+
creditsCharged: data.credits_charged ?? billingMetadata?.credits_charged,
|
|
1596
1667
|
estimatedExternalCostUsd: data.estimated_external_cost_usd ?? billingMetadata?.estimated_external_cost_usd,
|
|
1597
1668
|
billingMetadata,
|
|
1598
1669
|
historicalBillingMetadata: data.historical_billing_metadata,
|
|
@@ -1611,6 +1682,11 @@ function normalizeFindEmailResult(data) {
|
|
|
1611
1682
|
runId: data.run_id,
|
|
1612
1683
|
nextPollAfterSeconds: data.next_poll_after_seconds,
|
|
1613
1684
|
suggestedAction: data.suggested_action,
|
|
1685
|
+
retryEligible: data.retry_eligible,
|
|
1686
|
+
retryStrategy: ["new_idempotency_key", "same_run_recovery"].includes(data.retry_strategy) ? data.retry_strategy : void 0,
|
|
1687
|
+
doNotAutoResubmit: data.do_not_auto_resubmit === true,
|
|
1688
|
+
recoveryMode: data.recovery_mode === "same_run" ? "same_run" : void 0,
|
|
1689
|
+
recoveryStatus: ["pending", "completed"].includes(String(data.recovery_status)) ? data.recovery_status : void 0,
|
|
1614
1690
|
cachePublicationStatus: data.cache_publication_status,
|
|
1615
1691
|
cachePublicationRetryEligible: data.cache_publication_retry_eligible,
|
|
1616
1692
|
raw: data
|
|
@@ -1938,6 +2014,16 @@ function normalizeSignalDiscoverySignal(value) {
|
|
|
1938
2014
|
if (!companyName || !companyDomain) {
|
|
1939
2015
|
throw new Error("Signals Everything response violated the company attribution contract.");
|
|
1940
2016
|
}
|
|
2017
|
+
const eventDate = String(signal.event_date ?? signal.date ?? signal.signal_date ?? "").trim();
|
|
2018
|
+
const sourceUrl = String(signal.source_url ?? signal.url ?? "").trim();
|
|
2019
|
+
const evidence = Array.isArray(signal.evidence) ? signal.evidence.map((item) => ({
|
|
2020
|
+
url: String(item?.url ?? "").trim(),
|
|
2021
|
+
publishedAt: String(item?.published_at ?? item?.publishedAt ?? "").trim(),
|
|
2022
|
+
source: String(item?.source ?? "").trim()
|
|
2023
|
+
})).filter((item) => Boolean(item.url)) : [];
|
|
2024
|
+
if (!eventDate || !sourceUrl || !evidence.some((item) => item.url === sourceUrl && item.publishedAt === eventDate)) {
|
|
2025
|
+
throw new Error("Signals Everything response violated the dated-evidence and source-URL contract.");
|
|
2026
|
+
}
|
|
1941
2027
|
return {
|
|
1942
2028
|
id: signal.id,
|
|
1943
2029
|
company: {
|
|
@@ -1948,16 +2034,12 @@ function normalizeSignalDiscoverySignal(value) {
|
|
|
1948
2034
|
title: signal.title ?? "",
|
|
1949
2035
|
type: signal.type ?? signal.signal_type ?? "unknown",
|
|
1950
2036
|
summary: signal.summary ?? signal.content ?? signal.description ?? "",
|
|
1951
|
-
eventDate
|
|
1952
|
-
evidence
|
|
1953
|
-
url: String(item?.url ?? ""),
|
|
1954
|
-
publishedAt: String(item?.published_at ?? item?.publishedAt ?? ""),
|
|
1955
|
-
source: String(item?.source ?? "")
|
|
1956
|
-
})).filter((item) => Boolean(item.url)) : [],
|
|
2037
|
+
eventDate,
|
|
2038
|
+
evidence,
|
|
1957
2039
|
content: signal.summary ?? signal.content ?? signal.description ?? "",
|
|
1958
2040
|
date: signal.event_date ?? signal.date ?? signal.signal_date ?? null,
|
|
1959
2041
|
detectedAt: signal.event_date ?? signal.detected_at ?? null,
|
|
1960
|
-
sourceUrl
|
|
2042
|
+
sourceUrl,
|
|
1961
2043
|
sourceType: signal.source_type ?? null,
|
|
1962
2044
|
confidence: signal.confidence ?? signal.confidence_score ?? null,
|
|
1963
2045
|
classification: signal.signal_classification ?? signal.classification ?? null,
|
package/dist/index.mjs
CHANGED
package/dist/mcp-config.js
CHANGED
|
@@ -78,6 +78,8 @@ function publicRetryDetails(body) {
|
|
|
78
78
|
...body?.retry_strategy !== void 0 ? { retry_strategy: body.retry_strategy } : {},
|
|
79
79
|
...body?.credits_used !== void 0 ? { credits_used: body.credits_used } : {},
|
|
80
80
|
...body?.credits_charged !== void 0 ? { credits_charged: body.credits_charged } : {},
|
|
81
|
+
...body?.live_provider_called !== void 0 ? { live_provider_called: body.live_provider_called } : {},
|
|
82
|
+
...body?.estimated_external_cost_usd !== void 0 ? { estimated_external_cost_usd: body.estimated_external_cost_usd } : {},
|
|
81
83
|
...body?.job_id !== void 0 ? { job_id: body.job_id } : {},
|
|
82
84
|
...body?.idempotency_key !== void 0 ? { idempotency_key: body.idempotency_key } : {},
|
|
83
85
|
...body?.verification_run_id !== void 0 ? { verification_run_id: body.verification_run_id } : {},
|
|
@@ -162,7 +164,8 @@ var HttpClient = class {
|
|
|
162
164
|
const err = parseError(res.status, errBody);
|
|
163
165
|
if (err.isRetryable && attempt < this.maxRetries) {
|
|
164
166
|
const retryWithNewKey = err.details?.retry_strategy === "new_idempotency_key" && err.details?.credits_used === 0 && err.details?.credits_charged === 0;
|
|
165
|
-
|
|
167
|
+
const recoverSameRun = err.details?.retry_strategy === "same_run_recovery";
|
|
168
|
+
if (retryWithNewKey || recoverSameRun) throw err;
|
|
166
169
|
const wait = err.retryAfter !== void 0 ? err.retryAfter * 1e3 : Math.min(1e3 * Math.pow(2, attempt), 1e4);
|
|
167
170
|
await sleep(wait);
|
|
168
171
|
lastError = err;
|
|
@@ -234,6 +237,7 @@ var HttpClient = class {
|
|
|
234
237
|
if (!res.ok) {
|
|
235
238
|
const err = parseError(res.status, data ?? { message: text });
|
|
236
239
|
if (err.isRetryable && attempt < this.maxRetries) {
|
|
240
|
+
if (err.details?.retry_strategy === "same_run_recovery") throw err;
|
|
237
241
|
lastError = err;
|
|
238
242
|
await sleep(err.retryAfter ? err.retryAfter * 1e3 : Math.min(1e3 * Math.pow(2, attempt), 1e4));
|
|
239
243
|
continue;
|
|
@@ -258,6 +262,7 @@ var HttpClient = class {
|
|
|
258
262
|
details: isRecord(responseError.data) ? responseError.data : void 0
|
|
259
263
|
});
|
|
260
264
|
if (err.isRetryable && attempt < this.maxRetries) {
|
|
265
|
+
if (err.details?.retry_strategy === "same_run_recovery") throw err;
|
|
261
266
|
lastError = err;
|
|
262
267
|
await sleep(err.retryAfter ? err.retryAfter * 1e3 : Math.min(1e3 * Math.pow(2, attempt), 1e4));
|
|
263
268
|
continue;
|
|
@@ -266,7 +271,10 @@ var HttpClient = class {
|
|
|
266
271
|
}
|
|
267
272
|
return unwrapMcpResponse(data);
|
|
268
273
|
} catch (e) {
|
|
269
|
-
if (e instanceof SignalizError
|
|
274
|
+
if (e instanceof SignalizError) {
|
|
275
|
+
if (e.details?.retry_strategy === "same_run_recovery") throw e;
|
|
276
|
+
if (!e.isRetryable) throw e;
|
|
277
|
+
}
|
|
270
278
|
if (e.name === "AbortError") {
|
|
271
279
|
lastError = new SignalizError({
|
|
272
280
|
code: "TIMEOUT",
|
|
@@ -377,15 +385,25 @@ function unwrapMcpPayload(payload) {
|
|
|
377
385
|
return unwrapMcpPayload(payload.result);
|
|
378
386
|
}
|
|
379
387
|
if (payload.ok === false) {
|
|
388
|
+
if (isRecord(payload.result) && (payload.result.success === false || payload.result.ok === false)) {
|
|
389
|
+
return unwrapMcpPayload(payload.result);
|
|
390
|
+
}
|
|
380
391
|
const first = firstPayloadError(payload);
|
|
381
|
-
const
|
|
392
|
+
const firstDetails = isRecord(first.details) ? first.details : {};
|
|
393
|
+
const code = firstString(
|
|
394
|
+
firstDetails.error_code,
|
|
395
|
+
firstDetails.legacy_error_code,
|
|
396
|
+
first.code,
|
|
397
|
+
payload.error_code,
|
|
398
|
+
payload.code
|
|
399
|
+
) || (payload.approval_required ? "APPROVAL_REQUIRED" : "MCP_ERROR");
|
|
382
400
|
throw new SignalizError({
|
|
383
401
|
code,
|
|
384
402
|
message: firstString(first.message, payload.message, payload.summary, payload.error) || "MCP request failed",
|
|
385
403
|
errorType: mapErrorTypeFromCode(code),
|
|
386
404
|
details: {
|
|
387
405
|
...payload,
|
|
388
|
-
...
|
|
406
|
+
...firstDetails
|
|
389
407
|
}
|
|
390
408
|
});
|
|
391
409
|
}
|
|
@@ -394,14 +412,20 @@ function unwrapMcpPayload(payload) {
|
|
|
394
412
|
}
|
|
395
413
|
if (payload.success === false) {
|
|
396
414
|
const first = firstPayloadError(payload);
|
|
397
|
-
const
|
|
415
|
+
const firstDetails = isRecord(first.details) ? first.details : {};
|
|
416
|
+
const code = firstString(
|
|
417
|
+
firstDetails.error_code,
|
|
418
|
+
firstDetails.legacy_error_code,
|
|
419
|
+
first.code,
|
|
420
|
+
payload.error_code
|
|
421
|
+
) || (payload.approval_required ? "APPROVAL_REQUIRED" : "MCP_ERROR");
|
|
398
422
|
throw new SignalizError({
|
|
399
423
|
code,
|
|
400
424
|
message: firstString(first.message, payload.message, payload.summary) || "MCP request failed",
|
|
401
425
|
errorType: mapErrorTypeFromCode(code),
|
|
402
426
|
details: {
|
|
403
427
|
...payload,
|
|
404
|
-
...
|
|
428
|
+
...firstDetails
|
|
405
429
|
}
|
|
406
430
|
});
|
|
407
431
|
}
|
|
@@ -591,6 +615,31 @@ function assertLargeCoreProductInputBounds(path2, body) {
|
|
|
591
615
|
);
|
|
592
616
|
}
|
|
593
617
|
|
|
618
|
+
// ../../supabase/functions/_shared/find-email-identity.ts
|
|
619
|
+
var LINKEDIN_PERSON_PROFILE_URL_PATTERN = "^[hH][tT][tT][pP][sS]://(?:[A-Za-z0-9-]+\\.)*[lL][iI][nN][kK][eE][dD][iI][nN]\\.[cC][oO][mM]/[iI][nN]/[^/?#]+/?(?:[?#].*)?$";
|
|
620
|
+
var LINKEDIN_PERSON_PROFILE_URL_REGEX = new RegExp(LINKEDIN_PERSON_PROFILE_URL_PATTERN);
|
|
621
|
+
function nonEmptyText(value) {
|
|
622
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
623
|
+
}
|
|
624
|
+
function isLinkedInPersonProfileUrl(value) {
|
|
625
|
+
if (!nonEmptyText(value)) return false;
|
|
626
|
+
const normalized = String(value).trim();
|
|
627
|
+
if (!LINKEDIN_PERSON_PROFILE_URL_REGEX.test(normalized)) return false;
|
|
628
|
+
try {
|
|
629
|
+
const url = new URL(normalized);
|
|
630
|
+
const hostname = url.hostname.toLowerCase();
|
|
631
|
+
return url.protocol === "https:" && !url.username && !url.password && !url.port && (hostname === "linkedin.com" || hostname.endsWith(".linkedin.com")) && /^\/in\/[^/]+\/?$/i.test(url.pathname);
|
|
632
|
+
} catch {
|
|
633
|
+
return false;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
function hasFindEmailIdentity(input) {
|
|
637
|
+
if (isLinkedInPersonProfileUrl(input.linkedin_url)) return true;
|
|
638
|
+
const hasName = nonEmptyText(input.full_name) || nonEmptyText(input.first_name) && nonEmptyText(input.last_name);
|
|
639
|
+
return hasName && nonEmptyText(input.company_domain);
|
|
640
|
+
}
|
|
641
|
+
var FIND_EMAIL_IDENTITY_REQUIREMENT = "Provide an HTTPS LinkedIn person profile URL (/in/<slug>), or provide company_domain with full_name or first_name and last_name.";
|
|
642
|
+
|
|
594
643
|
// src/index.ts
|
|
595
644
|
var MAX_ROW_RATE_LIMIT_RETRIES = 2;
|
|
596
645
|
var Signaliz = class {
|
|
@@ -598,22 +647,28 @@ var Signaliz = class {
|
|
|
598
647
|
this.client = new HttpClient(config);
|
|
599
648
|
}
|
|
600
649
|
async findEmail(params) {
|
|
601
|
-
const
|
|
650
|
+
const request = findEmailRequestBody(params);
|
|
651
|
+
assertFindEmailRequestIdentity(request);
|
|
652
|
+
const data = await this.client.post("api/v1/find-email", request);
|
|
602
653
|
return isCoreProductDryRun(data) ? normalizeCoreProductDryRunResult(data) : normalizeFindEmailResult(data);
|
|
603
654
|
}
|
|
604
655
|
async findEmails(params, options) {
|
|
605
656
|
validateBatchSize(params);
|
|
657
|
+
const requests = params.map(findEmailRequestBody);
|
|
658
|
+
if (!requests.some(hasFindEmailRequestIdentity)) {
|
|
659
|
+
throw new TypeError(`Find Email batch must include at least one valid identity. ${FIND_EMAIL_IDENTITY_REQUIREMENT}`);
|
|
660
|
+
}
|
|
606
661
|
if (options?.dryRun === true) {
|
|
607
662
|
return this.runCoreProductDryRun(
|
|
608
663
|
"api/v1/find-email",
|
|
609
|
-
|
|
664
|
+
requests,
|
|
610
665
|
options.idempotencyKey
|
|
611
666
|
);
|
|
612
667
|
}
|
|
613
668
|
const startedAt = Date.now();
|
|
614
669
|
const round = await this.runCoreBatchRound(
|
|
615
670
|
"api/v1/find-email",
|
|
616
|
-
|
|
671
|
+
requests.map((request, index) => ({ index, request })),
|
|
617
672
|
options
|
|
618
673
|
);
|
|
619
674
|
return finalizeCoreBatch(
|
|
@@ -1439,6 +1494,8 @@ function batchItemFailure(index, error, raw) {
|
|
|
1439
1494
|
const retryStrategy = raw?.retry_strategy ?? raw?.retryStrategy;
|
|
1440
1495
|
const creditsUsed = raw?.credits_used ?? raw?.creditsUsed;
|
|
1441
1496
|
const creditsCharged = raw?.credits_charged ?? raw?.creditsCharged;
|
|
1497
|
+
const liveProviderCalled = raw?.live_provider_called ?? raw?.liveProviderCalled;
|
|
1498
|
+
const estimatedExternalCostUsd = raw?.estimated_external_cost_usd ?? raw?.estimatedExternalCostUsd;
|
|
1442
1499
|
const runId = [raw?.run_id, raw?.runId, raw?.signal_run_id, raw?.signalRunId].find((value) => typeof value === "string" && value.trim());
|
|
1443
1500
|
const verificationRunId = raw?.verification_run_id ?? raw?.verificationRunId;
|
|
1444
1501
|
const jobId = raw?.job_id ?? raw?.jobId;
|
|
@@ -1450,13 +1507,18 @@ function batchItemFailure(index, error, raw) {
|
|
|
1450
1507
|
...errorCode ? { errorCode } : {},
|
|
1451
1508
|
...typeof retryEligible === "boolean" ? { retryEligible } : {},
|
|
1452
1509
|
...Number.isFinite(retryAfterSeconds2) && retryAfterSeconds2 >= 0 ? { retryAfterSeconds: retryAfterSeconds2 } : {},
|
|
1453
|
-
...
|
|
1510
|
+
...["new_idempotency_key", "same_run_recovery"].includes(String(retryStrategy)) ? { retryStrategy } : {},
|
|
1454
1511
|
...creditsUsed === 0 ? { creditsUsed: 0 } : {},
|
|
1455
1512
|
...creditsCharged === 0 ? { creditsCharged: 0 } : {},
|
|
1513
|
+
...liveProviderCalled === false ? { liveProviderCalled: false } : {},
|
|
1514
|
+
...estimatedExternalCostUsd === 0 ? { estimatedExternalCostUsd: 0 } : {},
|
|
1456
1515
|
...typeof runId === "string" && runId.trim() ? { runId: runId.trim() } : {},
|
|
1457
1516
|
...typeof verificationRunId === "string" && verificationRunId.trim() ? { verificationRunId: verificationRunId.trim() } : {},
|
|
1458
1517
|
...typeof jobId === "string" && jobId.trim() ? { jobId: jobId.trim() } : {},
|
|
1459
|
-
...typeof suggestedAction === "string" && suggestedAction.trim() ? { suggestedAction: suggestedAction.trim() } : {}
|
|
1518
|
+
...typeof suggestedAction === "string" && suggestedAction.trim() ? { suggestedAction: suggestedAction.trim() } : {},
|
|
1519
|
+
...raw?.do_not_auto_resubmit === true ? { doNotAutoResubmit: true } : {},
|
|
1520
|
+
...raw?.recovery_mode === "same_run" ? { recoveryMode: "same_run" } : {},
|
|
1521
|
+
...["pending", "completed"].includes(String(raw?.recovery_status)) ? { recoveryStatus: raw?.recovery_status } : {}
|
|
1460
1522
|
};
|
|
1461
1523
|
}
|
|
1462
1524
|
function recoverableJobRowFailed(row) {
|
|
@@ -1519,6 +1581,14 @@ function findEmailRequestBody(params) {
|
|
|
1519
1581
|
idempotency_key: params.idempotencyKey
|
|
1520
1582
|
});
|
|
1521
1583
|
}
|
|
1584
|
+
function hasFindEmailRequestIdentity(request) {
|
|
1585
|
+
return typeof request.run_id === "string" && request.run_id.trim().length > 0 || hasFindEmailIdentity(request);
|
|
1586
|
+
}
|
|
1587
|
+
function assertFindEmailRequestIdentity(request) {
|
|
1588
|
+
if (!hasFindEmailRequestIdentity(request)) {
|
|
1589
|
+
throw new TypeError(`Find Email requires a valid identity. ${FIND_EMAIL_IDENTITY_REQUIREMENT}`);
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1522
1592
|
function verifyEmailBatchRequestBody(input, options) {
|
|
1523
1593
|
if (typeof input === "string") {
|
|
1524
1594
|
return compact({ email: input, skip_cache: options?.skipCache });
|
|
@@ -1597,6 +1667,7 @@ function normalizeFindEmailResult(data) {
|
|
|
1597
1667
|
verificationObservedAt: typeof data.verification_observed_at === "string" ? data.verification_observed_at : void 0,
|
|
1598
1668
|
failureReason: data.failure_reason ?? (failed || !found ? "no_verified_email_found" : "none"),
|
|
1599
1669
|
creditsUsed: data.credits_used ?? billingMetadata?.credits_used,
|
|
1670
|
+
creditsCharged: data.credits_charged ?? billingMetadata?.credits_charged,
|
|
1600
1671
|
estimatedExternalCostUsd: data.estimated_external_cost_usd ?? billingMetadata?.estimated_external_cost_usd,
|
|
1601
1672
|
billingMetadata,
|
|
1602
1673
|
historicalBillingMetadata: data.historical_billing_metadata,
|
|
@@ -1615,6 +1686,11 @@ function normalizeFindEmailResult(data) {
|
|
|
1615
1686
|
runId: data.run_id,
|
|
1616
1687
|
nextPollAfterSeconds: data.next_poll_after_seconds,
|
|
1617
1688
|
suggestedAction: data.suggested_action,
|
|
1689
|
+
retryEligible: data.retry_eligible,
|
|
1690
|
+
retryStrategy: ["new_idempotency_key", "same_run_recovery"].includes(data.retry_strategy) ? data.retry_strategy : void 0,
|
|
1691
|
+
doNotAutoResubmit: data.do_not_auto_resubmit === true,
|
|
1692
|
+
recoveryMode: data.recovery_mode === "same_run" ? "same_run" : void 0,
|
|
1693
|
+
recoveryStatus: ["pending", "completed"].includes(String(data.recovery_status)) ? data.recovery_status : void 0,
|
|
1618
1694
|
cachePublicationStatus: data.cache_publication_status,
|
|
1619
1695
|
cachePublicationRetryEligible: data.cache_publication_retry_eligible,
|
|
1620
1696
|
raw: data
|
|
@@ -1942,6 +2018,16 @@ function normalizeSignalDiscoverySignal(value) {
|
|
|
1942
2018
|
if (!companyName || !companyDomain) {
|
|
1943
2019
|
throw new Error("Signals Everything response violated the company attribution contract.");
|
|
1944
2020
|
}
|
|
2021
|
+
const eventDate = String(signal.event_date ?? signal.date ?? signal.signal_date ?? "").trim();
|
|
2022
|
+
const sourceUrl = String(signal.source_url ?? signal.url ?? "").trim();
|
|
2023
|
+
const evidence = Array.isArray(signal.evidence) ? signal.evidence.map((item) => ({
|
|
2024
|
+
url: String(item?.url ?? "").trim(),
|
|
2025
|
+
publishedAt: String(item?.published_at ?? item?.publishedAt ?? "").trim(),
|
|
2026
|
+
source: String(item?.source ?? "").trim()
|
|
2027
|
+
})).filter((item) => Boolean(item.url)) : [];
|
|
2028
|
+
if (!eventDate || !sourceUrl || !evidence.some((item) => item.url === sourceUrl && item.publishedAt === eventDate)) {
|
|
2029
|
+
throw new Error("Signals Everything response violated the dated-evidence and source-URL contract.");
|
|
2030
|
+
}
|
|
1945
2031
|
return {
|
|
1946
2032
|
id: signal.id,
|
|
1947
2033
|
company: {
|
|
@@ -1952,16 +2038,12 @@ function normalizeSignalDiscoverySignal(value) {
|
|
|
1952
2038
|
title: signal.title ?? "",
|
|
1953
2039
|
type: signal.type ?? signal.signal_type ?? "unknown",
|
|
1954
2040
|
summary: signal.summary ?? signal.content ?? signal.description ?? "",
|
|
1955
|
-
eventDate
|
|
1956
|
-
evidence
|
|
1957
|
-
url: String(item?.url ?? ""),
|
|
1958
|
-
publishedAt: String(item?.published_at ?? item?.publishedAt ?? ""),
|
|
1959
|
-
source: String(item?.source ?? "")
|
|
1960
|
-
})).filter((item) => Boolean(item.url)) : [],
|
|
2041
|
+
eventDate,
|
|
2042
|
+
evidence,
|
|
1961
2043
|
content: signal.summary ?? signal.content ?? signal.description ?? "",
|
|
1962
2044
|
date: signal.event_date ?? signal.date ?? signal.signal_date ?? null,
|
|
1963
2045
|
detectedAt: signal.event_date ?? signal.detected_at ?? null,
|
|
1964
|
-
sourceUrl
|
|
2046
|
+
sourceUrl,
|
|
1965
2047
|
sourceType: signal.source_type ?? null,
|
|
1966
2048
|
confidence: signal.confidence ?? signal.confidence_score ?? null,
|
|
1967
2049
|
classification: signal.signal_classification ?? signal.classification ?? null,
|
package/dist/mcp-config.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signaliz/sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.66",
|
|
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",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"scripts": {
|
|
16
16
|
"generate-types": "tsx scripts/generate-types.ts",
|
|
17
17
|
"build": "npm run generate-types && tsup src/index.ts src/mcp-config.ts --format cjs,esm --dts --clean",
|
|
18
|
-
"test": "tsx tests/core-products.test.ts",
|
|
18
|
+
"test": "tsx tests/core-products.test.ts && tsc --noEmit --strict --skipLibCheck --moduleResolution node --module esnext --target es2020 tests/find-email-types.test.ts",
|
|
19
19
|
"prepublishOnly": "npm run build"
|
|
20
20
|
},
|
|
21
21
|
"keywords": [
|