salesprompter-cli 0.1.48 → 0.1.50

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 +67 -30
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -8,6 +8,7 @@ import path from "node:path";
8
8
  import { emitKeypressEvents } from "node:readline";
9
9
  import { createInterface } from "node:readline/promises";
10
10
  import { setTimeout as delay } from "node:timers/promises";
11
+ import { gzipSync } from "node:zlib";
11
12
  import { createClient } from "@supabase/supabase-js";
12
13
  import pg from "pg";
13
14
  import { Command } from "commander";
@@ -7754,6 +7755,8 @@ async function createLocalAccountSearchBrowserRelay(requestedPort) {
7754
7755
  status: "task",
7755
7756
  requestId: pending.requestId,
7756
7757
  url: pending.url,
7758
+ headers: pending.headers,
7759
+ requiredHeaders: pending.requiredHeaders,
7757
7760
  }
7758
7761
  : { status: "idle" });
7759
7762
  return;
@@ -7792,7 +7795,10 @@ async function createLocalAccountSearchBrowserRelay(requestedPort) {
7792
7795
  return;
7793
7796
  }
7794
7797
  if (!Number.isFinite(status) || status < 200 || status >= 300) {
7795
- current.reject(new Error(`Sales Navigator browser relay failed with HTTP ${status}: ${bodyPreview}`));
7798
+ const recovery = status === 401 || status === 403
7799
+ ? " Refresh the Sales Navigator search, capture the current csrf-token from a native Lead Search request, and replay this task with the supplied headers."
7800
+ : "";
7801
+ current.reject(new Error(`Sales Navigator browser relay failed with HTTP ${status}: ${bodyPreview}.${recovery}`));
7796
7802
  writeLocalAccountSearchRelayJson(response, 200, {
7797
7803
  status: "failed",
7798
7804
  });
@@ -7827,21 +7833,37 @@ async function createLocalAccountSearchBrowserRelay(requestedPort) {
7827
7833
  }
7828
7834
  return {
7829
7835
  port: address.port,
7830
- request(url) {
7836
+ request(request) {
7831
7837
  if (pending) {
7832
7838
  throw new Error("Account Search browser relay already has a pending task.");
7833
7839
  }
7834
- const parsedUrl = new URL(url);
7840
+ const parsedUrl = new URL(request.url);
7835
7841
  if (!/(^|\.)linkedin\.com$/i.test(parsedUrl.hostname) ||
7836
7842
  !(parsedUrl.pathname.includes("/sales-api/salesApiAccountSearch") ||
7837
7843
  parsedUrl.pathname.includes("/sales-api/salesApiLeadSearch"))) {
7838
7844
  throw new Error("Browser relay only accepts LinkedIn Account or Lead Search API URLs.");
7839
7845
  }
7846
+ const headers = Object.fromEntries(Object.entries(request.headers)
7847
+ .map(([name, value]) => [name.toLowerCase(), value])
7848
+ .filter(([name]) => ![
7849
+ "cookie",
7850
+ "host",
7851
+ "origin",
7852
+ "referer",
7853
+ "content-length",
7854
+ "user-agent",
7855
+ ].includes(name)));
7856
+ headers.accept ??= "*/*";
7857
+ headers["x-restli-protocol-version"] ??= "2.0.0";
7840
7858
  requestSequence += 1;
7841
7859
  return new Promise((resolve, reject) => {
7842
7860
  pending = {
7843
7861
  requestId: `sales-nav-search-${requestSequence}`,
7844
- url,
7862
+ url: request.url,
7863
+ headers,
7864
+ requiredHeaders: parsedUrl.pathname.includes("salesApiLeadSearch")
7865
+ ? ["csrf-token"]
7866
+ : [],
7845
7867
  resolve,
7846
7868
  reject,
7847
7869
  };
@@ -8739,34 +8761,41 @@ function describeLocalSalesNavigatorAccountPartialError(fetchResult) {
8739
8761
  async function importLocalSalesNavigatorPeopleViaApp(session, payload) {
8740
8762
  const { value } = await fetchCliJson(session, (currentSession) => {
8741
8763
  const workspaceClientId = currentSession.user.workspaceClientId?.trim() || null;
8764
+ const serializedPayload = JSON.stringify({
8765
+ sourceQueryUrl: payload.sourceQueryUrl,
8766
+ slicedQueryUrl: payload.sourceQueryUrl,
8767
+ appliedFilters: [],
8768
+ maxResultsPerSearch: payload.maxResultsPerSearch,
8769
+ numberOfProfiles: payload.numberOfProfiles,
8770
+ slicePreset: payload.slicePreset,
8771
+ totalResults: payload.totalResults,
8772
+ fetchedPages: payload.fetchedPages,
8773
+ people: payload.people,
8774
+ rawPayload: {
8775
+ clientId: workspaceClientId ?? undefined,
8776
+ client_id: workspaceClientId ?? undefined,
8777
+ leadList: workspaceClientId
8778
+ ? { clientId: workspaceClientId }
8779
+ : undefined,
8780
+ workflow: "salesnav:local-import",
8781
+ localPeopleCount: payload.people.length,
8782
+ fetchedPages: payload.fetchedPages,
8783
+ pacing: payload.pacing,
8784
+ },
8785
+ });
8786
+ const shouldCompress = Buffer.byteLength(serializedPayload) >= 512 * 1024;
8742
8787
  return fetch(`${currentSession.apiBaseUrl}/api/cli/salesnav/local-import`, {
8743
8788
  method: "POST",
8744
8789
  headers: {
8745
- "Content-Type": "application/json",
8790
+ "Content-Type": shouldCompress
8791
+ ? "application/octet-stream"
8792
+ : "application/json",
8746
8793
  Authorization: `Bearer ${currentSession.accessToken}`,
8794
+ ...(shouldCompress
8795
+ ? { "X-Salesprompter-Content-Encoding": "gzip" }
8796
+ : {}),
8747
8797
  },
8748
- body: JSON.stringify({
8749
- sourceQueryUrl: payload.sourceQueryUrl,
8750
- slicedQueryUrl: payload.sourceQueryUrl,
8751
- appliedFilters: [],
8752
- maxResultsPerSearch: payload.maxResultsPerSearch,
8753
- numberOfProfiles: payload.numberOfProfiles,
8754
- slicePreset: payload.slicePreset,
8755
- totalResults: payload.totalResults,
8756
- fetchedPages: payload.fetchedPages,
8757
- people: payload.people,
8758
- rawPayload: {
8759
- clientId: workspaceClientId ?? undefined,
8760
- client_id: workspaceClientId ?? undefined,
8761
- leadList: workspaceClientId
8762
- ? { clientId: workspaceClientId }
8763
- : undefined,
8764
- workflow: "salesnav:local-import",
8765
- localPeopleCount: payload.people.length,
8766
- fetchedPages: payload.fetchedPages,
8767
- pacing: payload.pacing,
8768
- },
8769
- }),
8798
+ body: shouldCompress ? gzipSync(serializedPayload) : serializedPayload,
8770
8799
  });
8771
8800
  }, SalesNavigatorLocalImportResponseSchema);
8772
8801
  return value;
@@ -13273,7 +13302,7 @@ async function runSalesNavigatorPeopleCollectCommand(options) {
13273
13302
  retryMaxDelayMs: 10_000
13274
13303
  },
13275
13304
  executeRequest: browserRelay
13276
- ? (request) => browserRelay.request(request.url)
13305
+ ? (request) => browserRelay.request(request)
13277
13306
  : undefined
13278
13307
  });
13279
13308
  }
@@ -13295,6 +13324,14 @@ async function runSalesNavigatorPeopleCollectCommand(options) {
13295
13324
  dryRun: false,
13296
13325
  collected: collected.people.length,
13297
13326
  totalResults: collected.totalResults,
13327
+ collectionComplete: collected.totalResults != null &&
13328
+ collected.people.length >= collected.totalResults,
13329
+ truncated: collected.totalResults != null &&
13330
+ collected.totalResults > collected.people.length &&
13331
+ collected.people.length >= maxResults,
13332
+ remainingResults: collected.totalResults == null
13333
+ ? null
13334
+ : Math.max(0, collected.totalResults - collected.people.length),
13298
13335
  fetchedPages: collected.fetchedPages,
13299
13336
  runId: imported.runId,
13300
13337
  imported: imported.imported,
@@ -13351,7 +13388,7 @@ async function runAffiliateLaunchCommand(options) {
13351
13388
  retryMaxDelayMs: 10_000,
13352
13389
  },
13353
13390
  executeRequest: browserRelay
13354
- ? (request) => browserRelay.request(request.url)
13391
+ ? (request) => browserRelay.request(request)
13355
13392
  : undefined,
13356
13393
  });
13357
13394
  }
@@ -14456,7 +14493,7 @@ program
14456
14493
  };
14457
14494
  };
14458
14495
  const executeRequest = (request) => browserRelay
14459
- ? browserRelay.request(request.url)
14496
+ ? browserRelay.request(request)
14460
14497
  : fetchLocalSalesNavigatorRequest(request, retry);
14461
14498
  try {
14462
14499
  let requestsThisRun = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "salesprompter-cli",
3
- "version": "0.1.48",
3
+ "version": "0.1.50",
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",