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 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"],