heyreach-cli 0.1.1 → 0.1.3
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/index.js +54 -14
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +40 -10
- package/dist/mcp.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -64,7 +64,9 @@ var init_config = __esm({
|
|
|
64
64
|
// src/core/errors.ts
|
|
65
65
|
function classifyHttpError(status, body) {
|
|
66
66
|
const parsed = safeParse(body);
|
|
67
|
-
const
|
|
67
|
+
const rawVal = parsed?.message || parsed?.error || body || `HTTP ${status} error`;
|
|
68
|
+
const raw = typeof rawVal === "string" ? rawVal : JSON.stringify(rawVal);
|
|
69
|
+
const message = extractMessage(raw);
|
|
68
70
|
if (status === 401 || status === 403) return new AuthError(message);
|
|
69
71
|
if (status === 404) return new NotFoundError(message);
|
|
70
72
|
if (status === 422) return new ValidationError(message);
|
|
@@ -72,6 +74,18 @@ function classifyHttpError(status, body) {
|
|
|
72
74
|
if (status >= 500) return new ServerError(message);
|
|
73
75
|
return new HeyReachError(message, "HTTP_ERROR", status);
|
|
74
76
|
}
|
|
77
|
+
function extractMessage(raw) {
|
|
78
|
+
const nested = safeParse(raw);
|
|
79
|
+
if (nested?.errors && typeof nested.errors === "object") {
|
|
80
|
+
const parts = [];
|
|
81
|
+
for (const [field, msgs] of Object.entries(nested.errors)) {
|
|
82
|
+
const msgList = Array.isArray(msgs) ? msgs.join("; ") : String(msgs);
|
|
83
|
+
parts.push(`${field}: ${msgList}`);
|
|
84
|
+
}
|
|
85
|
+
if (parts.length > 0) return parts.join(". ");
|
|
86
|
+
}
|
|
87
|
+
return raw;
|
|
88
|
+
}
|
|
75
89
|
function safeParse(text) {
|
|
76
90
|
try {
|
|
77
91
|
return JSON.parse(text);
|
|
@@ -255,7 +269,9 @@ function createClient(auth) {
|
|
|
255
269
|
return { request, paginate };
|
|
256
270
|
}
|
|
257
271
|
function buildUrl(baseUrl, path2, query) {
|
|
258
|
-
const
|
|
272
|
+
const base = baseUrl.endsWith("/") ? baseUrl : baseUrl + "/";
|
|
273
|
+
const cleanPath = path2.startsWith("/") ? path2.slice(1) : path2;
|
|
274
|
+
const url = new URL(cleanPath, base);
|
|
259
275
|
if (query) {
|
|
260
276
|
for (const [key, value] of Object.entries(query)) {
|
|
261
277
|
if (value !== void 0 && value !== null) {
|
|
@@ -631,6 +647,7 @@ var init_get_for_lead = __esm({
|
|
|
631
647
|
"use strict";
|
|
632
648
|
init_esm_shims();
|
|
633
649
|
init_handler();
|
|
650
|
+
init_errors();
|
|
634
651
|
campaignsGetForLeadCommand = {
|
|
635
652
|
name: "campaigns_get_for_lead",
|
|
636
653
|
group: "campaigns",
|
|
@@ -658,7 +675,12 @@ var init_get_for_lead = __esm({
|
|
|
658
675
|
},
|
|
659
676
|
endpoint: { method: "POST", path: "/campaign/GetCampaignsForLead" },
|
|
660
677
|
fieldMappings: { offset: "body", limit: "body", email: "body", linkedinId: "body", profileUrl: "body" },
|
|
661
|
-
handler: (input, client) =>
|
|
678
|
+
handler: (input, client) => {
|
|
679
|
+
if (!input.email && !input.linkedinId && !input.profileUrl) {
|
|
680
|
+
throw new ValidationError("At least one of --email, --linkedin-id, or --profile-url is required.");
|
|
681
|
+
}
|
|
682
|
+
return executeCommand(campaignsGetForLeadCommand, input, client);
|
|
683
|
+
}
|
|
662
684
|
};
|
|
663
685
|
}
|
|
664
686
|
});
|
|
@@ -1257,6 +1279,7 @@ var init_get_for_lead2 = __esm({
|
|
|
1257
1279
|
"use strict";
|
|
1258
1280
|
init_esm_shims();
|
|
1259
1281
|
init_handler();
|
|
1282
|
+
init_errors();
|
|
1260
1283
|
listsGetForLeadCommand = {
|
|
1261
1284
|
name: "lists_get_for_lead",
|
|
1262
1285
|
group: "lists",
|
|
@@ -1281,7 +1304,12 @@ var init_get_for_lead2 = __esm({
|
|
|
1281
1304
|
},
|
|
1282
1305
|
endpoint: { method: "POST", path: "/list/GetListsForLead" },
|
|
1283
1306
|
fieldMappings: { offset: "body", limit: "body", email: "body", linkedinId: "body", profileUrl: "body" },
|
|
1284
|
-
handler: (input, client) =>
|
|
1307
|
+
handler: (input, client) => {
|
|
1308
|
+
if (!input.email && !input.linkedinId && !input.profileUrl) {
|
|
1309
|
+
throw new ValidationError("At least one of --email, --linkedin-id, or --profile-url is required.");
|
|
1310
|
+
}
|
|
1311
|
+
return executeCommand(listsGetForLeadCommand, input, client);
|
|
1312
|
+
}
|
|
1285
1313
|
};
|
|
1286
1314
|
}
|
|
1287
1315
|
});
|
|
@@ -1332,8 +1360,8 @@ var init_overview = __esm({
|
|
|
1332
1360
|
'heyreach stats overview --start-date 2025-01-01 --end-date 2025-01-31 --campaign-ids "1,2,3"'
|
|
1333
1361
|
],
|
|
1334
1362
|
inputSchema: z24.object({
|
|
1335
|
-
startDate: z24.string().describe("Start date (ISO 8601)"),
|
|
1336
|
-
endDate: z24.string().describe("End date (ISO 8601)"),
|
|
1363
|
+
startDate: z24.string().optional().describe("Start date (ISO 8601). Defaults to 30 days ago."),
|
|
1364
|
+
endDate: z24.string().optional().describe("End date (ISO 8601). Defaults to today."),
|
|
1337
1365
|
accountIds: z24.string().optional().describe("Comma-separated LinkedIn account IDs (empty = all)"),
|
|
1338
1366
|
campaignIds: z24.string().optional().describe("Comma-separated campaign IDs (empty = all)")
|
|
1339
1367
|
}),
|
|
@@ -1348,12 +1376,14 @@ var init_overview = __esm({
|
|
|
1348
1376
|
endpoint: { method: "POST", path: "/stats/GetOverallStats" },
|
|
1349
1377
|
fieldMappings: {},
|
|
1350
1378
|
handler: async (input, client) => {
|
|
1379
|
+
const now = /* @__PURE__ */ new Date();
|
|
1380
|
+
const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1e3);
|
|
1351
1381
|
const body = {
|
|
1352
|
-
startDate: input.startDate,
|
|
1353
|
-
endDate: input.endDate
|
|
1382
|
+
startDate: input.startDate ?? thirtyDaysAgo.toISOString(),
|
|
1383
|
+
endDate: input.endDate ?? now.toISOString(),
|
|
1384
|
+
accountIds: input.accountIds ? input.accountIds.split(",").map((s) => Number(s.trim())) : [],
|
|
1385
|
+
campaignIds: input.campaignIds ? input.campaignIds.split(",").map((s) => Number(s.trim())) : []
|
|
1354
1386
|
};
|
|
1355
|
-
if (input.accountIds) body.accountIds = input.accountIds.split(",").map((s) => Number(s.trim()));
|
|
1356
|
-
if (input.campaignIds) body.campaignIds = input.campaignIds.split(",").map((s) => Number(s.trim()));
|
|
1357
1387
|
return client.request({ method: "POST", path: "/stats/GetOverallStats", body });
|
|
1358
1388
|
}
|
|
1359
1389
|
};
|
|
@@ -2404,7 +2434,7 @@ function getGlobalOpts(program2) {
|
|
|
2404
2434
|
};
|
|
2405
2435
|
}
|
|
2406
2436
|
function registerLoginCommand(program2) {
|
|
2407
|
-
program2.command("login").description("Save your API key to ~/.heyreach/config.json").option("--org", "Store Organization API key instead of workspace key").action(async (opts) => {
|
|
2437
|
+
program2.command("login").description("Save your API key to ~/.heyreach/config.json").option("--org", "Store Organization API key instead of workspace key").addHelpText("after", "\nExamples:\n $ heyreach login --api-key <key>\n $ heyreach login --org --org-key <key>\n $ heyreach login # interactive prompt").action(async (opts) => {
|
|
2408
2438
|
const globalOpts = getGlobalOpts(program2);
|
|
2409
2439
|
const isOrg = opts.org;
|
|
2410
2440
|
let apiKey = isOrg ? globalOpts.orgKey ?? process.env.HEYREACH_ORG_API_KEY : globalOpts.apiKey ?? process.env.HEYREACH_API_KEY;
|
|
@@ -2418,9 +2448,17 @@ function registerLoginCommand(program2) {
|
|
|
2418
2448
|
outputError({ error: "API key is required.", code: "VALIDATION_ERROR" }, globalOpts);
|
|
2419
2449
|
return;
|
|
2420
2450
|
}
|
|
2451
|
+
try {
|
|
2452
|
+
const checkPath = isOrg ? "/organization/GetWorkspaces" : "/auth/CheckApiKey";
|
|
2453
|
+
const client = createClient({ apiKey, baseUrl: "https://api.heyreach.io/api/public" });
|
|
2454
|
+
await client.request({ method: "GET", path: checkPath });
|
|
2455
|
+
} catch {
|
|
2456
|
+
outputError({ error: `Invalid ${isOrg ? "Organization" : ""} API key. Check your key and try again.`, code: "AUTH_ERROR" }, globalOpts);
|
|
2457
|
+
return;
|
|
2458
|
+
}
|
|
2421
2459
|
const config = isOrg ? { org_api_key: apiKey } : { api_key: apiKey };
|
|
2422
2460
|
saveConfig(config);
|
|
2423
|
-
output({ success: true, message: "Credentials saved.", config_path: getConfigPath() }, globalOpts);
|
|
2461
|
+
output({ success: true, message: "Credentials saved and verified.", config_path: getConfigPath() }, globalOpts);
|
|
2424
2462
|
});
|
|
2425
2463
|
}
|
|
2426
2464
|
function registerLogoutCommand(program2) {
|
|
@@ -2444,9 +2482,11 @@ function registerStatusCommand(program2) {
|
|
|
2444
2482
|
}, globalOpts);
|
|
2445
2483
|
} catch (err) {
|
|
2446
2484
|
const config = loadConfig();
|
|
2485
|
+
const usedKey = globalOpts.apiKey ?? process.env.HEYREACH_API_KEY ?? config.api_key;
|
|
2447
2486
|
output({
|
|
2448
2487
|
authenticated: false,
|
|
2449
|
-
api_key:
|
|
2488
|
+
api_key: usedKey ? "***" + usedKey.slice(-4) : "(not set)",
|
|
2489
|
+
api_key_source: globalOpts.apiKey ? "--api-key flag" : process.env.HEYREACH_API_KEY ? "HEYREACH_API_KEY env" : config.api_key ? "config file" : "none",
|
|
2450
2490
|
config_path: getConfigPath(),
|
|
2451
2491
|
error: err instanceof Error ? err.message : String(err)
|
|
2452
2492
|
}, globalOpts);
|
|
@@ -2606,7 +2646,7 @@ import { Command } from "commander";
|
|
|
2606
2646
|
var program = new Command();
|
|
2607
2647
|
program.name("heyreach").description(
|
|
2608
2648
|
"HeyReach CLI \u2014 manage LinkedIn campaigns, leads, lists, inbox, webhooks, and more from your terminal."
|
|
2609
|
-
).version("0.1.
|
|
2649
|
+
).version("0.1.3").option("--pretty", "Pretty-print JSON output").option("--quiet", "Suppress output, exit codes only").option("--fields <fields>", "Comma-separated fields to include in output").option("--api-key <key>", "HeyReach workspace API key").option("--org-key <key>", "HeyReach Organization API key");
|
|
2610
2650
|
registerAllCommands(program);
|
|
2611
2651
|
program.parse();
|
|
2612
2652
|
//# sourceMappingURL=index.js.map
|