@floomhq/signaldash 0.8.0 → 0.9.0
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/bin/sd.mjs +23 -33
- package/package.json +1 -1
package/bin/sd.mjs
CHANGED
|
@@ -278,46 +278,36 @@ export async function cmdConnections(outPath, dependencies = {}) {
|
|
|
278
278
|
const log = dependencies.log || console.log;
|
|
279
279
|
const request = dependencies.request || api;
|
|
280
280
|
const { chalk, ora } = await ui();
|
|
281
|
-
const { writeFileSync: wf
|
|
281
|
+
const { writeFileSync: wf } = await import("node:fs");
|
|
282
282
|
const file = outPath || "linkedin-connections.csv";
|
|
283
283
|
|
|
284
|
-
//
|
|
285
|
-
//
|
|
286
|
-
//
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
const prev = JSON.parse(rf(stateFile, "utf8"));
|
|
292
|
-
cursor = prev.cursor || null; rows = prev.rows || [];
|
|
293
|
-
if (cursor) log(" " + chalk.dim(`resuming from previous run (${rows.length} already fetched)`));
|
|
294
|
-
} catch {}
|
|
284
|
+
// Background drip-sync: one page (~100 connections) per ~90s, server-side.
|
|
285
|
+
// A burst export of a large network looks robotic to LinkedIn; this paces it
|
|
286
|
+
// like a human and survives restarts, so the user just waits for the file.
|
|
287
|
+
const start = await request("/li/connections/sync", {});
|
|
288
|
+
if (start.status >= 300) {
|
|
289
|
+
(dependencies.error || console.error)(start.json.error || "could not start sync");
|
|
290
|
+
process.exitCode = 1; return;
|
|
295
291
|
}
|
|
296
|
-
|
|
297
|
-
|
|
292
|
+
const spin = ora({ text: "Syncing connections (paced to keep your account safe)...", indent: 2 }).start();
|
|
293
|
+
let done = false;
|
|
298
294
|
for (;;) {
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
rows = rows.concat(r.json.connections || []);
|
|
306
|
-
cursor = r.json.next_cursor;
|
|
307
|
-
spin.text = `Fetched ${rows.length} connections...`;
|
|
308
|
-
if (!cursor) break;
|
|
309
|
-
wf(stateFile, JSON.stringify({ cursor, rows }));
|
|
295
|
+
const st = await request("/li/connections/sync", undefined, { method: "GET" });
|
|
296
|
+
const s2 = st.json || {};
|
|
297
|
+
spin.text = `Synced ${s2.fetched ?? 0} connections (${s2.pages ?? 0} pages)...`;
|
|
298
|
+
if (s2.status === "complete") { done = true; break; }
|
|
299
|
+
if (s2.status === "failed" || s2.status === "paused") { spin.warn(`sync ${s2.status}: ${s2.error || ""}`); break; }
|
|
300
|
+
await new Promise(r => setTimeout(r, 15000));
|
|
310
301
|
}
|
|
311
|
-
|
|
312
|
-
|
|
302
|
+
const dl = await request("/li/connections/download", undefined, { method: "GET" });
|
|
303
|
+
const rows = (dl.json && dl.json.connections) || [];
|
|
304
|
+
if (!rows.length) { spin.fail("nothing fetched yet, run again later to resume"); process.exitCode = 1; return; }
|
|
305
|
+
if (done) spin.succeed(`${rows.length} connections`);
|
|
313
306
|
const esc = v => `"${String(v ?? "").replace(/"/g, '""')}"`;
|
|
314
|
-
|
|
315
|
-
...rows.map(c => [c.name, c.headline, c.public_id, c.profile_url, c.connected_at].map(esc).join(","))].join("\n");
|
|
316
|
-
wf(file, csv);
|
|
317
|
-
try { const { unlinkSync } = await import("node:fs"); if (ex(stateFile)) unlinkSync(stateFile); } catch {}
|
|
307
|
+
wf(file, ["name,headline,public_id,profile_url,connected_at",
|
|
308
|
+
...rows.map(c => [c.name, c.headline, c.public_id, c.profile_url, c.connected_at].map(esc).join(","))].join("\n"));
|
|
318
309
|
log(" " + chalk.green("+") + " saved " + chalk.cyan(file));
|
|
319
|
-
log(" " + chalk.dim("
|
|
320
|
-
log(" " + chalk.dim("and includes emails. Both work; that one never touches the API."));
|
|
310
|
+
if (!done) log(" " + chalk.dim("sync still running; run this again later to get the rest"));
|
|
321
311
|
}
|
|
322
312
|
|
|
323
313
|
export async function main(argv = process.argv.slice(2), dependencies = {}) {
|