@absolutejs/engagement-apollo 0.0.14 → 0.0.16
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.d.ts +6 -0
- package/dist/index.js +44 -13
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EngagementProviderError } from "@absolutejs/engagement";
|
|
1
2
|
import type { EngagementSource } from "@absolutejs/engagement";
|
|
2
3
|
export type ApolloOptions = {
|
|
3
4
|
apiKey: string;
|
|
@@ -6,4 +7,9 @@ export type ApolloOptions = {
|
|
|
6
7
|
/** Inject a fetch (tests, instrumentation). Defaults to global fetch. */
|
|
7
8
|
fetchImpl?: typeof fetch;
|
|
8
9
|
};
|
|
10
|
+
/** Safe provider classification; response bodies and billing context stay private. */
|
|
11
|
+
export declare class ApolloProviderError extends EngagementProviderError {
|
|
12
|
+
readonly code: string | null;
|
|
13
|
+
constructor(status: number, operation: string, code: string | null);
|
|
14
|
+
}
|
|
9
15
|
export declare const apolloSource: (options: ApolloOptions) => EngagementSource;
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,18 @@ var APOLLO_BASE_URL = "https://api.apollo.io";
|
|
|
8
8
|
var DEFAULT_ACTIVITY_LIMIT = 50;
|
|
9
9
|
var DEFAULT_SEARCH_LIMIT = 6;
|
|
10
10
|
var LOCKED_EMAIL = /email_not_unlocked/iu;
|
|
11
|
+
|
|
12
|
+
class ApolloProviderError extends EngagementProviderError {
|
|
13
|
+
code;
|
|
14
|
+
constructor(status, operation, code) {
|
|
15
|
+
super("apollo", status, operation);
|
|
16
|
+
this.code = code;
|
|
17
|
+
this.name = "ApolloProviderError";
|
|
18
|
+
if (code === "BILLING.LIMIT.CREDITS_EXHAUSTED") {
|
|
19
|
+
this.message = "Apollo lead credits are exhausted. An administrator must replenish the connected Apollo account; application credits do not fund Apollo.";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
11
23
|
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12
24
|
var str = (value) => typeof value === "string" && value.length > 0 ? value : null;
|
|
13
25
|
var num = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
@@ -49,6 +61,12 @@ var reference = (value) => isRecord(value) ? {
|
|
|
49
61
|
employeeCount: count(value.estimated_num_employees),
|
|
50
62
|
industries: strings(value.industries)
|
|
51
63
|
} : null;
|
|
64
|
+
var providerFailure = async (res, operation) => {
|
|
65
|
+
const value = await res.json().catch(() => null);
|
|
66
|
+
const details = isRecord(value) && isRecord(value.error_details) ? value.error_details : null;
|
|
67
|
+
const code = details && typeof details.code === "string" && /^[A-Z0-9_.]{1,120}$/u.test(details.code) ? details.code : null;
|
|
68
|
+
return new ApolloProviderError(res.status, operation, code);
|
|
69
|
+
};
|
|
52
70
|
var apolloSource = (options) => {
|
|
53
71
|
const baseUrl = options.baseUrl ?? APOLLO_BASE_URL;
|
|
54
72
|
const doFetch = options.fetchImpl ?? fetch;
|
|
@@ -60,14 +78,17 @@ var apolloSource = (options) => {
|
|
|
60
78
|
const res = await doFetch(`${baseUrl}${path}`, {
|
|
61
79
|
body: JSON.stringify(body),
|
|
62
80
|
headers,
|
|
63
|
-
method: "POST"
|
|
81
|
+
method: "POST",
|
|
82
|
+
signal: AbortSignal.timeout(30000)
|
|
64
83
|
});
|
|
65
84
|
if (res.status === 429)
|
|
66
85
|
throw new RateLimitError("apollo");
|
|
67
86
|
if (!res.ok)
|
|
68
|
-
|
|
69
|
-
const json = await res.json();
|
|
70
|
-
|
|
87
|
+
throw await providerFailure(res, path);
|
|
88
|
+
const json = await res.json().catch(() => null);
|
|
89
|
+
if (!isRecord(json))
|
|
90
|
+
throw new EngagementProviderError("apollo", 502, `invalid ${path} response`);
|
|
91
|
+
return json;
|
|
71
92
|
};
|
|
72
93
|
const normalizePerson = (person) => {
|
|
73
94
|
const org = isRecord(person.organization) ? person.organization : null;
|
|
@@ -100,33 +121,42 @@ var apolloSource = (options) => {
|
|
|
100
121
|
};
|
|
101
122
|
};
|
|
102
123
|
const matchById = async (id) => {
|
|
103
|
-
const json = await post("/v1/people/match", { id });
|
|
104
|
-
|
|
124
|
+
const json = await post("/api/v1/people/match", { id });
|
|
125
|
+
if (json.person !== null && !isRecord(json.person))
|
|
126
|
+
throw new EngagementProviderError("apollo", 502, "invalid person enrichment response");
|
|
127
|
+
const person = isRecord(json.person) ? json.person : null;
|
|
105
128
|
return person ? normalizePerson(person) : null;
|
|
106
129
|
};
|
|
107
130
|
const enrichPerson = async (query) => {
|
|
108
|
-
const json = await post("/v1/people/match", {
|
|
131
|
+
const json = await post("/api/v1/people/match", {
|
|
109
132
|
domain: query.domain,
|
|
110
133
|
email: query.email,
|
|
111
134
|
linkedin_url: query.linkedinUrl,
|
|
112
135
|
name: query.name,
|
|
113
136
|
organization_name: query.company
|
|
114
137
|
});
|
|
115
|
-
|
|
138
|
+
if (json.person !== null && !isRecord(json.person))
|
|
139
|
+
throw new EngagementProviderError("apollo", 502, "invalid person enrichment response");
|
|
140
|
+
const person = isRecord(json.person) ? json.person : null;
|
|
116
141
|
return person ? normalizePerson(person) : null;
|
|
117
142
|
};
|
|
118
143
|
const searchPeople = async (query) => {
|
|
119
144
|
const limit = query.limit ?? DEFAULT_SEARCH_LIMIT;
|
|
120
|
-
|
|
145
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100)
|
|
146
|
+
throw new RangeError("Apollo people limit must be an integer from 1 to 100");
|
|
147
|
+
const search = await post("/api/v1/mixed_people/api_search", {
|
|
121
148
|
page: 1,
|
|
122
149
|
per_page: limit,
|
|
123
150
|
...query.titles && query.titles.length > 0 ? { person_titles: query.titles } : {},
|
|
124
151
|
...query.domain ? { q_organization_domains_list: [query.domain] } : {},
|
|
125
152
|
...!query.domain && query.company ? { q_keywords: query.company } : {}
|
|
126
153
|
});
|
|
127
|
-
const searchRequests =
|
|
128
|
-
|
|
129
|
-
|
|
154
|
+
const searchRequests = 1;
|
|
155
|
+
if (!Array.isArray(search.people))
|
|
156
|
+
throw new EngagementProviderError("apollo", 502, "invalid people search response");
|
|
157
|
+
const ids = [
|
|
158
|
+
...new Set(search.people.map((person) => isRecord(person) ? str(person.id) : null).filter((id) => id !== null))
|
|
159
|
+
].slice(0, limit);
|
|
130
160
|
if (ids.length === 0) {
|
|
131
161
|
return { people: [], revealsAttempted: 0, searchRequests };
|
|
132
162
|
}
|
|
@@ -203,7 +233,7 @@ var apolloSource = (options) => {
|
|
|
203
233
|
if (res.status === 404 && !body)
|
|
204
234
|
return null;
|
|
205
235
|
if (!res.ok)
|
|
206
|
-
throw
|
|
236
|
+
throw await providerFailure(res, body ? "company search" : "company enrichment");
|
|
207
237
|
const value = await res.json();
|
|
208
238
|
if (!isRecord(value))
|
|
209
239
|
throw new EngagementProviderError("apollo", 502, "invalid company response");
|
|
@@ -289,5 +319,6 @@ var apolloSource = (options) => {
|
|
|
289
319
|
};
|
|
290
320
|
};
|
|
291
321
|
export {
|
|
322
|
+
ApolloProviderError,
|
|
292
323
|
apolloSource
|
|
293
324
|
};
|