salesprompter-cli 0.1.27 → 0.1.30
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/CODE_OF_CONDUCT.md +35 -0
- package/CONTRIBUTING.md +89 -0
- package/README.md +29 -1
- package/SECURITY.md +35 -0
- package/dist/cli.js +1213 -62
- package/dist/domainfinder.js +132 -0
- package/dist/linkedin-companies.js +3 -3
- package/dist/linkedin-products.js +2 -2
- package/dist/linkedin-session-contracts.js +3 -0
- package/dist/linkedin-session.js +8 -9
- package/dist/vendor/salesprompter-shared/extension-session-contracts.js +29 -0
- package/dist/vendor/salesprompter-shared/linkedin-session.js +22 -0
- package/dist/vendor/salesprompter-shared/phantombuster-contracts.js +16 -0
- package/dist/vendor/salesprompter-shared/session-vault-contracts.js +17 -0
- package/package.json +16 -4
- package/dist/hunter-emails.js +0 -291
package/dist/domainfinder.js
CHANGED
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
const DOMAIN_BLACKLIST = new Set(["linkedin.com", "bit.ly", "linktr.ee", "facebook.com"]);
|
|
2
|
+
const COMPANY_NAME_STOPWORDS = new Set([
|
|
3
|
+
"group",
|
|
4
|
+
"gmbh",
|
|
5
|
+
"ag",
|
|
6
|
+
"kg",
|
|
7
|
+
"co",
|
|
8
|
+
"company",
|
|
9
|
+
"holding",
|
|
10
|
+
"holdings",
|
|
11
|
+
"solutions",
|
|
12
|
+
"systems",
|
|
13
|
+
"services",
|
|
14
|
+
"international",
|
|
15
|
+
"global",
|
|
16
|
+
"the",
|
|
17
|
+
"und",
|
|
18
|
+
"and",
|
|
19
|
+
"de",
|
|
20
|
+
"of"
|
|
21
|
+
]);
|
|
2
22
|
function marketCountries(market) {
|
|
3
23
|
if (market === "dach") {
|
|
4
24
|
return ["DE", "AT", "CH"];
|
|
@@ -39,6 +59,90 @@ function rootDomain(value) {
|
|
|
39
59
|
}
|
|
40
60
|
return parts.slice(-2).join(".");
|
|
41
61
|
}
|
|
62
|
+
function domainLabel(value) {
|
|
63
|
+
const root = rootDomain(value);
|
|
64
|
+
if (!root) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return root.split(".")[0] ?? null;
|
|
68
|
+
}
|
|
69
|
+
function companyNameTokens(companyName) {
|
|
70
|
+
return (companyName ?? "")
|
|
71
|
+
.toLowerCase()
|
|
72
|
+
.replace(/[^a-z0-9]+/g, " ")
|
|
73
|
+
.split(/\s+/)
|
|
74
|
+
.map((token) => token.trim())
|
|
75
|
+
.filter((token) => token.length >= 3 && !COMPANY_NAME_STOPWORDS.has(token));
|
|
76
|
+
}
|
|
77
|
+
function domainCompanyMatchScore(domain, companyName) {
|
|
78
|
+
const label = domainLabel(domain);
|
|
79
|
+
if (!label) {
|
|
80
|
+
return -1;
|
|
81
|
+
}
|
|
82
|
+
const normalizedLabel = label.replace(/[^a-z0-9]/g, "");
|
|
83
|
+
if (normalizedLabel.length === 0) {
|
|
84
|
+
return -1;
|
|
85
|
+
}
|
|
86
|
+
const tokens = companyNameTokens(companyName);
|
|
87
|
+
if (tokens.length === 0) {
|
|
88
|
+
return normalizedLabel.length;
|
|
89
|
+
}
|
|
90
|
+
let score = 0;
|
|
91
|
+
for (const token of tokens) {
|
|
92
|
+
const normalizedToken = token.replace(/[^a-z0-9]/g, "");
|
|
93
|
+
if (normalizedToken.length === 0) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (normalizedLabel === normalizedToken) {
|
|
97
|
+
score += 100 + normalizedToken.length;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (normalizedLabel.startsWith(normalizedToken)) {
|
|
101
|
+
score += 60 + normalizedToken.length;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (normalizedLabel.includes(normalizedToken)) {
|
|
105
|
+
score += 40 + normalizedToken.length;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (normalizedToken.startsWith(normalizedLabel) && normalizedLabel.length >= 4) {
|
|
109
|
+
score += 20 + normalizedLabel.length;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return score;
|
|
113
|
+
}
|
|
114
|
+
function chooseBetterCompanyMatchCandidate(candidates, baselineDomain) {
|
|
115
|
+
const baselineScore = domainCompanyMatchScore(baselineDomain, candidates[0]?.companyName);
|
|
116
|
+
const ranked = [...candidates]
|
|
117
|
+
.filter((candidate) => normalizeDomain(candidate.domain) !== null)
|
|
118
|
+
.filter((candidate) => !isBlacklistedDomain(candidate.domain))
|
|
119
|
+
.filter((candidate) => candidate.source !== "linkedin")
|
|
120
|
+
.sort((a, b) => {
|
|
121
|
+
const scoreDelta = domainCompanyMatchScore(b.domain, b.companyName) -
|
|
122
|
+
domainCompanyMatchScore(a.domain, a.companyName);
|
|
123
|
+
if (scoreDelta !== 0) {
|
|
124
|
+
return scoreDelta;
|
|
125
|
+
}
|
|
126
|
+
const hunterDelta = (b.hunterEmailCount ?? -1) - (a.hunterEmailCount ?? -1);
|
|
127
|
+
if (hunterDelta !== 0) {
|
|
128
|
+
return hunterDelta;
|
|
129
|
+
}
|
|
130
|
+
return (a.source ?? "").localeCompare(b.source ?? "");
|
|
131
|
+
});
|
|
132
|
+
const best = ranked[0] ?? null;
|
|
133
|
+
if (!best) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
const bestScore = domainCompanyMatchScore(best.domain, best.companyName);
|
|
137
|
+
const hasPositiveHunterSignal = (best.hunterEmailCount ?? 0) > 0;
|
|
138
|
+
if (hasPositiveHunterSignal && bestScore > baselineScore) {
|
|
139
|
+
return {
|
|
140
|
+
...best,
|
|
141
|
+
domain: normalizeDomain(best.domain)
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
42
146
|
function isBlacklistedDomain(value) {
|
|
43
147
|
const normalized = normalizeDomain(value);
|
|
44
148
|
if (!normalized) {
|
|
@@ -109,6 +213,20 @@ export function chooseBestDomain(candidates) {
|
|
|
109
213
|
const nonNullCandidates = candidates.filter((candidate) => normalizeDomain(candidate.domain) !== null);
|
|
110
214
|
const linkedinDomain = normalizeDomain(candidates[0].linkedinDomain);
|
|
111
215
|
const linkedinWebsite = normalizeDomain(candidates[0].linkedinWebsite);
|
|
216
|
+
const betterThanLinkedinDomain = linkedinDomain
|
|
217
|
+
? chooseBetterCompanyMatchCandidate(nonNullCandidates, linkedinDomain)
|
|
218
|
+
: null;
|
|
219
|
+
const betterThanLinkedinWebsite = !linkedinDomain && linkedinWebsite
|
|
220
|
+
? chooseBetterCompanyMatchCandidate(nonNullCandidates, linkedinWebsite)
|
|
221
|
+
: null;
|
|
222
|
+
if (betterThanLinkedinDomain) {
|
|
223
|
+
return {
|
|
224
|
+
companyKey,
|
|
225
|
+
selected: betterThanLinkedinDomain,
|
|
226
|
+
reason: "better-company-match",
|
|
227
|
+
candidates
|
|
228
|
+
};
|
|
229
|
+
}
|
|
112
230
|
if (linkedinDomain && !isBlacklistedDomain(linkedinDomain)) {
|
|
113
231
|
const selectedCandidate = nonNullCandidates.find((candidate) => normalizeDomain(candidate.domain) === linkedinDomain) ?? {
|
|
114
232
|
...candidates[0],
|
|
@@ -128,6 +246,14 @@ export function chooseBestDomain(candidates) {
|
|
|
128
246
|
candidates
|
|
129
247
|
};
|
|
130
248
|
}
|
|
249
|
+
if (betterThanLinkedinWebsite) {
|
|
250
|
+
return {
|
|
251
|
+
companyKey,
|
|
252
|
+
selected: betterThanLinkedinWebsite,
|
|
253
|
+
reason: "better-company-match",
|
|
254
|
+
candidates
|
|
255
|
+
};
|
|
256
|
+
}
|
|
131
257
|
if (linkedinWebsite && !isBlacklistedDomain(linkedinWebsite)) {
|
|
132
258
|
const websiteRoot = rootDomain(linkedinWebsite);
|
|
133
259
|
const selectedCandidate = nonNullCandidates.find((candidate) => rootDomain(candidate.domain) === websiteRoot) ?? {
|
|
@@ -234,6 +360,9 @@ export function compareDomainSelectionStrategies(candidates) {
|
|
|
234
360
|
if (improved.reason === "linkedin-domain" || improved.reason === "linkedin-website") {
|
|
235
361
|
flags.push("preferred-linkedin");
|
|
236
362
|
}
|
|
363
|
+
if (improved.reason === "better-company-match") {
|
|
364
|
+
flags.push("preferred-hunter-company-match");
|
|
365
|
+
}
|
|
237
366
|
for (const flag of flags) {
|
|
238
367
|
changeFlags[flag] = (changeFlags[flag] ?? 0) + 1;
|
|
239
368
|
}
|
|
@@ -310,6 +439,9 @@ export function auditDomainDecisions(decisions) {
|
|
|
310
439
|
if (decision.reason === "fallback-first-non-null") {
|
|
311
440
|
flags.push("fallback-selected");
|
|
312
441
|
}
|
|
442
|
+
if (decision.reason === "better-company-match") {
|
|
443
|
+
flags.push("better-company-match-selected");
|
|
444
|
+
}
|
|
313
445
|
if (decision.reason === "highest-hunter-count") {
|
|
314
446
|
flags.push("hunter-selected");
|
|
315
447
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { load } from "cheerio";
|
|
2
2
|
import { BigQuery } from "@google-cloud/bigquery";
|
|
3
|
+
import { DEFAULT_LINKEDIN_SCRAPER_USER_AGENT } from "./linkedin-session-contracts.js";
|
|
3
4
|
const DEFAULT_LINKEDIN_BASE_URL = "https://www.linkedin.com";
|
|
4
|
-
const DEFAULT_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36";
|
|
5
5
|
const DEFAULT_RAPIDAPI_LINKEDIN_COMPANY_HOST = "web-scraping-api2.p.rapidapi.com";
|
|
6
6
|
const DEFAULT_RAPIDAPI_LINKEDIN_COMPANY_ENDPOINT = "https://web-scraping-api2.p.rapidapi.com/get-company-by-linkedinurl";
|
|
7
7
|
const DEFAULT_BIGQUERY_PROJECT_ID = process.env.BQ_PROJECT_ID ?? process.env.GOOGLE_CLOUD_PROJECT ?? process.env.GCLOUD_PROJECT ?? "icpidentifier";
|
|
@@ -429,7 +429,7 @@ export async function fetchLinkedInCompanyBackfillCandidates(bigQuery, clientId,
|
|
|
429
429
|
async function fetchHtml(url) {
|
|
430
430
|
const response = await fetch(url, {
|
|
431
431
|
headers: {
|
|
432
|
-
"User-Agent":
|
|
432
|
+
"User-Agent": DEFAULT_LINKEDIN_SCRAPER_USER_AGENT
|
|
433
433
|
}
|
|
434
434
|
});
|
|
435
435
|
return {
|
|
@@ -446,7 +446,7 @@ export async function scrapeLinkedInCompany(candidate) {
|
|
|
446
446
|
headers: {
|
|
447
447
|
"x-rapidapi-key": rapidApiConfig.apiKey,
|
|
448
448
|
"x-rapidapi-host": rapidApiConfig.host,
|
|
449
|
-
"User-Agent":
|
|
449
|
+
"User-Agent": DEFAULT_LINKEDIN_SCRAPER_USER_AGENT
|
|
450
450
|
}
|
|
451
451
|
});
|
|
452
452
|
const text = await response.text();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { load } from "cheerio";
|
|
2
|
+
import { DEFAULT_LINKEDIN_SCRAPER_USER_AGENT } from "./linkedin-session-contracts.js";
|
|
2
3
|
const DEFAULT_LINKEDIN_BASE_URL = "https://www.linkedin.com";
|
|
3
|
-
const DEFAULT_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36";
|
|
4
4
|
function normalizeWhitespace(value) {
|
|
5
5
|
return (value ?? "").replace(/\s+/g, " ").trim();
|
|
6
6
|
}
|
|
@@ -525,7 +525,7 @@ export function createLinkedInHtmlFetcher(fetchImpl = fetch) {
|
|
|
525
525
|
return async (url) => {
|
|
526
526
|
const response = await fetchImpl(url, {
|
|
527
527
|
headers: {
|
|
528
|
-
"User-Agent":
|
|
528
|
+
"User-Agent": DEFAULT_LINKEDIN_SCRAPER_USER_AGENT,
|
|
529
529
|
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
530
530
|
},
|
|
531
531
|
redirect: "follow"
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export * from "./vendor/salesprompter-shared/linkedin-session.js";
|
|
2
|
+
export { DEFAULT_LINKEDIN_USER_AGENT as DEFAULT_LINKEDIN_SESSION_USER_AGENT } from "./vendor/salesprompter-shared/linkedin-session.js";
|
|
3
|
+
export const DEFAULT_LINKEDIN_SCRAPER_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36";
|
package/dist/linkedin-session.js
CHANGED
|
@@ -3,10 +3,10 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
3
3
|
import { dirname, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { createClient } from "@supabase/supabase-js";
|
|
6
|
+
import { DEFAULT_LINKEDIN_SESSION_USER_AGENT, formatLiAtCookieHeader } from "./linkedin-session-contracts.js";
|
|
6
7
|
const COOKIE_VAULT_KEY_CONTEXT = "salesprompter:linkedin-session-cookie:v1";
|
|
7
8
|
const AES_256_KEY_BYTES = 32;
|
|
8
9
|
const REQUEST_TIMEOUT_MS = 20_000;
|
|
9
|
-
const DEFAULT_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36";
|
|
10
10
|
const MAX_COOKIE_VALIDATION_ATTEMPTS = 8;
|
|
11
11
|
const COOKIE_VALIDATION_TIMEOUT_MS = 75_000;
|
|
12
12
|
const COOKIE_PROBE_TIMEOUT_MS = 8_000;
|
|
@@ -68,7 +68,7 @@ function parseDotEnvFile(filePath) {
|
|
|
68
68
|
envFileCache.set(filePath, parsed);
|
|
69
69
|
return parsed;
|
|
70
70
|
}
|
|
71
|
-
function resolveConfiguredEnvValue(env, key) {
|
|
71
|
+
export function resolveConfiguredEnvValue(env, key) {
|
|
72
72
|
const directValue = env[key]?.trim() || "";
|
|
73
73
|
if (directValue.length > 0) {
|
|
74
74
|
return directValue;
|
|
@@ -230,6 +230,7 @@ export async function recordLinkedInSessionCookieAudit(supabase, input) {
|
|
|
230
230
|
last_sales_navigator_status: input.salesNavigatorStatus,
|
|
231
231
|
last_recruiter_status: input.recruiterStatus,
|
|
232
232
|
last_product_class: input.productClass,
|
|
233
|
+
last_ingested_source: input.source,
|
|
233
234
|
last_validation_error: input.validationError ?? null,
|
|
234
235
|
last_validation_details: input.details ?? {}
|
|
235
236
|
})
|
|
@@ -270,6 +271,7 @@ async function listLinkedInSessionCookieCandidates(supabase, options) {
|
|
|
270
271
|
"session_cookie_auth_tag",
|
|
271
272
|
"last_user_email",
|
|
272
273
|
"last_user_handle",
|
|
274
|
+
"last_ingested_source",
|
|
273
275
|
"is_active",
|
|
274
276
|
"inactive_reason",
|
|
275
277
|
"last_validation_at",
|
|
@@ -338,6 +340,7 @@ async function buildClaimedLinkedInSessionCookieFromRow(supabase, row, source, e
|
|
|
338
340
|
sessionCookie,
|
|
339
341
|
userEmail: claimedIdentity.userEmail,
|
|
340
342
|
userHandle: claimedIdentity.userHandle,
|
|
343
|
+
lastIngestedSource: row.last_ingested_source ?? null,
|
|
341
344
|
claimStrategy: options?.claimStrategy,
|
|
342
345
|
previousInactiveReason: row.inactive_reason ?? null
|
|
343
346
|
};
|
|
@@ -513,10 +516,6 @@ function extractTitle(body) {
|
|
|
513
516
|
const match = body.match(/<title[^>]*>([^<]+)<\/title>/i);
|
|
514
517
|
return match ? match[1].trim().replace(/\s+/g, " ") : null;
|
|
515
518
|
}
|
|
516
|
-
function normalizeLiAtCookie(sessionCookie) {
|
|
517
|
-
const trimmed = sessionCookie.trim();
|
|
518
|
-
return trimmed.startsWith("li_at=") ? trimmed.slice("li_at=".length) : trimmed;
|
|
519
|
-
}
|
|
520
519
|
function includesAny(value, patterns) {
|
|
521
520
|
const normalized = value ?? "";
|
|
522
521
|
return patterns.some((pattern) => pattern.test(normalized));
|
|
@@ -558,7 +557,7 @@ function hasSearchEntitlementSignals(result) {
|
|
|
558
557
|
]));
|
|
559
558
|
}
|
|
560
559
|
export async function fetchHtmlWithSessionCookie(url, sessionCookie, options) {
|
|
561
|
-
const
|
|
560
|
+
const cookieHeader = formatLiAtCookieHeader(sessionCookie);
|
|
562
561
|
const redirectChain = [];
|
|
563
562
|
let currentUrl = url;
|
|
564
563
|
const seenUrls = new Set([url]);
|
|
@@ -571,8 +570,8 @@ export async function fetchHtmlWithSessionCookie(url, sessionCookie, options) {
|
|
|
571
570
|
redirect: "manual",
|
|
572
571
|
signal: controller.signal,
|
|
573
572
|
headers: {
|
|
574
|
-
Cookie:
|
|
575
|
-
"User-Agent": options?.userAgent ??
|
|
573
|
+
Cookie: cookieHeader ?? "",
|
|
574
|
+
"User-Agent": options?.userAgent ?? DEFAULT_LINKEDIN_SESSION_USER_AGENT,
|
|
576
575
|
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
577
576
|
"Accept-Language": "en-US,en;q=0.9",
|
|
578
577
|
"Cache-Control": "no-cache",
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const linkedInCapturedSessionSchema = z.object({
|
|
3
|
+
sessionCookie: z.string().min(1),
|
|
4
|
+
csrfToken: z.string().min(1),
|
|
5
|
+
linkedInIdentity: z.string().min(1),
|
|
6
|
+
userAgent: z.string().min(1),
|
|
7
|
+
requestId: z.string().min(1).nullable().optional(),
|
|
8
|
+
timestamp: z.string().min(1).nullable().optional(),
|
|
9
|
+
extractedFrom: z.string().min(1).nullable().optional(),
|
|
10
|
+
});
|
|
11
|
+
export const extensionSessionSyncPayloadSchema = z.object({
|
|
12
|
+
sessionCookie: z.string().min(1),
|
|
13
|
+
csrfToken: z.string().min(1),
|
|
14
|
+
linkedInIdentity: z.string().min(1),
|
|
15
|
+
userAgent: z.string().min(1),
|
|
16
|
+
requestId: z.string().min(1).nullable().optional(),
|
|
17
|
+
userEmail: z.string().email().nullable().optional(),
|
|
18
|
+
userFullName: z.string().min(1).nullable().optional(),
|
|
19
|
+
userHandle: z.string().min(1).nullable().optional(),
|
|
20
|
+
});
|
|
21
|
+
export const extensionSessionSyncSuccessSchema = z.object({
|
|
22
|
+
success: z.literal(true),
|
|
23
|
+
result: z.unknown().nullable().optional(),
|
|
24
|
+
persisted: z.boolean().nullable().optional(),
|
|
25
|
+
storageReady: z.boolean().nullable().optional(),
|
|
26
|
+
});
|
|
27
|
+
export const extensionSessionSyncErrorSchema = z.object({
|
|
28
|
+
error: z.string().min(1),
|
|
29
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const DEFAULT_LINKEDIN_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36';
|
|
2
|
+
function normalizeWhitespace(value) {
|
|
3
|
+
return (value ?? '').replace(/\s+/g, ' ').trim();
|
|
4
|
+
}
|
|
5
|
+
export function extractLiAtCookieValue(sessionCookie) {
|
|
6
|
+
const trimmed = normalizeWhitespace(sessionCookie);
|
|
7
|
+
if (!trimmed) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
const liAtMatch = trimmed.match(/(?:^|[;\s])li_at="?([^";]+)"?/i);
|
|
11
|
+
if (liAtMatch?.[1]) {
|
|
12
|
+
return liAtMatch[1];
|
|
13
|
+
}
|
|
14
|
+
return trimmed.startsWith('li_at=') ? trimmed.slice('li_at='.length) : trimmed;
|
|
15
|
+
}
|
|
16
|
+
export function normalizeLiAtCookie(sessionCookie) {
|
|
17
|
+
return extractLiAtCookieValue(sessionCookie);
|
|
18
|
+
}
|
|
19
|
+
export function formatLiAtCookieHeader(sessionCookie) {
|
|
20
|
+
const normalized = normalizeLiAtCookie(sessionCookie);
|
|
21
|
+
return normalized ? `li_at=${normalized}` : null;
|
|
22
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const DEFAULT_PHANTOMBUSTER_API_BASE = 'https://api.phantombuster.com/api/v2';
|
|
3
|
+
export const DEFAULT_LINKEDIN_COMPANY_SCRAPER_AGENT_ID = '3415615142546934';
|
|
4
|
+
export const LINKEDIN_COMPANY_SCRAPER_COLUMN_NAME = 'Url';
|
|
5
|
+
export const linkedInCompanyScraperLaunchOptionsSchema = z.object({
|
|
6
|
+
spreadsheetUrl: z.string().url(),
|
|
7
|
+
columnName: z.string().min(1).nullable().optional(),
|
|
8
|
+
webhookUrl: z.string().url().nullable().optional(),
|
|
9
|
+
sessionCookie: z.string().min(1).nullable().optional(),
|
|
10
|
+
userAgent: z.string().min(1).nullable().optional(),
|
|
11
|
+
companiesPerLaunch: z.number().int().positive().nullable().optional(),
|
|
12
|
+
delayBetween: z.number().nonnegative().nullable().optional(),
|
|
13
|
+
});
|
|
14
|
+
export const phantombusterLaunchResponseSchema = z.object({
|
|
15
|
+
containerId: z.string().min(1),
|
|
16
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const linkedInSessionSelectionSourceSchema = z.enum([
|
|
3
|
+
'cli_linkedin_company_backfill',
|
|
4
|
+
'cli_linkedin_company_backfill_preflight',
|
|
5
|
+
'cli_linkedin_company_backfill_invalid_session',
|
|
6
|
+
'cli_linkedin_company_backfill_decrypt_failure',
|
|
7
|
+
'extension_user_profile',
|
|
8
|
+
'extension_user_profile_li_at_fallback',
|
|
9
|
+
'operator_env_seed',
|
|
10
|
+
'pipedream_raw_manual_seed',
|
|
11
|
+
]);
|
|
12
|
+
export const linkedInSessionInactiveReasonSchema = z.enum([
|
|
13
|
+
'linkedin_session_invalid',
|
|
14
|
+
'decrypt_failed',
|
|
15
|
+
'excluded_linkedin_session_identity',
|
|
16
|
+
'quarantined_browser_unverified',
|
|
17
|
+
]);
|
package/package.json
CHANGED
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "salesprompter-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.30",
|
|
4
4
|
"description": "Sales workflow CLI for guided lead generation, enrichment, scoring, and sync.",
|
|
5
|
+
"author": "Daniel Sinewe <hello@danielsinewe.com>",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"bin": {
|
|
7
8
|
"salesprompter": "dist/cli.js"
|
|
8
9
|
},
|
|
9
10
|
"files": [
|
|
10
11
|
"dist",
|
|
11
|
-
"README.md"
|
|
12
|
+
"README.md",
|
|
13
|
+
"CONTRIBUTING.md",
|
|
14
|
+
"CODE_OF_CONDUCT.md",
|
|
15
|
+
"SECURITY.md"
|
|
12
16
|
],
|
|
13
17
|
"scripts": {
|
|
14
18
|
"build": "tsc -p tsconfig.json",
|
|
15
19
|
"build:docs:site": "node ./scripts/build-docs-site.mjs",
|
|
16
20
|
"check": "tsc --noEmit -p tsconfig.json",
|
|
21
|
+
"supabase:migrations:check": "node ./scripts/check-app-supabase-migrations.mjs",
|
|
22
|
+
"supabase:migrations:sync": "node ./scripts/sync-app-supabase-migrations.mjs",
|
|
23
|
+
"shared:sync": "node ./scripts/sync-shared.mjs",
|
|
17
24
|
"docs:dev": "mint dev",
|
|
18
25
|
"docs:broken-links": "mint broken-links",
|
|
19
26
|
"docs:a11y": "mint a11y",
|
|
@@ -42,12 +49,17 @@
|
|
|
42
49
|
"tooling"
|
|
43
50
|
],
|
|
44
51
|
"homepage": "https://salesprompter.ai/docs",
|
|
52
|
+
"funding": {
|
|
53
|
+
"type": "other",
|
|
54
|
+
"url": "https://salesprompter.ai"
|
|
55
|
+
},
|
|
45
56
|
"repository": {
|
|
46
57
|
"type": "git",
|
|
47
58
|
"url": "git+https://github.com/danielsinewe/salesprompter-cli.git"
|
|
48
59
|
},
|
|
49
60
|
"bugs": {
|
|
50
|
-
"url": "https://github.com/danielsinewe/salesprompter-cli/issues"
|
|
61
|
+
"url": "https://github.com/danielsinewe/salesprompter-cli/issues",
|
|
62
|
+
"email": "hello@danielsinewe.com"
|
|
51
63
|
},
|
|
52
64
|
"license": "MIT",
|
|
53
65
|
"dependencies": {
|
|
@@ -64,7 +76,7 @@
|
|
|
64
76
|
"@types/node": "^24.3.0",
|
|
65
77
|
"gray-matter": "^4.0.3",
|
|
66
78
|
"marked": "^16.3.0",
|
|
67
|
-
"mint": "^4.2.
|
|
79
|
+
"mint": "^4.2.216",
|
|
68
80
|
"typescript": "^5.9.2"
|
|
69
81
|
}
|
|
70
82
|
}
|