orangeslice 1.7.18 → 1.7.20
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/api.js +15 -9
- package/dist/expansion.js +20 -81
- package/package.json +1 -1
package/dist/api.js
CHANGED
|
@@ -14,6 +14,17 @@ const DEFAULT_POLL_INTERVAL_MS = 1000;
|
|
|
14
14
|
function sleep(ms) {
|
|
15
15
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
16
16
|
}
|
|
17
|
+
async function readResponseBody(res) {
|
|
18
|
+
const text = await res.text();
|
|
19
|
+
if (!text)
|
|
20
|
+
return null;
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(text);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return text;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
17
28
|
function asErrorMessage(body) {
|
|
18
29
|
if (!body || typeof body !== "object")
|
|
19
30
|
return undefined;
|
|
@@ -74,7 +85,7 @@ async function pollUntilComplete(baseUrl, functionId, pending) {
|
|
|
74
85
|
while (Date.now() < timeoutAt) {
|
|
75
86
|
await sleep(pollAfterMs);
|
|
76
87
|
const res = await fetch(pollUrl, { method: "GET", headers: { "Content-Type": "application/json" } });
|
|
77
|
-
const data =
|
|
88
|
+
const data = await readResponseBody(res);
|
|
78
89
|
if (isPendingResponse(data) || res.status === 202) {
|
|
79
90
|
const next = data.pollAfterMs;
|
|
80
91
|
pollAfterMs = typeof next === "number" && next > 0 ? next : DEFAULT_POLL_INTERVAL_MS;
|
|
@@ -103,16 +114,11 @@ async function post(functionId, payload, options = {}) {
|
|
|
103
114
|
});
|
|
104
115
|
if (!res.ok) {
|
|
105
116
|
let message = `${res.status}`;
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
message = asErrorMessage(data) || JSON.stringify(data);
|
|
109
|
-
}
|
|
110
|
-
catch {
|
|
111
|
-
message = await res.text();
|
|
112
|
-
}
|
|
117
|
+
const data = await readResponseBody(res);
|
|
118
|
+
message = asErrorMessage(data) || (typeof data === "string" ? data : JSON.stringify(data));
|
|
113
119
|
throw new Error(`[orangeslice] ${functionId}: ${res.status} ${message}`);
|
|
114
120
|
}
|
|
115
|
-
const data =
|
|
121
|
+
const data = await readResponseBody(res);
|
|
116
122
|
if (isPendingResponse(data)) {
|
|
117
123
|
return pollUntilComplete(baseUrl, functionId, data);
|
|
118
124
|
}
|
package/dist/expansion.js
CHANGED
|
@@ -22,15 +22,8 @@ function extractLinkedinUsername(url) {
|
|
|
22
22
|
const slug = match[1].trim();
|
|
23
23
|
return slug.length > 0 ? slug : undefined;
|
|
24
24
|
}
|
|
25
|
-
function extractLinkedinCompanySlug(url) {
|
|
26
|
-
const match = url.match(/linkedin\.com\/company\/([^/?#]+)/i);
|
|
27
|
-
if (!match?.[1])
|
|
28
|
-
return undefined;
|
|
29
|
-
const slug = match[1].trim().toLowerCase();
|
|
30
|
-
return slug.length > 0 ? slug : undefined;
|
|
31
|
-
}
|
|
32
25
|
async function personLinkedinFindUrl(params) {
|
|
33
|
-
return (0, api_1.post)("linkedin/find-profile-url", params
|
|
26
|
+
return (0, api_1.post)("linkedin/find-profile-url", params);
|
|
34
27
|
}
|
|
35
28
|
async function personLinkedinEnrich(params) {
|
|
36
29
|
const url = typeof params.url === "string" ? params.url.trim() : "";
|
|
@@ -81,7 +74,22 @@ async function personContactGet(params) {
|
|
|
81
74
|
return (0, api_1.post)("contact", params);
|
|
82
75
|
}
|
|
83
76
|
async function companyLinkedinFindUrl(params) {
|
|
84
|
-
|
|
77
|
+
const companyName = typeof params.companyName === "string" && params.companyName.trim().length > 0
|
|
78
|
+
? params.companyName.trim()
|
|
79
|
+
: typeof params.name === "string" && params.name.trim().length > 0
|
|
80
|
+
? params.name.trim()
|
|
81
|
+
: undefined;
|
|
82
|
+
const website = typeof params.website === "string" && params.website.trim().length > 0
|
|
83
|
+
? params.website.trim()
|
|
84
|
+
: typeof params.domain === "string" && params.domain.trim().length > 0
|
|
85
|
+
? params.domain.trim()
|
|
86
|
+
: undefined;
|
|
87
|
+
const payload = {
|
|
88
|
+
...params,
|
|
89
|
+
...(companyName ? { companyName } : {}),
|
|
90
|
+
...(website ? { website } : {}),
|
|
91
|
+
};
|
|
92
|
+
return (0, api_1.post)("find-linkedin-company-url", payload);
|
|
85
93
|
}
|
|
86
94
|
async function companyLinkedinEnrich(params) {
|
|
87
95
|
const shorthand = typeof params.shorthand === "string" ? params.shorthand.trim() : "";
|
|
@@ -106,78 +114,9 @@ async function companyLinkedinEnrich(params) {
|
|
|
106
114
|
return data.rows?.[0] ?? null;
|
|
107
115
|
}
|
|
108
116
|
async function companyGetEmployeesFromLinkedin(params) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const titleVariations = Array.isArray(params.titleVariations)
|
|
113
|
-
? params.titleVariations
|
|
114
|
-
.filter((v) => typeof v === "string" && v.trim().length > 0)
|
|
115
|
-
.map((v) => v.trim())
|
|
116
|
-
: [];
|
|
117
|
-
const titleSqlFilterRaw = typeof params.titleSqlFilter === "string" ? params.titleSqlFilter.trim() : "";
|
|
118
|
-
const titleSqlFilter = titleSqlFilterRaw.replace(/\bpos\./g, "lp.");
|
|
119
|
-
const limit = typeof params.limit === "number" && Number.isFinite(params.limit)
|
|
120
|
-
? Math.max(1, Math.min(200, Math.floor(params.limit)))
|
|
121
|
-
: 50;
|
|
122
|
-
const offset = typeof params.offset === "number" && Number.isFinite(params.offset) && params.offset >= 0
|
|
123
|
-
? Math.floor(params.offset)
|
|
124
|
-
: 0;
|
|
125
|
-
const minConnections = typeof params.minConnections === "number" && Number.isFinite(params.minConnections)
|
|
126
|
-
? Math.max(0, Math.floor(params.minConnections))
|
|
127
|
-
: 20;
|
|
128
|
-
const usOnly = params.usOnly === undefined ? true : params.usOnly === true;
|
|
129
|
-
if (!companySlug) {
|
|
130
|
-
throw new Error("[orangeslice] company.getEmployeesFromLinkedin: provide linkedinUrl or companySlug");
|
|
131
|
-
}
|
|
132
|
-
const filters = [
|
|
133
|
-
`lp.linkedin_company_id = tc.linkedin_company_id`,
|
|
134
|
-
`COALESCE(lp.connections, 0) >= ${minConnections}`,
|
|
135
|
-
];
|
|
136
|
-
if (usOnly)
|
|
137
|
-
filters.push(`COALESCE(lp.location_country_code, '') = 'US'`);
|
|
138
|
-
if (titleSqlFilter) {
|
|
139
|
-
filters.push(`(${titleSqlFilter})`);
|
|
140
|
-
}
|
|
141
|
-
else if (titleVariations.length > 0) {
|
|
142
|
-
const or = titleVariations
|
|
143
|
-
.map((title) => `lower(COALESCE(lp.title, '')) LIKE ${sqlString(`%${title.toLowerCase()}%`)}`)
|
|
144
|
-
.join(" OR ");
|
|
145
|
-
filters.push(`(${or})`);
|
|
146
|
-
}
|
|
147
|
-
const sql = `WITH tc AS (
|
|
148
|
-
SELECT linkedin_company_id
|
|
149
|
-
FROM linkedin_company_slug
|
|
150
|
-
WHERE slug_key64 = key64(${sqlString(companySlug)})
|
|
151
|
-
LIMIT 1
|
|
152
|
-
)
|
|
153
|
-
SELECT
|
|
154
|
-
lp.first_name AS lp_first_name,
|
|
155
|
-
lp.last_name AS lp_last_name,
|
|
156
|
-
lp.formatted_name AS lp_formatted_name,
|
|
157
|
-
lp.headline AS lp_headline,
|
|
158
|
-
lp.location_name AS lp_location_name,
|
|
159
|
-
COALESCE(lp.public_profile_url, lp.standard_profile_url) AS lp_public_profile_url,
|
|
160
|
-
lp.title AS lp_title,
|
|
161
|
-
lp.org AS lp_company_name,
|
|
162
|
-
lp.connections AS lp_connections,
|
|
163
|
-
COUNT(*) OVER() AS _total
|
|
164
|
-
FROM linkedin_profile lp
|
|
165
|
-
JOIN tc ON true
|
|
166
|
-
WHERE ${filters.join(" AND ")}
|
|
167
|
-
ORDER BY lp.connections DESC NULLS LAST, lp.updated_at DESC NULLS LAST
|
|
168
|
-
LIMIT ${limit} OFFSET ${offset}`;
|
|
169
|
-
const data = await (0, api_1.post)("b2b", { sql }, { direct: true });
|
|
170
|
-
const rows = data.rows ?? [];
|
|
171
|
-
const total = rows.length > 0 ? Number(rows[0]._total ?? 0) : 0;
|
|
172
|
-
const employees = rows.map((row) => {
|
|
173
|
-
const { _total, ...rest } = row;
|
|
174
|
-
return rest;
|
|
175
|
-
});
|
|
176
|
-
return {
|
|
177
|
-
employees,
|
|
178
|
-
nextPage: employees.length === limit && offset + limit < total ? offset + limit : null,
|
|
179
|
-
totalResults: total,
|
|
180
|
-
};
|
|
117
|
+
// Route through the dedicated backend function, which uses optimized query plans.
|
|
118
|
+
// The raw SQL fallback can hit 60s statement timeouts on large companies.
|
|
119
|
+
return (0, api_1.post)("b2b-get-employees-for-company", params);
|
|
181
120
|
}
|
|
182
121
|
async function geoParseAddress(params) {
|
|
183
122
|
return (0, api_1.post)("geo", params);
|