@coldiq/mcp 5.4.6 → 5.4.8
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 +7 -3
- package/dist/index.js.map +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +17 -12
- package/dist/registry.js.map +1 -1
- package/dist/tools/get-website-visitors.js +2 -2
- package/dist/tools/get-website-visitors.js.map +1 -1
- package/dist/tools/list-website-visitors-sites.d.ts +19 -0
- package/dist/tools/list-website-visitors-sites.d.ts.map +1 -0
- package/dist/tools/list-website-visitors-sites.js +43 -0
- package/dist/tools/list-website-visitors-sites.js.map +1 -0
- package/dist/tools/setup-website-visitors.d.ts +21 -0
- package/dist/tools/setup-website-visitors.d.ts.map +1 -0
- package/dist/tools/setup-website-visitors.js +36 -0
- package/dist/tools/setup-website-visitors.js.map +1 -0
- package/dist/utils/provider-resolver.js +1 -1
- package/package.json +1 -1
- package/src/index.ts +19 -3
- package/src/registry.ts +16 -12
- package/src/tools/get-website-visitors.ts +2 -2
- package/src/tools/list-website-visitors-sites.ts +49 -0
- package/src/tools/setup-website-visitors.ts +40 -0
- package/src/utils/provider-resolver.ts +1 -1
- package/tests/executor.test.ts +2 -2
- package/tests/registry-enrich-person.test.ts +4 -4
- package/tests/registry-find-people.test.ts +3 -2
- package/tests/registry-search-companies.test.ts +11 -2
- package/tests/registry.test.ts +9 -8
- package/tests/tools/list-website-visitors-sites.test.ts +142 -0
- package/tests/tools/setup-website-visitors.test.ts +106 -0
|
@@ -2,13 +2,13 @@ import { z } from 'zod';
|
|
|
2
2
|
import { callApi } from '../client.js';
|
|
3
3
|
export const getWebsiteVisitorsName = 'get_website_visitors';
|
|
4
4
|
export const getWebsiteVisitorsDescription = 'Read the leads ColdIQ Visitor ID identified on one of your websites — the people who visited (with verified work email, title and LinkedIn where available) or the companies they belong to (with firmographics). ' +
|
|
5
|
-
'Use `type: "people"` for enriched contacts and `type: "companies"` for enriched accounts. To find `website_id`, call
|
|
5
|
+
'Use `type: "people"` for enriched contacts and `type: "companies"` for enriched accounts. To find `website_id`, call `list_website_visitors_sites`; to add a site, call `setup_website_visitors`. ' +
|
|
6
6
|
'Results are paginated: pass the `cursor` from the previous response to fetch the next page. Free — identifications are billed when they are delivered, not when you read them.';
|
|
7
7
|
export const getWebsiteVisitorsSchema = {
|
|
8
8
|
website_id: z
|
|
9
9
|
.number()
|
|
10
10
|
.int()
|
|
11
|
-
.describe('The tracked website to read leads from, as returned by
|
|
11
|
+
.describe('The tracked website to read leads from, as returned by `list_website_visitors_sites`.'),
|
|
12
12
|
type: z
|
|
13
13
|
.enum(['people', 'companies'])
|
|
14
14
|
.describe('"people" returns identified contacts (email, title, LinkedIn); "companies" returns identified accounts (firmographics).'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-website-visitors.js","sourceRoot":"","sources":["../../src/tools/get-website-visitors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,CAAC,MAAM,sBAAsB,GAAG,sBAAsB,CAAA;AAE5D,MAAM,CAAC,MAAM,6BAA6B,GACxC,oNAAoN;IACpN,
|
|
1
|
+
{"version":3,"file":"get-website-visitors.js","sourceRoot":"","sources":["../../src/tools/get-website-visitors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,CAAC,MAAM,sBAAsB,GAAG,sBAAsB,CAAA;AAE5D,MAAM,CAAC,MAAM,6BAA6B,GACxC,oNAAoN;IACpN,oMAAoM;IACpM,gLAAgL,CAAA;AAElL,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,UAAU,EAAE,CAAC;SACV,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,CAAC,uFAAuF,CAAC;IACpG,IAAI,EAAE,CAAC;SACJ,IAAI,CAAC,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;SAC7B,QAAQ,CAAC,yHAAyH,CAAC;IACtI,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,GAAG,CAAC;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,gFAAgF,CAAC;IAC7F,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+CAA+C,CAAC;IACvF,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,qEAAqE,CAAC;IAClF,UAAU,EAAE,CAAC;SACV,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,yGAAyG,CAAC;IACtH,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,kEAAkE,CAAC;CAChF,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,KAA8B;IAC5E,MAAM,SAAS,GAAG,KAAK,CAAC,UAAoB,CAAA;IAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,IAA8B,CAAA;IACjD,MAAM,QAAQ,GAAG,IAAI,KAAK,QAAQ,CAAA;IAClC,MAAM,IAAI,GAAG,wBAAwB,SAAS,IAAI,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,EAAE,CAAA;IAEtF,MAAM,KAAK,GAA2B,EAAE,CAAA;IACxC,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAChE,IAAI,KAAK,CAAC,MAAM;QAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IACrD,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,KAAK,CAAC,KAAK;YAAE,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAClD,IAAI,KAAK,CAAC,UAAU;YAAE,KAAK,CAAC,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;IACnE,CAAC;SAAM,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACxB,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IACrC,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,CAAA;IACxD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wBACnB,KAAK,EAAE,6BAA6B,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,EAAE;wBACvE,MAAM,EAAE,GAAG,CAAC,MAAM;wBAClB,IAAI,EAAE,GAAG,CAAC,IAAI;qBACf,CAAC;iBACH;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAA;IACH,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;AAC3F,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const listWebsiteVisitorsSitesName = "list_website_visitors_sites";
|
|
3
|
+
export declare const listWebsiteVisitorsSitesDescription: string;
|
|
4
|
+
export declare const listWebsiteVisitorsSitesSchema: {
|
|
5
|
+
website_id: z.ZodOptional<z.ZodNumber>;
|
|
6
|
+
};
|
|
7
|
+
export declare function listWebsiteVisitorsSitesHandler(input: Record<string, unknown>): Promise<{
|
|
8
|
+
content: {
|
|
9
|
+
type: "text";
|
|
10
|
+
text: string;
|
|
11
|
+
}[];
|
|
12
|
+
isError: boolean;
|
|
13
|
+
} | {
|
|
14
|
+
content: {
|
|
15
|
+
type: "text";
|
|
16
|
+
text: string;
|
|
17
|
+
}[];
|
|
18
|
+
}>;
|
|
19
|
+
//# sourceMappingURL=list-website-visitors-sites.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-website-visitors-sites.d.ts","sourceRoot":"","sources":["../../src/tools/list-website-visitors-sites.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,4BAA4B,gCAAgC,CAAA;AAEzE,eAAO,MAAM,mCAAmC,QAImE,CAAA;AAEnH,eAAO,MAAM,8BAA8B;;CAM1C,CAAA;AASD,wBAAsB,+BAA+B,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;GAsBnF"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { callApi } from '../client.js';
|
|
3
|
+
export const listWebsiteVisitorsSitesName = 'list_website_visitors_sites';
|
|
4
|
+
export const listWebsiteVisitorsSitesDescription = 'List the websites ColdIQ Visitor ID tracks for this account — each with its `id`, `domain`, `status`, whether it is `identifying` right now, and its `monthly_limit` (credits, companies, people, used_credits). ' +
|
|
5
|
+
'Pass `website_id` to get one website in full (pixel `embed_html` and `install` state; `install` null = state unknown, re-check later) together with its usage this period (people and companies identified, what it cost, and the live `credits_per_person` / `credits_per_company` — a person costs 6× a company; always quote these live values, never numbers from memory) — returned as `{ website, usage }`; when the usage read fails, `usage` is null and `usage_error` carries the status and message. ' +
|
|
6
|
+
'Free. Use the `id` as `website_id` in `get_website_visitors`; add a new site with `setup_website_visitors` (a 409 there whose message mentions a deactivated workspace means the domain is held by a deactivated workspace — do not retry, tell the user to contact ColdIQ support; any other 409 means the domain is already in this list — reuse it). ' +
|
|
7
|
+
'Any write (POST/PATCH/PUT/DELETE) returns 403 for a workspace member key — ask the workspace owner or an admin.';
|
|
8
|
+
export const listWebsiteVisitorsSitesSchema = {
|
|
9
|
+
website_id: z
|
|
10
|
+
.number()
|
|
11
|
+
.int()
|
|
12
|
+
.optional()
|
|
13
|
+
.describe('Return this one website with its install state and usage instead of the list.'),
|
|
14
|
+
};
|
|
15
|
+
function failure(error, status, data) {
|
|
16
|
+
return {
|
|
17
|
+
content: [{ type: 'text', text: JSON.stringify({ error, status, data }) }],
|
|
18
|
+
isError: true,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export async function listWebsiteVisitorsSitesHandler(input) {
|
|
22
|
+
if (input.website_id === undefined) {
|
|
23
|
+
const res = await callApi('GET', '/visitor-id/websites');
|
|
24
|
+
if (!res.ok)
|
|
25
|
+
return failure('Failed to list tracked websites', res.status, res.data);
|
|
26
|
+
return { content: [{ type: 'text', text: JSON.stringify({ data: res.data }) }] };
|
|
27
|
+
}
|
|
28
|
+
const websiteId = input.website_id;
|
|
29
|
+
const [website, usage] = await Promise.all([
|
|
30
|
+
callApi('GET', `/visitor-id/websites/${websiteId}`),
|
|
31
|
+
callApi('GET', `/visitor-id/websites/${websiteId}/usage`),
|
|
32
|
+
]);
|
|
33
|
+
if (!website.ok)
|
|
34
|
+
return failure('Failed to read tracked website', website.status, website.data);
|
|
35
|
+
// A failed usage read must not discard the website the caller asked for: the pixel
|
|
36
|
+
// and install state stay useful on their own, so the usage gap is reported next to
|
|
37
|
+
// them instead of replacing them.
|
|
38
|
+
const data = usage.ok
|
|
39
|
+
? { website: website.data, usage: usage.data }
|
|
40
|
+
: { website: website.data, usage: null, usage_error: { status: usage.status, data: usage.data } };
|
|
41
|
+
return { content: [{ type: 'text', text: JSON.stringify({ data }) }] };
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=list-website-visitors-sites.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-website-visitors-sites.js","sourceRoot":"","sources":["../../src/tools/list-website-visitors-sites.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,CAAC,MAAM,4BAA4B,GAAG,6BAA6B,CAAA;AAEzE,MAAM,CAAC,MAAM,mCAAmC,GAC9C,mNAAmN;IACnN,ifAAif;IACjf,0VAA0V;IAC1V,iHAAiH,CAAA;AAEnH,MAAM,CAAC,MAAM,8BAA8B,GAAG;IAC5C,UAAU,EAAE,CAAC;SACV,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,QAAQ,CAAC,+EAA+E,CAAC;CAC7F,CAAA;AAED,SAAS,OAAO,CAAC,KAAa,EAAE,MAAc,EAAE,IAAa;IAC3D,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACnF,OAAO,EAAE,IAAI;KACd,CAAA;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,+BAA+B,CAAC,KAA8B;IAClF,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE,sBAAsB,CAAC,CAAA;QACxD,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,OAAO,CAAC,iCAAiC,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,CAAA;QACpF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;IAC3F,CAAC;IAED,MAAM,SAAS,GAAG,KAAK,CAAC,UAAoB,CAAA;IAC5C,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACzC,OAAO,CAAC,KAAK,EAAE,wBAAwB,SAAS,EAAE,CAAC;QACnD,OAAO,CAAC,KAAK,EAAE,wBAAwB,SAAS,QAAQ,CAAC;KAC1D,CAAC,CAAA;IACF,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,OAAO,CAAC,gCAAgC,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IAE/F,mFAAmF;IACnF,mFAAmF;IACnF,kCAAkC;IAClC,MAAM,IAAI,GAAG,KAAK,CAAC,EAAE;QACnB,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE;QAC9C,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,CAAA;IAEnG,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;AACjF,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const setupWebsiteVisitorsName = "setup_website_visitors";
|
|
3
|
+
export declare const setupWebsiteVisitorsDescription: string;
|
|
4
|
+
export declare const setupWebsiteVisitorsSchema: {
|
|
5
|
+
domain: z.ZodString;
|
|
6
|
+
name: z.ZodOptional<z.ZodString>;
|
|
7
|
+
};
|
|
8
|
+
export declare function setupWebsiteVisitorsHandler(input: Record<string, unknown>): Promise<{
|
|
9
|
+
content: {
|
|
10
|
+
type: "text";
|
|
11
|
+
text: string;
|
|
12
|
+
}[];
|
|
13
|
+
isError: boolean;
|
|
14
|
+
} | {
|
|
15
|
+
content: {
|
|
16
|
+
type: "text";
|
|
17
|
+
text: string;
|
|
18
|
+
}[];
|
|
19
|
+
isError?: undefined;
|
|
20
|
+
}>;
|
|
21
|
+
//# sourceMappingURL=setup-website-visitors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-website-visitors.d.ts","sourceRoot":"","sources":["../../src/tools/setup-website-visitors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,wBAAwB,2BAA2B,CAAA;AAEhE,eAAO,MAAM,+BAA+B,QAOyB,CAAA;AAErE,eAAO,MAAM,0BAA0B;;;CAMtC,CAAA;AAED,wBAAsB,2BAA2B,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;GAiB/E"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { callApi } from '../client.js';
|
|
3
|
+
export const setupWebsiteVisitorsName = 'setup_website_visitors';
|
|
4
|
+
export const setupWebsiteVisitorsDescription = 'Set up ColdIQ Visitor ID on a website the user owns: creates the tracked website for a domain and returns it with the ready-to-paste tracking pixel (`embed_html`, `script_url`) and its install state (`install.is_installed`). ' +
|
|
5
|
+
'`install` can be null: that means the install state is unknown — re-check later, never report "not installed" from null. ' +
|
|
6
|
+
'One pixel per domain: a 409 whose message mentions a deactivated workspace = the domain is held by a deactivated workspace — do not retry, tell the user to contact ColdIQ support; any other 409 = a pixel already exists for this domain — call `list_website_visitors_sites` and reuse it. ' +
|
|
7
|
+
'Any write (POST/PATCH/PUT/DELETE) returns 403 for a workspace member key — ask the workspace owner or an admin. ' +
|
|
8
|
+
'Setup and reads are free. Identifications are billed once the pixel is live, within the site\'s monthly limit; a person costs 6× a company. ' +
|
|
9
|
+
'Always quote the live `credits_per_person` / `credits_per_company` from `list_website_visitors_sites` with a `website_id`, never numbers from memory. ' +
|
|
10
|
+
'Read the identified leads afterwards with `get_website_visitors`.';
|
|
11
|
+
export const setupWebsiteVisitorsSchema = {
|
|
12
|
+
domain: z
|
|
13
|
+
.string()
|
|
14
|
+
.min(1)
|
|
15
|
+
.describe('Website domain the tracking pixel will identify visitors for, e.g. "coldiq.com".'),
|
|
16
|
+
name: z.string().optional().describe('Display name for the website (defaults to the domain).'),
|
|
17
|
+
};
|
|
18
|
+
export async function setupWebsiteVisitorsHandler(input) {
|
|
19
|
+
const body = { domain: String(input.domain) };
|
|
20
|
+
if (input.name)
|
|
21
|
+
body.name = String(input.name);
|
|
22
|
+
const res = await callApi('POST', '/visitor-id/websites', body);
|
|
23
|
+
if (!res.ok) {
|
|
24
|
+
return {
|
|
25
|
+
content: [
|
|
26
|
+
{
|
|
27
|
+
type: 'text',
|
|
28
|
+
text: JSON.stringify({ error: 'Failed to set up website visitor identification', status: res.status, data: res.data }),
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
isError: true,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return { content: [{ type: 'text', text: JSON.stringify({ data: res.data }) }] };
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=setup-website-visitors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-website-visitors.js","sourceRoot":"","sources":["../../src/tools/setup-website-visitors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,CAAC,MAAM,wBAAwB,GAAG,wBAAwB,CAAA;AAEhE,MAAM,CAAC,MAAM,+BAA+B,GAC1C,mOAAmO;IACnO,2HAA2H;IAC3H,gSAAgS;IAChS,kHAAkH;IAClH,8IAA8I;IAC9I,wJAAwJ;IACxJ,mEAAmE,CAAA;AAErE,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CAAC,kFAAkF,CAAC;IAC/F,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wDAAwD,CAAC;CAC/F,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,KAA8B;IAC9E,MAAM,IAAI,GAA4B,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAA;IACtE,IAAI,KAAK,CAAC,IAAI;QAAE,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAE9C,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,sBAAsB,EAAE,IAAI,CAAC,CAAA;IAC/D,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,iDAAiD,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;iBACvH;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAA;IACH,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAA;AAC3F,CAAC"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -179,6 +179,20 @@ import {
|
|
|
179
179
|
getWebsiteVisitorsHandler,
|
|
180
180
|
} from './tools/get-website-visitors.js'
|
|
181
181
|
|
|
182
|
+
import {
|
|
183
|
+
setupWebsiteVisitorsName,
|
|
184
|
+
setupWebsiteVisitorsDescription,
|
|
185
|
+
setupWebsiteVisitorsSchema,
|
|
186
|
+
setupWebsiteVisitorsHandler,
|
|
187
|
+
} from './tools/setup-website-visitors.js'
|
|
188
|
+
|
|
189
|
+
import {
|
|
190
|
+
listWebsiteVisitorsSitesName,
|
|
191
|
+
listWebsiteVisitorsSitesDescription,
|
|
192
|
+
listWebsiteVisitorsSitesSchema,
|
|
193
|
+
listWebsiteVisitorsSitesHandler,
|
|
194
|
+
} from './tools/list-website-visitors-sites.js'
|
|
195
|
+
|
|
182
196
|
import {
|
|
183
197
|
listDataSourcesName,
|
|
184
198
|
listDataSourcesDescription,
|
|
@@ -268,9 +282,11 @@ registerPublicTool(listSkillsName, listSkillsDescription, listSkillsSchema, list
|
|
|
268
282
|
registerPublicTool(loadSkillName, loadSkillDescription, loadSkillSchema, loadSkillHandler)
|
|
269
283
|
registerPublicTool(extractPostEngagementName, withKnowledgeFirstRequirement(extractPostEngagementDescription), extractPostEngagementSchema, extractPostEngagementHandler)
|
|
270
284
|
registerPublicTool(getPlaceReviewsName, withKnowledgeFirstRequirement(getPlaceReviewsDescription), getPlaceReviewsSchema, getPlaceReviewsHandler)
|
|
271
|
-
// ColdIQ Visitor ID:
|
|
272
|
-
//
|
|
273
|
-
//
|
|
285
|
+
// ColdIQ Visitor ID: set up a tracked website (one pixel per domain), list the
|
|
286
|
+
// account's websites (with install state + usage), read the leads identified on them.
|
|
287
|
+
// All three are free; identifications are billed when delivered.
|
|
288
|
+
registerPublicTool(setupWebsiteVisitorsName, withKnowledgeFirstRequirement(setupWebsiteVisitorsDescription), setupWebsiteVisitorsSchema, setupWebsiteVisitorsHandler)
|
|
289
|
+
registerPublicTool(listWebsiteVisitorsSitesName, withKnowledgeFirstRequirement(listWebsiteVisitorsSitesDescription), listWebsiteVisitorsSitesSchema, listWebsiteVisitorsSitesHandler)
|
|
274
290
|
registerPublicTool(getWebsiteVisitorsName, withKnowledgeFirstRequirement(getWebsiteVisitorsDescription), getWebsiteVisitorsSchema, getWebsiteVisitorsHandler)
|
|
275
291
|
// Generic endpoint discovery + invoke: reach any integrated provider without a dedicated tool.
|
|
276
292
|
registerPublicTool(searchEndpointsName, withKnowledgeFirstRequirement(searchEndpointsDescription), searchEndpointsSchema, searchEndpointsHandler)
|
package/src/registry.ts
CHANGED
|
@@ -475,9 +475,12 @@ const searchCompaniesProviders: ProviderEntry[] = [
|
|
|
475
475
|
id: 'apollo',
|
|
476
476
|
endpoint: '/apollo/organizations/search',
|
|
477
477
|
method: 'POST',
|
|
478
|
-
|
|
478
|
+
// Keep Apollo behind the normal company databases. Its limited seat is a
|
|
479
|
+
// recovery source, before the costly Lima Data prospect and DiscoLike tails.
|
|
480
|
+
priority: 19,
|
|
479
481
|
isApplicable: (input) => {
|
|
480
482
|
// Apollo has no founded-year, technologies, funding, revenue, exclusion, or hiring filters — skip when set.
|
|
483
|
+
if (input.linkedin_search_url) return false
|
|
481
484
|
if (typeof input.min_founded_year === 'number' || typeof input.max_founded_year === 'number') return false
|
|
482
485
|
if (isNonEmptyArray(input.technologies)) return false
|
|
483
486
|
if (isNonEmptyArray(input.funding_stages)) return false
|
|
@@ -891,7 +894,7 @@ const searchCompaniesProviders: ProviderEntry[] = [
|
|
|
891
894
|
id: 'limadata-prospect-filter',
|
|
892
895
|
endpoint: '/limadata/prospect/companies/filter',
|
|
893
896
|
method: 'POST',
|
|
894
|
-
priority:
|
|
897
|
+
priority: 20,
|
|
895
898
|
mapParams: (input) => {
|
|
896
899
|
// Lima Data prospect filter uses [{filter_type, values}]. We can only reliably
|
|
897
900
|
// map company_headcount (size buckets); industries/locations need LinkedIn IDs.
|
|
@@ -923,7 +926,7 @@ const searchCompaniesProviders: ProviderEntry[] = [
|
|
|
923
926
|
id: 'limadata-prospect-url',
|
|
924
927
|
endpoint: '/limadata/prospect/companies/search-url',
|
|
925
928
|
method: 'POST',
|
|
926
|
-
priority:
|
|
929
|
+
priority: 21,
|
|
927
930
|
mapParams: (input) => ({
|
|
928
931
|
body: { search_url: input.linkedin_search_url as string },
|
|
929
932
|
}),
|
|
@@ -1087,7 +1090,7 @@ const searchCompaniesProviders: ProviderEntry[] = [
|
|
|
1087
1090
|
id: 'discolike',
|
|
1088
1091
|
endpoint: '/discolike/discover',
|
|
1089
1092
|
method: 'GET',
|
|
1090
|
-
priority:
|
|
1093
|
+
priority: 22,
|
|
1091
1094
|
isApplicable: (input) => {
|
|
1092
1095
|
if (!isNonEmptyArray(input.similar_to_domains) && !isNonEmptyArray(input.keywords) && !isNonEmptyArray(input.industries)) return false
|
|
1093
1096
|
if (isNonEmptyArray(input.locations)) return false
|
|
@@ -1277,7 +1280,8 @@ const findPeopleProviders: ProviderEntry[] = [
|
|
|
1277
1280
|
id: 'apollo',
|
|
1278
1281
|
endpoint: '/apollo/people/search',
|
|
1279
1282
|
method: 'POST',
|
|
1280
|
-
|
|
1283
|
+
// Apollo is the last active people-search recovery source in this mirror.
|
|
1284
|
+
priority: 11,
|
|
1281
1285
|
// Apollo caps per_page at 100 and rejects larger values with a 400. The
|
|
1282
1286
|
// find_people schema permits limit up to 500 (a waterfall-wide ceiling),
|
|
1283
1287
|
// so clamp here to keep Apollo from breaking the request when the caller
|
|
@@ -1614,7 +1618,7 @@ const findEmailProviders: ProviderEntry[] = [
|
|
|
1614
1618
|
id: 'limadata-work-email',
|
|
1615
1619
|
endpoint: '/limadata/find/work-email',
|
|
1616
1620
|
method: 'POST',
|
|
1617
|
-
priority:
|
|
1621
|
+
priority: 4,
|
|
1618
1622
|
mapParams: (input) => {
|
|
1619
1623
|
const fullName = [input.first_name, input.last_name].filter(Boolean).join(' ')
|
|
1620
1624
|
return {
|
|
@@ -1711,7 +1715,7 @@ const findEmailProviders: ProviderEntry[] = [
|
|
|
1711
1715
|
id: 'apollo-people-match',
|
|
1712
1716
|
endpoint: '/apollo/people/match',
|
|
1713
1717
|
method: 'POST',
|
|
1714
|
-
priority:
|
|
1718
|
+
priority: 5,
|
|
1715
1719
|
isApplicable: (input) =>
|
|
1716
1720
|
(typeof input.linkedin_url === 'string' && (input.linkedin_url as string).length > 0) ||
|
|
1717
1721
|
(!!input.first_name && !!input.last_name && !!(input.domain || input.company_name)),
|
|
@@ -2066,7 +2070,7 @@ const enrichCompanyProviders: ProviderEntry[] = [
|
|
|
2066
2070
|
id: 'apollo',
|
|
2067
2071
|
endpoint: '/apollo/organizations/enrich',
|
|
2068
2072
|
method: 'POST',
|
|
2069
|
-
priority:
|
|
2073
|
+
priority: 7,
|
|
2070
2074
|
isApplicable: (input) => !!input.domain,
|
|
2071
2075
|
mapParams: (input) => ({ body: { domain: input.domain } }),
|
|
2072
2076
|
hasResult: (data) => {
|
|
@@ -2095,7 +2099,7 @@ const enrichCompanyProviders: ProviderEntry[] = [
|
|
|
2095
2099
|
id: 'findymail',
|
|
2096
2100
|
endpoint: '/findymail/search/company',
|
|
2097
2101
|
method: 'POST',
|
|
2098
|
-
priority:
|
|
2102
|
+
priority: 6,
|
|
2099
2103
|
mapParams: (input) => ({
|
|
2100
2104
|
body: {
|
|
2101
2105
|
...(input.domain ? { domain: input.domain } : {}),
|
|
@@ -3296,7 +3300,7 @@ const enrichPersonProviders: ProviderEntry[] = [
|
|
|
3296
3300
|
id: 'apollo-people-match',
|
|
3297
3301
|
endpoint: '/apollo/people/match',
|
|
3298
3302
|
method: 'POST',
|
|
3299
|
-
priority:
|
|
3303
|
+
priority: 11,
|
|
3300
3304
|
mapParams: (input) => ({
|
|
3301
3305
|
body: {
|
|
3302
3306
|
first_name: input.first_name,
|
|
@@ -3414,7 +3418,7 @@ const enrichPersonProviders: ProviderEntry[] = [
|
|
|
3414
3418
|
id: 'icypeas-reverse-email-lookup',
|
|
3415
3419
|
endpoint: '/icypeas/reverse-email-lookup',
|
|
3416
3420
|
method: 'POST',
|
|
3417
|
-
priority:
|
|
3421
|
+
priority: 12,
|
|
3418
3422
|
isApplicable: (input) => typeof input.email === 'string' && (input.email as string).includes('@'),
|
|
3419
3423
|
mapParams: (input) => ({ body: { email: input.email } }),
|
|
3420
3424
|
hasResult: isIcypeasReverseEmailFound,
|
|
@@ -3423,7 +3427,7 @@ const enrichPersonProviders: ProviderEntry[] = [
|
|
|
3423
3427
|
id: 'pdl-person-identify',
|
|
3424
3428
|
endpoint: '/pdl/person/identify',
|
|
3425
3429
|
method: 'POST',
|
|
3426
|
-
priority:
|
|
3430
|
+
priority: 13,
|
|
3427
3431
|
mapParams: (input) => ({
|
|
3428
3432
|
body: {
|
|
3429
3433
|
email: input.email,
|
|
@@ -5,14 +5,14 @@ export const getWebsiteVisitorsName = 'get_website_visitors'
|
|
|
5
5
|
|
|
6
6
|
export const getWebsiteVisitorsDescription =
|
|
7
7
|
'Read the leads ColdIQ Visitor ID identified on one of your websites — the people who visited (with verified work email, title and LinkedIn where available) or the companies they belong to (with firmographics). ' +
|
|
8
|
-
'Use `type: "people"` for enriched contacts and `type: "companies"` for enriched accounts. To find `website_id`, call
|
|
8
|
+
'Use `type: "people"` for enriched contacts and `type: "companies"` for enriched accounts. To find `website_id`, call `list_website_visitors_sites`; to add a site, call `setup_website_visitors`. ' +
|
|
9
9
|
'Results are paginated: pass the `cursor` from the previous response to fetch the next page. Free — identifications are billed when they are delivered, not when you read them.'
|
|
10
10
|
|
|
11
11
|
export const getWebsiteVisitorsSchema = {
|
|
12
12
|
website_id: z
|
|
13
13
|
.number()
|
|
14
14
|
.int()
|
|
15
|
-
.describe('The tracked website to read leads from, as returned by
|
|
15
|
+
.describe('The tracked website to read leads from, as returned by `list_website_visitors_sites`.'),
|
|
16
16
|
type: z
|
|
17
17
|
.enum(['people', 'companies'])
|
|
18
18
|
.describe('"people" returns identified contacts (email, title, LinkedIn); "companies" returns identified accounts (firmographics).'),
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import { callApi } from '../client.js'
|
|
3
|
+
|
|
4
|
+
export const listWebsiteVisitorsSitesName = 'list_website_visitors_sites'
|
|
5
|
+
|
|
6
|
+
export const listWebsiteVisitorsSitesDescription =
|
|
7
|
+
'List the websites ColdIQ Visitor ID tracks for this account — each with its `id`, `domain`, `status`, whether it is `identifying` right now, and its `monthly_limit` (credits, companies, people, used_credits). ' +
|
|
8
|
+
'Pass `website_id` to get one website in full (pixel `embed_html` and `install` state; `install` null = state unknown, re-check later) together with its usage this period (people and companies identified, what it cost, and the live `credits_per_person` / `credits_per_company` — a person costs 6× a company; always quote these live values, never numbers from memory) — returned as `{ website, usage }`; when the usage read fails, `usage` is null and `usage_error` carries the status and message. ' +
|
|
9
|
+
'Free. Use the `id` as `website_id` in `get_website_visitors`; add a new site with `setup_website_visitors` (a 409 there whose message mentions a deactivated workspace means the domain is held by a deactivated workspace — do not retry, tell the user to contact ColdIQ support; any other 409 means the domain is already in this list — reuse it). ' +
|
|
10
|
+
'Any write (POST/PATCH/PUT/DELETE) returns 403 for a workspace member key — ask the workspace owner or an admin.'
|
|
11
|
+
|
|
12
|
+
export const listWebsiteVisitorsSitesSchema = {
|
|
13
|
+
website_id: z
|
|
14
|
+
.number()
|
|
15
|
+
.int()
|
|
16
|
+
.optional()
|
|
17
|
+
.describe('Return this one website with its install state and usage instead of the list.'),
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function failure(error: string, status: number, data: unknown) {
|
|
21
|
+
return {
|
|
22
|
+
content: [{ type: 'text' as const, text: JSON.stringify({ error, status, data }) }],
|
|
23
|
+
isError: true,
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function listWebsiteVisitorsSitesHandler(input: Record<string, unknown>) {
|
|
28
|
+
if (input.website_id === undefined) {
|
|
29
|
+
const res = await callApi('GET', '/visitor-id/websites')
|
|
30
|
+
if (!res.ok) return failure('Failed to list tracked websites', res.status, res.data)
|
|
31
|
+
return { content: [{ type: 'text' as const, text: JSON.stringify({ data: res.data }) }] }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const websiteId = input.website_id as number
|
|
35
|
+
const [website, usage] = await Promise.all([
|
|
36
|
+
callApi('GET', `/visitor-id/websites/${websiteId}`),
|
|
37
|
+
callApi('GET', `/visitor-id/websites/${websiteId}/usage`),
|
|
38
|
+
])
|
|
39
|
+
if (!website.ok) return failure('Failed to read tracked website', website.status, website.data)
|
|
40
|
+
|
|
41
|
+
// A failed usage read must not discard the website the caller asked for: the pixel
|
|
42
|
+
// and install state stay useful on their own, so the usage gap is reported next to
|
|
43
|
+
// them instead of replacing them.
|
|
44
|
+
const data = usage.ok
|
|
45
|
+
? { website: website.data, usage: usage.data }
|
|
46
|
+
: { website: website.data, usage: null, usage_error: { status: usage.status, data: usage.data } }
|
|
47
|
+
|
|
48
|
+
return { content: [{ type: 'text' as const, text: JSON.stringify({ data }) }] }
|
|
49
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import { callApi } from '../client.js'
|
|
3
|
+
|
|
4
|
+
export const setupWebsiteVisitorsName = 'setup_website_visitors'
|
|
5
|
+
|
|
6
|
+
export const setupWebsiteVisitorsDescription =
|
|
7
|
+
'Set up ColdIQ Visitor ID on a website the user owns: creates the tracked website for a domain and returns it with the ready-to-paste tracking pixel (`embed_html`, `script_url`) and its install state (`install.is_installed`). ' +
|
|
8
|
+
'`install` can be null: that means the install state is unknown — re-check later, never report "not installed" from null. ' +
|
|
9
|
+
'One pixel per domain: a 409 whose message mentions a deactivated workspace = the domain is held by a deactivated workspace — do not retry, tell the user to contact ColdIQ support; any other 409 = a pixel already exists for this domain — call `list_website_visitors_sites` and reuse it. ' +
|
|
10
|
+
'Any write (POST/PATCH/PUT/DELETE) returns 403 for a workspace member key — ask the workspace owner or an admin. ' +
|
|
11
|
+
'Setup and reads are free. Identifications are billed once the pixel is live, within the site\'s monthly limit; a person costs 6× a company. ' +
|
|
12
|
+
'Always quote the live `credits_per_person` / `credits_per_company` from `list_website_visitors_sites` with a `website_id`, never numbers from memory. ' +
|
|
13
|
+
'Read the identified leads afterwards with `get_website_visitors`.'
|
|
14
|
+
|
|
15
|
+
export const setupWebsiteVisitorsSchema = {
|
|
16
|
+
domain: z
|
|
17
|
+
.string()
|
|
18
|
+
.min(1)
|
|
19
|
+
.describe('Website domain the tracking pixel will identify visitors for, e.g. "coldiq.com".'),
|
|
20
|
+
name: z.string().optional().describe('Display name for the website (defaults to the domain).'),
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function setupWebsiteVisitorsHandler(input: Record<string, unknown>) {
|
|
24
|
+
const body: Record<string, unknown> = { domain: String(input.domain) }
|
|
25
|
+
if (input.name) body.name = String(input.name)
|
|
26
|
+
|
|
27
|
+
const res = await callApi('POST', '/visitor-id/websites', body)
|
|
28
|
+
if (!res.ok) {
|
|
29
|
+
return {
|
|
30
|
+
content: [
|
|
31
|
+
{
|
|
32
|
+
type: 'text' as const,
|
|
33
|
+
text: JSON.stringify({ error: 'Failed to set up website visitor identification', status: res.status, data: res.data }),
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
isError: true,
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return { content: [{ type: 'text' as const, text: JSON.stringify({ data: res.data }) }] }
|
|
40
|
+
}
|
package/tests/executor.test.ts
CHANGED
|
@@ -310,7 +310,7 @@ describe('executor postFilter integration', () => {
|
|
|
310
310
|
})
|
|
311
311
|
|
|
312
312
|
it('invokes Apollo postFilter — strips accounts and drops wrong-country orgs → falls through to error', async () => {
|
|
313
|
-
// Apollo is
|
|
313
|
+
// Apollo is a late recovery source. Mock earlier providers so Apollo is reached.
|
|
314
314
|
// Apollo returns orgs with wrong country + accounts key.
|
|
315
315
|
// postFilter should: strip accounts, drop German org, keep no French orgs → hasResult false → error.
|
|
316
316
|
let callCount = 0
|
|
@@ -348,7 +348,7 @@ describe('executor postFilter integration', () => {
|
|
|
348
348
|
})
|
|
349
349
|
|
|
350
350
|
it('passes raw data through unchanged when postFilter is not set (enrich_company)', async () => {
|
|
351
|
-
//
|
|
351
|
+
// Company enrichment providers have no postFilter.
|
|
352
352
|
// Verify a successful response is returned as-is.
|
|
353
353
|
globalThis.fetch = vi.fn(async () =>
|
|
354
354
|
new Response(JSON.stringify({ name: 'ColdIQ', domain: 'coldiq.com' }), { status: 200 })
|
|
@@ -133,8 +133,8 @@ describe('apollo-people-match', () => {
|
|
|
133
133
|
expect(p().hasResult({})).toBe(false)
|
|
134
134
|
})
|
|
135
135
|
|
|
136
|
-
it('priority is
|
|
137
|
-
expect(p().priority).toBe(
|
|
136
|
+
it('priority is 11', () => {
|
|
137
|
+
expect(p().priority).toBe(11)
|
|
138
138
|
})
|
|
139
139
|
})
|
|
140
140
|
|
|
@@ -450,8 +450,8 @@ describe('pdl-person-identify', () => {
|
|
|
450
450
|
expect(p().hasResult({ status: 404, matches: [] })).toBe(false)
|
|
451
451
|
})
|
|
452
452
|
|
|
453
|
-
it('priority is
|
|
454
|
-
expect(p().priority).toBe(
|
|
453
|
+
it('priority is 13 (last dormant fallback)', () => {
|
|
454
|
+
expect(p().priority).toBe(13)
|
|
455
455
|
})
|
|
456
456
|
})
|
|
457
457
|
|
|
@@ -897,8 +897,9 @@ describe('find_people priority ordering', () => {
|
|
|
897
897
|
expect(providers()[0].id).toBe('leadsfactory')
|
|
898
898
|
})
|
|
899
899
|
|
|
900
|
-
it('
|
|
900
|
+
it('Apollo is last in the active wired set', () => {
|
|
901
901
|
const ps = providers()
|
|
902
|
-
expect(ps[ps.length - 1].id).toBe('
|
|
902
|
+
expect(ps[ps.length - 1].id).toBe('apollo')
|
|
903
|
+
expect(ps[ps.length - 1].priority).toBe(11)
|
|
903
904
|
})
|
|
904
905
|
})
|
|
@@ -291,6 +291,11 @@ describe('apollo search_companies', () => {
|
|
|
291
291
|
const body = p().mapParams({ keywords: ['SaaS'] }).body as Record<string, unknown>
|
|
292
292
|
expect(body.limit).toBe(25)
|
|
293
293
|
})
|
|
294
|
+
|
|
295
|
+
it('is a recovery source and does not handle a LinkedIn search URL', () => {
|
|
296
|
+
expect(p().priority).toBe(19)
|
|
297
|
+
expect(p().isApplicable?.({ linkedin_search_url: 'https://www.linkedin.com/sales/search/company' })).toBe(false)
|
|
298
|
+
})
|
|
294
299
|
})
|
|
295
300
|
|
|
296
301
|
describe('theirstack search_companies', () => {
|
|
@@ -418,9 +423,13 @@ describe('search_companies priority ordering', () => {
|
|
|
418
423
|
}
|
|
419
424
|
})
|
|
420
425
|
|
|
421
|
-
it('
|
|
426
|
+
it('keeps Apollo before the costly tail and DiscoLike last', () => {
|
|
422
427
|
const ps = providers()
|
|
423
428
|
expect(ps[ps.length - 1].id).toBe('discolike')
|
|
424
|
-
expect(ps[ps.length -
|
|
429
|
+
expect(ps[ps.length - 1].priority).toBe(22)
|
|
430
|
+
expect(ps.findIndex((provider) => provider.id === 'ai-ark-companies'))
|
|
431
|
+
.toBeLessThan(ps.findIndex((provider) => provider.id === 'apollo'))
|
|
432
|
+
expect(ps.findIndex((provider) => provider.id === 'apollo'))
|
|
433
|
+
.toBeLessThan(ps.findIndex((provider) => provider.id === 'limadata-prospect-filter'))
|
|
425
434
|
})
|
|
426
435
|
})
|
package/tests/registry.test.ts
CHANGED
|
@@ -472,17 +472,17 @@ describe('registry', () => {
|
|
|
472
472
|
'fullenrich',
|
|
473
473
|
'theirstack',
|
|
474
474
|
'signalbase',
|
|
475
|
-
'apollo',
|
|
476
475
|
'limadata',
|
|
477
476
|
'predictleads',
|
|
478
477
|
'sumble',
|
|
479
|
-
'limadata-prospect-filter',
|
|
480
|
-
'limadata-prospect-url',
|
|
481
478
|
'linkupapi-search',
|
|
482
479
|
'linkupapi-fundraising',
|
|
483
480
|
'linkupapi-hiring',
|
|
484
481
|
'prospeo-search-company',
|
|
485
482
|
'ai-ark-companies',
|
|
483
|
+
'apollo',
|
|
484
|
+
'limadata-prospect-filter',
|
|
485
|
+
'limadata-prospect-url',
|
|
486
486
|
'discolike',
|
|
487
487
|
])
|
|
488
488
|
})
|
|
@@ -695,11 +695,11 @@ describe('registry', () => {
|
|
|
695
695
|
expect(wiza.priority).toBe(7)
|
|
696
696
|
})
|
|
697
697
|
|
|
698
|
-
it('mirrors the server order: findymail → leadmagic → prospeo →
|
|
698
|
+
it('mirrors the server order: findymail → leadmagic → prospeo → limadata → apollo → icypeas → wiza', () => {
|
|
699
699
|
const ids = getProviders('find_email').map((p) => p.id)
|
|
700
700
|
expect(ids).toEqual([
|
|
701
|
-
'findymail', 'leadmagic', 'prospeo', '
|
|
702
|
-
'
|
|
701
|
+
'findymail', 'leadmagic', 'prospeo', 'limadata-work-email',
|
|
702
|
+
'apollo-people-match', 'icypeas', 'wiza',
|
|
703
703
|
])
|
|
704
704
|
})
|
|
705
705
|
|
|
@@ -798,8 +798,8 @@ describe('registry', () => {
|
|
|
798
798
|
it('providers preserve their order with disabled providers omitted', () => {
|
|
799
799
|
const ids = getProviders('enrich_company').map((p) => p.id)
|
|
800
800
|
expect(ids).toEqual([
|
|
801
|
-
'
|
|
802
|
-
'
|
|
801
|
+
'limadata', 'prospeo', 'findymail',
|
|
802
|
+
'apollo', 'wiza', 'icypeas',
|
|
803
803
|
'builtwith', 'openmart', 'linkupapi-by-domain', 'linkupapi-by-url', 'discolike',
|
|
804
804
|
])
|
|
805
805
|
})
|
|
@@ -1215,6 +1215,7 @@ describe('registry', () => {
|
|
|
1215
1215
|
expect(apollo.isApplicable!({ exclude_countries: ['CN'] })).toBe(false)
|
|
1216
1216
|
expect(apollo.isApplicable!({ min_workforce_growth_pct: 10 })).toBe(false)
|
|
1217
1217
|
expect(apollo.isApplicable!({ is_hiring: true })).toBe(false)
|
|
1218
|
+
expect(apollo.isApplicable?.({ linkedin_search_url: 'https://www.linkedin.com/sales/search/company' })).toBe(false)
|
|
1218
1219
|
})
|
|
1219
1220
|
|
|
1220
1221
|
it('SignalBase isApplicable: skips for advanced filters it cannot apply', () => {
|