salesprompter-cli 0.1.37 → 0.1.38

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.
Files changed (2) hide show
  1. package/dist/cli.js +93 -11
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { spawn } from "node:child_process";
3
+ import { createHash } from "node:crypto";
3
4
  import { access, appendFile, mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
4
5
  import { createRequire } from "node:module";
5
6
  import os from "node:os";
@@ -25,7 +26,8 @@ import { InstantlySyncProvider } from "./instantly.js";
25
26
  import { backfillLinkedInCompanies } from "./linkedin-companies.js";
26
27
  import { parseLinkedInCompanyPage } from "./linkedin-companies.js";
27
28
  import { crawlLinkedInProductCategory } from "./linkedin-products.js";
28
- import { claimValidatedSalesNavigatorSessionCookieForCli, createLinkedInSessionSupabaseClient, resolveConfiguredEnvValue } from "./linkedin-session.js";
29
+ import { claimValidatedSalesNavigatorSessionCookieForCli, createLinkedInSessionSupabaseClient, probeSalesNavigatorSearchSession, resolveConfiguredEnvValue } from "./linkedin-session.js";
30
+ import { extractLiAtCookieValue } from "./linkedin-session-contracts.js";
29
31
  import { buildLeadlistsFunnelQueries } from "./leadlists-funnel.js";
30
32
  import { readJsonFile, splitCsv, writeJsonFile, writeTextFile } from "./io.js";
31
33
  import { buildSalesNavigatorCrawlPreview, createSalesNavigatorCrawlSeed, DEFAULT_SALES_NAVIGATOR_CRAWL_DIMENSIONS, buildSalesNavigatorPeopleSlice, deriveSalesNavigatorTitleQuerySeeds, expandSalesNavigatorCrawlAttempt, SalesNavigatorSliceTooBroadError } from "./sales-navigator.js";
@@ -5869,6 +5871,15 @@ async function runSalesNavigatorExport(session, payload, traceId, logOptions = {
5869
5871
  }
5870
5872
  }
5871
5873
  async function startSalesNavigatorExport(session, payload, traceId) {
5874
+ const exportSession = await resolveSalesNavigatorExportSessionOverride(payload.slicedQueryUrl, {
5875
+ source: "cli_salesnav_export_start"
5876
+ });
5877
+ const sessionOverridePayload = exportSession
5878
+ ? {
5879
+ sessionCookie: exportSession.sessionCookie,
5880
+ selectedSessionCookieSha256: exportSession.selectedSessionCookieSha256
5881
+ }
5882
+ : {};
5872
5883
  return await fetchCliJson(session, (currentSession) => fetch(`${currentSession.apiBaseUrl}/api/cli/salesnav/export`, {
5873
5884
  method: "POST",
5874
5885
  signal: AbortSignal.timeout(SALES_NAVIGATOR_EXPORT_START_TIMEOUT_MS),
@@ -5879,7 +5890,8 @@ async function startSalesNavigatorExport(session, payload, traceId) {
5879
5890
  },
5880
5891
  body: JSON.stringify({
5881
5892
  ...payload,
5882
- appliedFilters: serializeSalesNavigatorFiltersForApi(payload.appliedFilters)
5893
+ appliedFilters: serializeSalesNavigatorFiltersForApi(payload.appliedFilters),
5894
+ ...sessionOverridePayload
5883
5895
  })
5884
5896
  }), SalesNavigatorExportStartResponseSchema);
5885
5897
  }
@@ -6686,25 +6698,95 @@ function buildSalesNavigatorSliceFailureReport(slice, error, options) {
6686
6698
  function formatSalesNavigatorSplitTrail(splitTrail) {
6687
6699
  return splitTrail.map((entry) => `${entry.key}:${entry.value.text}`);
6688
6700
  }
6701
+ let cachedSalesNavigatorExportSessionOverride = null;
6702
+ function hashSalesNavigatorSessionCookieForPhantombuster(sessionCookie) {
6703
+ const liAt = extractLiAtCookieValue(sessionCookie);
6704
+ if (!liAt) {
6705
+ return null;
6706
+ }
6707
+ return createHash("sha256").update(liAt).digest("hex");
6708
+ }
6709
+ function normalizeSalesNavigatorSessionCookieForPhantombuster(sessionCookie) {
6710
+ return extractLiAtCookieValue(sessionCookie) ?? sessionCookie;
6711
+ }
6712
+ function cacheSalesNavigatorExportSessionOverride(queryUrl, value) {
6713
+ cachedSalesNavigatorExportSessionOverride = {
6714
+ queryUrl,
6715
+ expiresAt: Date.now() + 120_000,
6716
+ value
6717
+ };
6718
+ return value;
6719
+ }
6720
+ async function resolveSalesNavigatorExportSessionOverride(queryUrl, options) {
6721
+ if (cachedSalesNavigatorExportSessionOverride &&
6722
+ cachedSalesNavigatorExportSessionOverride.queryUrl === queryUrl &&
6723
+ cachedSalesNavigatorExportSessionOverride.expiresAt > Date.now()) {
6724
+ return cachedSalesNavigatorExportSessionOverride.value;
6725
+ }
6726
+ const localExtensionConfig = await readLocalLinkedInExtensionDirectLookupConfig();
6727
+ if (localExtensionConfig?.cookie) {
6728
+ const selectedSessionCookieSha256 = hashSalesNavigatorSessionCookieForPhantombuster(localExtensionConfig.cookie);
6729
+ if (process.env.SALESPROMPTER_SALESNAV_EXPORT_SKIP_EXTENSION_PREFLIGHT === "1") {
6730
+ return cacheSalesNavigatorExportSessionOverride(queryUrl, {
6731
+ sessionCookie: normalizeSalesNavigatorSessionCookieForPhantombuster(localExtensionConfig.cookie),
6732
+ selectedSessionCookieSha256,
6733
+ source: "chrome_extension"
6734
+ });
6735
+ }
6736
+ const probe = await probeSalesNavigatorSearchSession(localExtensionConfig.cookie, queryUrl, {
6737
+ timeoutMs: 8000
6738
+ });
6739
+ await options.logger?.log("salesnav.export.session.chrome_extension.preflight", {
6740
+ source: options.source,
6741
+ queryUrl,
6742
+ status: probe.status,
6743
+ selectedSessionCookieSha256,
6744
+ finalUrl: probe.finalUrl,
6745
+ validationError: probe.validationError
6746
+ });
6747
+ if (probe.status === "ok") {
6748
+ return cacheSalesNavigatorExportSessionOverride(queryUrl, {
6749
+ sessionCookie: normalizeSalesNavigatorSessionCookieForPhantombuster(localExtensionConfig.cookie),
6750
+ selectedSessionCookieSha256,
6751
+ source: "chrome_extension"
6752
+ });
6753
+ }
6754
+ }
6755
+ const claimed = await claimValidatedSalesNavigatorSessionCookieForCli({
6756
+ queryUrl,
6757
+ source: options.source,
6758
+ env: process.env
6759
+ });
6760
+ if (claimed?.sessionCookie) {
6761
+ return cacheSalesNavigatorExportSessionOverride(queryUrl, {
6762
+ sessionCookie: normalizeSalesNavigatorSessionCookieForPhantombuster(claimed.sessionCookie),
6763
+ selectedSessionCookieSha256: claimed.sessionCookieSha256 ??
6764
+ hashSalesNavigatorSessionCookieForPhantombuster(claimed.sessionCookie),
6765
+ source: "session_vault"
6766
+ });
6767
+ }
6768
+ if (localExtensionConfig?.cookie &&
6769
+ process.env.SALESPROMPTER_SALESNAV_EXPORT_REQUIRE_FRESH_SESSION === "1") {
6770
+ throw new Error("The local Salesprompter Chrome extension session cookie is not valid for Sales Navigator. Reconnect the extension, then retry the CLI command.");
6771
+ }
6772
+ if (process.env.SALESPROMPTER_CLI_MANAGE_LINKEDIN_SESSIONS === "1") {
6773
+ throw new Error("No validated LinkedIn Sales Navigator session cookie is available from the CLI-managed session pool.");
6774
+ }
6775
+ return null;
6776
+ }
6689
6777
  async function ensureSalesNavigatorSessionPoolReady(queryUrl, options) {
6690
6778
  try {
6691
6779
  await options.logger?.log("salesnav.session_pool.preflight.started", {
6692
6780
  source: options.source,
6693
6781
  queryUrl
6694
6782
  });
6695
- const claimed = await claimValidatedSalesNavigatorSessionCookieForCli({
6696
- queryUrl,
6697
- source: options.source,
6698
- env: process.env
6699
- });
6783
+ const claimed = await resolveSalesNavigatorExportSessionOverride(queryUrl, options);
6700
6784
  await options.logger?.log("salesnav.session_pool.preflight.completed", {
6701
6785
  source: options.source,
6702
6786
  queryUrl,
6703
6787
  status: claimed ? "ok" : "skipped",
6704
- selectedSessionUserEmail: claimed?.userEmail ?? null,
6705
- selectedSessionUserHandle: claimed?.userHandle ?? null,
6706
- selectedSessionCookieSha256: claimed?.sessionCookieSha256 ?? null,
6707
- selectedSessionLastIngestedSource: claimed?.lastIngestedSource ?? null
6788
+ selectedSessionSource: claimed?.source ?? "app_managed",
6789
+ selectedSessionCookieSha256: claimed?.selectedSessionCookieSha256 ?? null
6708
6790
  });
6709
6791
  return {
6710
6792
  ready: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "salesprompter-cli",
3
- "version": "0.1.37",
3
+ "version": "0.1.38",
4
4
  "description": "Sales workflow CLI for guided lead generation, enrichment, scoring, and sync.",
5
5
  "author": "Daniel Sinewe <hello@danielsinewe.com>",
6
6
  "type": "module",