gtm-now 0.10.3 → 0.10.5
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/dist/index.js +164 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -204,7 +204,8 @@ var init_config = __esm({
|
|
|
204
204
|
GTM_INSTANTLY_API_KEY: "instantly",
|
|
205
205
|
GTM_SMARTLEAD_API_KEY: "smartlead",
|
|
206
206
|
GTM_HARVEST_API_KEY: "harvest",
|
|
207
|
-
GTM_STORELEADS_API_KEY: "storeleads"
|
|
207
|
+
GTM_STORELEADS_API_KEY: "storeleads",
|
|
208
|
+
GTM_EXA_API_KEY: "exa"
|
|
208
209
|
};
|
|
209
210
|
ENV_WORKSPACE_MAP = {
|
|
210
211
|
GTM_PLUSVIBE_WORKSPACE_ID: "plusvibe"
|
|
@@ -10390,6 +10391,154 @@ var init_harvest = __esm({
|
|
|
10390
10391
|
}
|
|
10391
10392
|
});
|
|
10392
10393
|
|
|
10394
|
+
// src/providers/adapters/exa.ts
|
|
10395
|
+
function extractDomain(url) {
|
|
10396
|
+
try {
|
|
10397
|
+
return new URL(url).hostname.replace(/^www\./, "");
|
|
10398
|
+
} catch {
|
|
10399
|
+
return url.replace(/^https?:\/\//, "").replace(/^www\./, "").split("/")[0] ?? url;
|
|
10400
|
+
}
|
|
10401
|
+
}
|
|
10402
|
+
function cleanTitle(title) {
|
|
10403
|
+
return title.replace(/\s*[-|]\s*[^-|]*$/, "").trim() || title;
|
|
10404
|
+
}
|
|
10405
|
+
function truncate(text, maxLength) {
|
|
10406
|
+
if (!text) return void 0;
|
|
10407
|
+
if (text.length <= maxLength) return text;
|
|
10408
|
+
return text.slice(0, maxLength - 3) + "...";
|
|
10409
|
+
}
|
|
10410
|
+
var BASE_URL2, REQUEST_TIMEOUT_MS2, ExaAdapter;
|
|
10411
|
+
var init_exa = __esm({
|
|
10412
|
+
"src/providers/adapters/exa.ts"() {
|
|
10413
|
+
"use strict";
|
|
10414
|
+
init_dist();
|
|
10415
|
+
BASE_URL2 = "https://api.exa.ai";
|
|
10416
|
+
REQUEST_TIMEOUT_MS2 = 15e3;
|
|
10417
|
+
ExaAdapter = class {
|
|
10418
|
+
name = "exa";
|
|
10419
|
+
capabilities = ["find_companies"];
|
|
10420
|
+
notes = 'Best for: semantic/neural company search. "Companies like Stripe but for healthcare" works. Meaning-based, not keyword matching.';
|
|
10421
|
+
apiKey;
|
|
10422
|
+
constructor(apiKey) {
|
|
10423
|
+
this.apiKey = apiKey;
|
|
10424
|
+
}
|
|
10425
|
+
async checkCredentials() {
|
|
10426
|
+
try {
|
|
10427
|
+
const res = await this.post("/search", {
|
|
10428
|
+
query: "test",
|
|
10429
|
+
type: "neural",
|
|
10430
|
+
category: "company",
|
|
10431
|
+
numResults: 1
|
|
10432
|
+
});
|
|
10433
|
+
return res.ok;
|
|
10434
|
+
} catch (error) {
|
|
10435
|
+
logError("exa:checkCredentials", error instanceof Error ? error : new Error(String(error)));
|
|
10436
|
+
return false;
|
|
10437
|
+
}
|
|
10438
|
+
}
|
|
10439
|
+
// ─── CompanyFinder ──────────────────────────────────
|
|
10440
|
+
async findCompanies(query) {
|
|
10441
|
+
const response = await this.routeQuery(query);
|
|
10442
|
+
const data = await response.json();
|
|
10443
|
+
const results = Array.isArray(data.results) ? data.results : [];
|
|
10444
|
+
return results.map((r) => this.mapResult(r));
|
|
10445
|
+
}
|
|
10446
|
+
// ─── Query Routing ──────────────────────────────────
|
|
10447
|
+
async routeQuery(query) {
|
|
10448
|
+
if (query.domain && !query.icp_text && !query.domains?.length) {
|
|
10449
|
+
return this.searchSingleDomain(query.domain, query);
|
|
10450
|
+
}
|
|
10451
|
+
if (query.domains?.length) {
|
|
10452
|
+
return this.findSimilar(query.domains, query);
|
|
10453
|
+
}
|
|
10454
|
+
return this.searchByIcp(query.icp_text ?? "", query);
|
|
10455
|
+
}
|
|
10456
|
+
async searchByIcp(icpText, query) {
|
|
10457
|
+
const body = {
|
|
10458
|
+
query: icpText,
|
|
10459
|
+
type: "neural",
|
|
10460
|
+
category: "company",
|
|
10461
|
+
numResults: query.limit ?? 25,
|
|
10462
|
+
contents: {
|
|
10463
|
+
text: { maxCharacters: 500 },
|
|
10464
|
+
summary: { query: "What does this company do?" }
|
|
10465
|
+
}
|
|
10466
|
+
};
|
|
10467
|
+
if (query.negate_domains?.length) {
|
|
10468
|
+
body.excludeDomains = query.negate_domains;
|
|
10469
|
+
}
|
|
10470
|
+
return this.post("/search", body);
|
|
10471
|
+
}
|
|
10472
|
+
async findSimilar(domains, query) {
|
|
10473
|
+
const primaryDomain = domains[0];
|
|
10474
|
+
const url = primaryDomain.includes("://") ? primaryDomain : `https://${primaryDomain}`;
|
|
10475
|
+
const body = {
|
|
10476
|
+
url,
|
|
10477
|
+
numResults: query.limit ?? 25,
|
|
10478
|
+
category: "company",
|
|
10479
|
+
contents: {
|
|
10480
|
+
text: { maxCharacters: 500 },
|
|
10481
|
+
summary: { query: "What does this company do?" }
|
|
10482
|
+
}
|
|
10483
|
+
};
|
|
10484
|
+
if (domains.length > 1) {
|
|
10485
|
+
body.includeDomains = domains.slice(1);
|
|
10486
|
+
}
|
|
10487
|
+
if (query.negate_domains?.length) {
|
|
10488
|
+
body.excludeDomains = query.negate_domains;
|
|
10489
|
+
}
|
|
10490
|
+
return this.post("/findSimilar", body);
|
|
10491
|
+
}
|
|
10492
|
+
async searchSingleDomain(domain, query) {
|
|
10493
|
+
const body = {
|
|
10494
|
+
query: domain,
|
|
10495
|
+
type: "neural",
|
|
10496
|
+
category: "company",
|
|
10497
|
+
includeDomains: [domain],
|
|
10498
|
+
numResults: 1,
|
|
10499
|
+
contents: {
|
|
10500
|
+
text: { maxCharacters: 1e3 },
|
|
10501
|
+
summary: { query: "What does this company do and what industry is it in?" }
|
|
10502
|
+
}
|
|
10503
|
+
};
|
|
10504
|
+
if (query.negate_domains?.length) {
|
|
10505
|
+
body.excludeDomains = query.negate_domains;
|
|
10506
|
+
}
|
|
10507
|
+
return this.post("/search", body);
|
|
10508
|
+
}
|
|
10509
|
+
// ─── Result Mapping ─────────────────────────────────
|
|
10510
|
+
mapResult(result) {
|
|
10511
|
+
return {
|
|
10512
|
+
domain: extractDomain(result.url),
|
|
10513
|
+
name: cleanTitle(result.title ?? extractDomain(result.url)),
|
|
10514
|
+
description: result.summary ?? truncate(result.text, 300),
|
|
10515
|
+
score: result.score,
|
|
10516
|
+
sources: [this.name]
|
|
10517
|
+
};
|
|
10518
|
+
}
|
|
10519
|
+
// ─── HTTP ───────────────────────────────────────────
|
|
10520
|
+
async post(path2, body) {
|
|
10521
|
+
const res = await fetch(`${BASE_URL2}${path2}`, {
|
|
10522
|
+
method: "POST",
|
|
10523
|
+
headers: {
|
|
10524
|
+
"Content-Type": "application/json",
|
|
10525
|
+
"x-api-key": this.apiKey
|
|
10526
|
+
},
|
|
10527
|
+
body: JSON.stringify(body),
|
|
10528
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2)
|
|
10529
|
+
});
|
|
10530
|
+
if (!res.ok) {
|
|
10531
|
+
const text = await res.text().catch(() => "");
|
|
10532
|
+
throw Object.assign(new Error(`Exa API error ${res.status}: ${text || res.statusText}`), {
|
|
10533
|
+
statusCode: res.status === 429 ? 429 : 502
|
|
10534
|
+
});
|
|
10535
|
+
}
|
|
10536
|
+
return res;
|
|
10537
|
+
}
|
|
10538
|
+
};
|
|
10539
|
+
}
|
|
10540
|
+
});
|
|
10541
|
+
|
|
10393
10542
|
// src/providers/adapters/index.ts
|
|
10394
10543
|
var init_adapters = __esm({
|
|
10395
10544
|
"src/providers/adapters/index.ts"() {
|
|
@@ -10406,6 +10555,7 @@ var init_adapters = __esm({
|
|
|
10406
10555
|
init_smartlead();
|
|
10407
10556
|
init_storeleads();
|
|
10408
10557
|
init_harvest();
|
|
10558
|
+
init_exa();
|
|
10409
10559
|
}
|
|
10410
10560
|
});
|
|
10411
10561
|
|
|
@@ -10436,6 +10586,8 @@ function createAdapter(name, config) {
|
|
|
10436
10586
|
return config.api_key ? new StoreLeadsAdapter(config.api_key) : null;
|
|
10437
10587
|
case "harvest":
|
|
10438
10588
|
return config.api_key ? new HarvestApiAdapter(config.api_key) : null;
|
|
10589
|
+
case "exa":
|
|
10590
|
+
return config.api_key ? new ExaAdapter(config.api_key) : null;
|
|
10439
10591
|
default:
|
|
10440
10592
|
return null;
|
|
10441
10593
|
}
|
|
@@ -10589,6 +10741,17 @@ var init_manifests = __esm({
|
|
|
10589
10741
|
quirks: ["free plan limitation"]
|
|
10590
10742
|
}
|
|
10591
10743
|
},
|
|
10744
|
+
exa: {
|
|
10745
|
+
name: "exa",
|
|
10746
|
+
capabilities: ["find_companies"],
|
|
10747
|
+
auto_selectable: false,
|
|
10748
|
+
find_companies: {
|
|
10749
|
+
max_limit: 100,
|
|
10750
|
+
default_limit: 25,
|
|
10751
|
+
supported_params: ["icp_text", "domains", "domain", "negate_domains"],
|
|
10752
|
+
quirks: ["semantic/neural search", "no employee or industry data", "premium provider"]
|
|
10753
|
+
}
|
|
10754
|
+
},
|
|
10592
10755
|
prospeo: {
|
|
10593
10756
|
name: "prospeo",
|
|
10594
10757
|
capabilities: ["find_people"],
|