@curviate/cli 0.14.0 → 0.15.1
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/CHANGELOG.md +161 -0
- package/README.md +52 -79
- package/dist/{account-7AUDAMIK.js → account-FM473HEK.js} +38 -371
- package/dist/{chunk-SSPILTKF.js → chunk-45KHSWCV.js} +56 -48
- package/dist/chunk-BGZW6B7G.js +59 -0
- package/dist/chunk-EEMJDJ4W.js +80 -0
- package/dist/{chunk-JXF47TRY.js → chunk-M33MI53G.js} +33 -1
- package/dist/chunk-QJZ3LWOX.js +24 -0
- package/dist/{chunk-4JHGVY7R.js → chunk-TMU3CSPR.js} +4 -0
- package/dist/{chunk-HMAGEMF7.js → chunk-ZE7QGR3F.js} +4 -0
- package/dist/cli.js +127 -15
- package/dist/comment-NCDXERSI.js +555 -0
- package/dist/{company-RU2CA5DY.js → company-IYTMW64G.js} +27 -74
- package/dist/{config-Q2AEWSEC.js → config-P5CPF5WC.js} +1 -1
- package/dist/{connect-QT6ZOS75.js → connect-TTJHMBUP.js} +91 -45
- package/dist/{exit-codes-ZTY2NY3X.js → exit-codes-SL3GQF7W.js} +1 -1
- package/dist/{inbox-DN7X7CM2.js → inbox-EOOGJ3ZN.js} +55 -124
- package/dist/job-YARGTHUY.js +631 -0
- package/dist/{login-BBVQLXM7.js → login-MFB45PVZ.js} +1 -1
- package/dist/{message-6K5E3CUF.js → message-2DLIQIE6.js} +61 -51
- package/dist/{post-2JQZ3OSF.js → post-GRIJ7X52.js} +188 -221
- package/dist/profile-57RJEL7H.js +809 -0
- package/dist/{recruiter-XHVMQWK6.js → recruiter-CTYH7AYG.js} +740 -226
- package/dist/{sales-nav-QTSTJMKA.js → sales-nav-NUMEYOEO.js} +119 -77
- package/dist/{search-ZGTS45BT.js → search-RD4TXNV7.js} +103 -39
- package/dist/{webhook-EIY5WWTE.js → webhook-CEP7SGP5.js} +8 -45
- package/package.json +4 -3
- package/dist/chunk-GXTZION6.js +0 -45
- package/dist/chunk-Q43HZUN3.js +0 -29
- package/dist/job-FGGQEXSU.js +0 -105
- package/dist/profile-DD5GMGNL.js +0 -501
|
@@ -0,0 +1,809 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
resolveMemberOrMeProviderId,
|
|
4
|
+
resolveMemberProviderId
|
|
5
|
+
} from "./chunk-QJZ3LWOX.js";
|
|
6
|
+
import {
|
|
7
|
+
AttachError,
|
|
8
|
+
readAttachment,
|
|
9
|
+
toAttachmentPayload
|
|
10
|
+
} from "./chunk-BGZW6B7G.js";
|
|
11
|
+
import {
|
|
12
|
+
buildPreviewOutput
|
|
13
|
+
} from "./chunk-R3VLWLVV.js";
|
|
14
|
+
import {
|
|
15
|
+
slimProfile,
|
|
16
|
+
slimProfileMe
|
|
17
|
+
} from "./chunk-45KHSWCV.js";
|
|
18
|
+
import {
|
|
19
|
+
resolveIdentifier
|
|
20
|
+
} from "./chunk-DMQZEPQE.js";
|
|
21
|
+
import {
|
|
22
|
+
pageDelayFromFlags,
|
|
23
|
+
streamAll
|
|
24
|
+
} from "./chunk-EEMJDJ4W.js";
|
|
25
|
+
import {
|
|
26
|
+
createClient,
|
|
27
|
+
renderError,
|
|
28
|
+
renderSuccess,
|
|
29
|
+
renderUnexpectedError,
|
|
30
|
+
resolveEffectiveConfig
|
|
31
|
+
} from "./chunk-M33MI53G.js";
|
|
32
|
+
import {
|
|
33
|
+
GLOBAL_FLAGS,
|
|
34
|
+
WRITE_SINGLE_FLAGS
|
|
35
|
+
} from "./chunk-TMU3CSPR.js";
|
|
36
|
+
|
|
37
|
+
// src/commands/profile.ts
|
|
38
|
+
import { defineCommand } from "citty";
|
|
39
|
+
|
|
40
|
+
// src/lib/sections.ts
|
|
41
|
+
var SECTION_BASE_NAMES = [
|
|
42
|
+
"experience",
|
|
43
|
+
"education",
|
|
44
|
+
"languages",
|
|
45
|
+
"skills",
|
|
46
|
+
"certifications",
|
|
47
|
+
"volunteer_experience",
|
|
48
|
+
"projects",
|
|
49
|
+
"recommendations",
|
|
50
|
+
"interests"
|
|
51
|
+
];
|
|
52
|
+
var VALID_LINKEDIN_SECTIONS = /* @__PURE__ */ new Set([
|
|
53
|
+
"linkedin_*",
|
|
54
|
+
...SECTION_BASE_NAMES.flatMap((n) => [`linkedin_${n}`, `linkedin_${n}_preview`])
|
|
55
|
+
]);
|
|
56
|
+
var CANONICAL_SECTION_VALUES = [
|
|
57
|
+
"linkedin_*",
|
|
58
|
+
...SECTION_BASE_NAMES.map((n) => `linkedin_${n}`)
|
|
59
|
+
];
|
|
60
|
+
function parseSectionsFlag(raw) {
|
|
61
|
+
const values = raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
62
|
+
const sections = [];
|
|
63
|
+
for (const value of values) {
|
|
64
|
+
const canonical = value.startsWith("linkedin_") ? value : `linkedin_${value}`;
|
|
65
|
+
if (!VALID_LINKEDIN_SECTIONS.has(canonical)) {
|
|
66
|
+
return {
|
|
67
|
+
ok: false,
|
|
68
|
+
error: `error: --sections: unknown section "${value}". Valid values: ${CANONICAL_SECTION_VALUES.join(", ")} (each also has a _preview variant).
|
|
69
|
+
`
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
sections.push(canonical);
|
|
73
|
+
}
|
|
74
|
+
return { ok: true, sections };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/commands/profile.ts
|
|
78
|
+
function requireAccount(account, out) {
|
|
79
|
+
if (!account) {
|
|
80
|
+
out.stderr.write("error: --account is required for this command. Set it via --account, CURVIATE_ACCOUNT, or `curviate config set-account`.\n");
|
|
81
|
+
process.exit(2);
|
|
82
|
+
}
|
|
83
|
+
return account;
|
|
84
|
+
}
|
|
85
|
+
function rejectPreviewOnRead(preview, out) {
|
|
86
|
+
if (preview) {
|
|
87
|
+
out.stderr.write("error: --preview is only valid on write commands (mutations). Reads just run.\n");
|
|
88
|
+
process.exit(2);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function rejectAllOnNonPaginated(all, out) {
|
|
92
|
+
if (all) {
|
|
93
|
+
out.stderr.write("error: --all is not supported on non-paginated commands.\n");
|
|
94
|
+
process.exit(2);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function buildOutputStreams() {
|
|
98
|
+
return {
|
|
99
|
+
stdout: { write: (s) => process.stdout.write(s) },
|
|
100
|
+
stderr: { write: (s) => process.stderr.write(s) }
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function resolveOutputOpts(flags) {
|
|
104
|
+
return {
|
|
105
|
+
json: (flags.json ?? false) || !process.stdout.isTTY,
|
|
106
|
+
isTTY: process.stdout.isTTY ?? false,
|
|
107
|
+
fields: flags.fields,
|
|
108
|
+
verbose: flags.verbose ?? false
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
async function runProfileMe(client, flags, out) {
|
|
112
|
+
rejectPreviewOnRead(flags.preview, out);
|
|
113
|
+
const hasActivityFlag = !!(flags.posts || flags.comments || flags.reactions || flags.followers);
|
|
114
|
+
if (!hasActivityFlag) {
|
|
115
|
+
rejectAllOnNonPaginated(flags.all, out);
|
|
116
|
+
}
|
|
117
|
+
if (flags.sections === "") {
|
|
118
|
+
out.stderr.write("error: --sections must not be empty. Omit the flag or provide section names.\n");
|
|
119
|
+
process.exit(2);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const accountId = requireAccount(flags.account, out);
|
|
123
|
+
const ns = client.account(accountId);
|
|
124
|
+
const outOpts = resolveOutputOpts(flags);
|
|
125
|
+
if (hasActivityFlag) {
|
|
126
|
+
const all = flags.all ?? false;
|
|
127
|
+
const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
|
|
128
|
+
const params2 = {};
|
|
129
|
+
if (flags.limit) params2.limit = parseInt(flags.limit, 10);
|
|
130
|
+
if (flags.cursor) params2.cursor = flags.cursor;
|
|
131
|
+
try {
|
|
132
|
+
if (flags.posts) {
|
|
133
|
+
if (all) {
|
|
134
|
+
const fn = (p) => ns.posts.listUserPosts("me", p);
|
|
135
|
+
for await (const item of streamAll(fn, params2, {
|
|
136
|
+
maxPages,
|
|
137
|
+
out,
|
|
138
|
+
pageDelayMs: pageDelayFromFlags(flags)
|
|
139
|
+
})) {
|
|
140
|
+
out.stdout.write(JSON.stringify(item) + "\n");
|
|
141
|
+
}
|
|
142
|
+
} else {
|
|
143
|
+
const result = await ns.posts.listUserPosts("me", params2);
|
|
144
|
+
renderSuccess(result, outOpts, out);
|
|
145
|
+
}
|
|
146
|
+
} else if (flags.comments) {
|
|
147
|
+
if (all) {
|
|
148
|
+
const fn = (p) => ns.comments.listUserComments("me", p);
|
|
149
|
+
for await (const item of streamAll(fn, params2, {
|
|
150
|
+
maxPages,
|
|
151
|
+
out,
|
|
152
|
+
pageDelayMs: pageDelayFromFlags(flags)
|
|
153
|
+
})) {
|
|
154
|
+
out.stdout.write(JSON.stringify(item) + "\n");
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
const result = await ns.comments.listUserComments("me", params2);
|
|
158
|
+
renderSuccess(result, outOpts, out);
|
|
159
|
+
}
|
|
160
|
+
} else if (flags.reactions) {
|
|
161
|
+
if (all) {
|
|
162
|
+
const fn = (p) => ns.posts.listUserReactions("me", p);
|
|
163
|
+
for await (const item of streamAll(fn, params2, {
|
|
164
|
+
maxPages,
|
|
165
|
+
out,
|
|
166
|
+
pageDelayMs: pageDelayFromFlags(flags)
|
|
167
|
+
})) {
|
|
168
|
+
out.stdout.write(JSON.stringify(item) + "\n");
|
|
169
|
+
}
|
|
170
|
+
} else {
|
|
171
|
+
const result = await ns.posts.listUserReactions("me", params2);
|
|
172
|
+
renderSuccess(result, outOpts, out);
|
|
173
|
+
}
|
|
174
|
+
} else if (flags.followers) {
|
|
175
|
+
if (all) {
|
|
176
|
+
const fn = (p) => ns.users.listFollowers("me", p);
|
|
177
|
+
for await (const item of streamAll(fn, params2, {
|
|
178
|
+
maxPages,
|
|
179
|
+
out,
|
|
180
|
+
pageDelayMs: pageDelayFromFlags(flags)
|
|
181
|
+
})) {
|
|
182
|
+
out.stdout.write(JSON.stringify(item) + "\n");
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
const result = await ns.users.listFollowers("me", params2);
|
|
186
|
+
renderSuccess(result, outOpts, out);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
} catch (err) {
|
|
190
|
+
const { CurviateError } = await import("@curviate/sdk");
|
|
191
|
+
if (err instanceof CurviateError) {
|
|
192
|
+
const { getExitCode } = await import("./exit-codes-SL3GQF7W.js");
|
|
193
|
+
renderError(err, outOpts, out);
|
|
194
|
+
process.exit(getExitCode(err.code));
|
|
195
|
+
}
|
|
196
|
+
renderUnexpectedError(err, out);
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const params = {};
|
|
202
|
+
if (flags.sections) {
|
|
203
|
+
const parsedSections = parseSectionsFlag(flags.sections);
|
|
204
|
+
if (!parsedSections.ok) {
|
|
205
|
+
out.stderr.write(parsedSections.error);
|
|
206
|
+
process.exit(2);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
params.linkedin_sections = parsedSections.sections;
|
|
210
|
+
}
|
|
211
|
+
try {
|
|
212
|
+
const result = await ns.users.get("me", params);
|
|
213
|
+
const slimOutOpts = { ...outOpts, slim: slimProfileMe };
|
|
214
|
+
renderSuccess(result, slimOutOpts, out);
|
|
215
|
+
} catch (err) {
|
|
216
|
+
const { CurviateError } = await import("@curviate/sdk");
|
|
217
|
+
if (err instanceof CurviateError) {
|
|
218
|
+
const { getExitCode } = await import("./exit-codes-SL3GQF7W.js");
|
|
219
|
+
renderError(err, outOpts, out);
|
|
220
|
+
process.exit(getExitCode(err.code));
|
|
221
|
+
}
|
|
222
|
+
renderUnexpectedError(err, out);
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
async function runProfileGet(client, flags, out) {
|
|
227
|
+
rejectPreviewOnRead(flags.preview, out);
|
|
228
|
+
const isListCommand = flags.posts || flags.comments || flags.reactions || flags.followers;
|
|
229
|
+
if (!isListCommand && flags.sections === "") {
|
|
230
|
+
out.stderr.write("error: --sections must not be empty. Omit the flag or provide section names.\n");
|
|
231
|
+
process.exit(2);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
let parsedSections;
|
|
235
|
+
if (!isListCommand && flags.sections) {
|
|
236
|
+
const result = parseSectionsFlag(flags.sections);
|
|
237
|
+
if (!result.ok) {
|
|
238
|
+
out.stderr.write(result.error);
|
|
239
|
+
process.exit(2);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
parsedSections = result.sections;
|
|
243
|
+
}
|
|
244
|
+
const accountId = requireAccount(flags.account, out);
|
|
245
|
+
const rawId = flags.id ?? "";
|
|
246
|
+
const resolvedId = resolveIdentifier(rawId);
|
|
247
|
+
const ns = client.account(accountId);
|
|
248
|
+
const outOpts = resolveOutputOpts(flags);
|
|
249
|
+
const all = flags.all ?? false;
|
|
250
|
+
const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
|
|
251
|
+
const limit = flags.limit ? parseInt(flags.limit, 10) : void 0;
|
|
252
|
+
const cursor = flags.cursor;
|
|
253
|
+
try {
|
|
254
|
+
if (flags.posts) {
|
|
255
|
+
const params = {};
|
|
256
|
+
if (limit !== void 0) params.limit = limit;
|
|
257
|
+
if (cursor) params.cursor = cursor;
|
|
258
|
+
let postId = resolvedId;
|
|
259
|
+
if (flags["is-company"]) {
|
|
260
|
+
const isNumericId = /^\d+$/.test(resolvedId);
|
|
261
|
+
if (!isNumericId) {
|
|
262
|
+
const companyData = await ns.companies.get(resolvedId);
|
|
263
|
+
postId = companyData.id;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (all) {
|
|
267
|
+
const fn = (p) => ns.posts.listUserPosts(postId, p);
|
|
268
|
+
for await (const item of streamAll(fn, params, {
|
|
269
|
+
maxPages,
|
|
270
|
+
out,
|
|
271
|
+
pageDelayMs: pageDelayFromFlags(flags)
|
|
272
|
+
})) {
|
|
273
|
+
out.stdout.write(JSON.stringify(item) + "\n");
|
|
274
|
+
}
|
|
275
|
+
} else {
|
|
276
|
+
const result = await ns.posts.listUserPosts(postId, params);
|
|
277
|
+
renderSuccess(result, outOpts, out);
|
|
278
|
+
}
|
|
279
|
+
} else if (flags.comments) {
|
|
280
|
+
const params = {};
|
|
281
|
+
if (limit !== void 0) params.limit = limit;
|
|
282
|
+
if (cursor) params.cursor = cursor;
|
|
283
|
+
if (all) {
|
|
284
|
+
const fn = (p) => ns.comments.listUserComments(resolvedId, p);
|
|
285
|
+
for await (const item of streamAll(fn, params, {
|
|
286
|
+
maxPages,
|
|
287
|
+
out,
|
|
288
|
+
pageDelayMs: pageDelayFromFlags(flags)
|
|
289
|
+
})) {
|
|
290
|
+
out.stdout.write(JSON.stringify(item) + "\n");
|
|
291
|
+
}
|
|
292
|
+
} else {
|
|
293
|
+
const result = await ns.comments.listUserComments(resolvedId, params);
|
|
294
|
+
renderSuccess(result, outOpts, out);
|
|
295
|
+
}
|
|
296
|
+
} else if (flags.reactions) {
|
|
297
|
+
const params = {};
|
|
298
|
+
if (limit !== void 0) params.limit = limit;
|
|
299
|
+
if (cursor) params.cursor = cursor;
|
|
300
|
+
if (all) {
|
|
301
|
+
const fn = (p) => ns.posts.listUserReactions(resolvedId, p);
|
|
302
|
+
for await (const item of streamAll(fn, params, {
|
|
303
|
+
maxPages,
|
|
304
|
+
out,
|
|
305
|
+
pageDelayMs: pageDelayFromFlags(flags)
|
|
306
|
+
})) {
|
|
307
|
+
out.stdout.write(JSON.stringify(item) + "\n");
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
const result = await ns.posts.listUserReactions(resolvedId, params);
|
|
311
|
+
renderSuccess(result, outOpts, out);
|
|
312
|
+
}
|
|
313
|
+
} else if (flags.followers) {
|
|
314
|
+
const params = {};
|
|
315
|
+
if (limit !== void 0) params.limit = limit;
|
|
316
|
+
if (cursor) params.cursor = cursor;
|
|
317
|
+
if (all) {
|
|
318
|
+
const fn = (p) => ns.users.listFollowers(resolvedId, p);
|
|
319
|
+
for await (const item of streamAll(fn, params, {
|
|
320
|
+
maxPages,
|
|
321
|
+
out,
|
|
322
|
+
pageDelayMs: pageDelayFromFlags(flags)
|
|
323
|
+
})) {
|
|
324
|
+
out.stdout.write(JSON.stringify(item) + "\n");
|
|
325
|
+
}
|
|
326
|
+
} else {
|
|
327
|
+
const result = await ns.users.listFollowers(resolvedId, params);
|
|
328
|
+
renderSuccess(result, outOpts, out);
|
|
329
|
+
}
|
|
330
|
+
} else {
|
|
331
|
+
rejectAllOnNonPaginated(flags.all, out);
|
|
332
|
+
const params = {};
|
|
333
|
+
if (parsedSections) {
|
|
334
|
+
params.linkedin_sections = parsedSections;
|
|
335
|
+
}
|
|
336
|
+
const getId = flags.sections ? await resolveMemberOrMeProviderId(ns, rawId) : resolvedId;
|
|
337
|
+
const result = await ns.users.get(getId, params);
|
|
338
|
+
const getOutOpts = { ...outOpts, slim: slimProfile };
|
|
339
|
+
renderSuccess(result, getOutOpts, out);
|
|
340
|
+
}
|
|
341
|
+
} catch (err) {
|
|
342
|
+
const { CurviateError } = await import("@curviate/sdk");
|
|
343
|
+
if (err instanceof CurviateError) {
|
|
344
|
+
const { getExitCode } = await import("./exit-codes-SL3GQF7W.js");
|
|
345
|
+
renderError(err, outOpts, out);
|
|
346
|
+
process.exit(getExitCode(err.code));
|
|
347
|
+
}
|
|
348
|
+
renderUnexpectedError(err, out);
|
|
349
|
+
process.exit(1);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
async function runProfileRelations(client, flags, out) {
|
|
353
|
+
rejectPreviewOnRead(flags.preview, out);
|
|
354
|
+
const accountId = requireAccount(flags.account, out);
|
|
355
|
+
const ns = client.account(accountId);
|
|
356
|
+
const outOpts = resolveOutputOpts(flags);
|
|
357
|
+
const all = flags.all ?? false;
|
|
358
|
+
const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
|
|
359
|
+
const limit = flags.limit ? parseInt(flags.limit, 10) : void 0;
|
|
360
|
+
const cursor = flags.cursor;
|
|
361
|
+
const params = {};
|
|
362
|
+
if (limit !== void 0) params.limit = limit;
|
|
363
|
+
if (cursor) params.cursor = cursor;
|
|
364
|
+
try {
|
|
365
|
+
if (all) {
|
|
366
|
+
const fn = (p) => ns.users.listRelations(p);
|
|
367
|
+
for await (const item of streamAll(fn, params, {
|
|
368
|
+
maxPages,
|
|
369
|
+
out,
|
|
370
|
+
pageDelayMs: pageDelayFromFlags(flags)
|
|
371
|
+
})) {
|
|
372
|
+
out.stdout.write(JSON.stringify(item) + "\n");
|
|
373
|
+
}
|
|
374
|
+
} else {
|
|
375
|
+
const result = await ns.users.listRelations(params);
|
|
376
|
+
renderSuccess(result, outOpts, out);
|
|
377
|
+
}
|
|
378
|
+
} catch (err) {
|
|
379
|
+
const { CurviateError } = await import("@curviate/sdk");
|
|
380
|
+
if (err instanceof CurviateError) {
|
|
381
|
+
const { getExitCode } = await import("./exit-codes-SL3GQF7W.js");
|
|
382
|
+
renderError(err, outOpts, out);
|
|
383
|
+
process.exit(getExitCode(err.code));
|
|
384
|
+
}
|
|
385
|
+
renderUnexpectedError(err, out);
|
|
386
|
+
process.exit(1);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
async function runProfileEndorse(client, flags, out) {
|
|
390
|
+
const accountId = requireAccount(flags.account, out);
|
|
391
|
+
const ns = client.account(accountId);
|
|
392
|
+
const skillId = flags["endorsement-id"] ?? "";
|
|
393
|
+
const outOpts = resolveOutputOpts(flags);
|
|
394
|
+
let providerId;
|
|
395
|
+
try {
|
|
396
|
+
providerId = await resolveMemberProviderId(ns, flags.id ?? "");
|
|
397
|
+
} catch (err) {
|
|
398
|
+
await handleSdkError(err, outOpts, out);
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
if (flags.preview) {
|
|
402
|
+
const preview = buildPreviewOutput({
|
|
403
|
+
method: "users.endorseSkill",
|
|
404
|
+
args: { id: providerId },
|
|
405
|
+
body: { endorsement_id: skillId },
|
|
406
|
+
account: accountId
|
|
407
|
+
});
|
|
408
|
+
out.stdout.write(JSON.stringify(preview) + "\n");
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
try {
|
|
412
|
+
const result = await ns.users.endorseSkill(providerId, { endorsement_id: skillId });
|
|
413
|
+
renderSuccess(result, outOpts, out);
|
|
414
|
+
} catch (err) {
|
|
415
|
+
await handleSdkError(err, outOpts, out);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
async function handleSdkError(err, outOpts, out) {
|
|
419
|
+
const { CurviateError } = await import("@curviate/sdk");
|
|
420
|
+
if (err instanceof CurviateError) {
|
|
421
|
+
const { getExitCode } = await import("./exit-codes-SL3GQF7W.js");
|
|
422
|
+
renderError(err, outOpts, out);
|
|
423
|
+
process.exit(getExitCode(err.code));
|
|
424
|
+
}
|
|
425
|
+
renderUnexpectedError(err, out);
|
|
426
|
+
process.exit(1);
|
|
427
|
+
}
|
|
428
|
+
async function runProfileUpdate(client, flags, out) {
|
|
429
|
+
const accountId = requireAccount(flags.account, out);
|
|
430
|
+
const body = {};
|
|
431
|
+
if (flags["first-name"]) body.first_name = flags["first-name"];
|
|
432
|
+
if (flags["last-name"]) body.last_name = flags["last-name"];
|
|
433
|
+
if (flags.headline) body.headline = flags.headline;
|
|
434
|
+
if (flags.bio) body.bio = flags.bio;
|
|
435
|
+
if (flags.skills) {
|
|
436
|
+
body.skills = flags.skills.split(",").map((s) => s.trim()).filter(Boolean).map((name) => ({ name }));
|
|
437
|
+
}
|
|
438
|
+
try {
|
|
439
|
+
if (flags.picture) {
|
|
440
|
+
const buf = await readAttachment(flags.picture);
|
|
441
|
+
body.picture = toAttachmentPayload(flags.picture, buf);
|
|
442
|
+
}
|
|
443
|
+
if (flags["background-picture"]) {
|
|
444
|
+
const buf = await readAttachment(flags["background-picture"]);
|
|
445
|
+
body.background_picture = toAttachmentPayload(flags["background-picture"], buf);
|
|
446
|
+
}
|
|
447
|
+
} catch (err) {
|
|
448
|
+
if (err instanceof AttachError) {
|
|
449
|
+
out.stderr.write(`error: ${err.message}
|
|
450
|
+
`);
|
|
451
|
+
process.exit(err.exitCode);
|
|
452
|
+
}
|
|
453
|
+
throw err;
|
|
454
|
+
}
|
|
455
|
+
if (Object.keys(body).length === 0) {
|
|
456
|
+
out.stderr.write("error: nothing to update \u2014 pass at least one of --first-name, --last-name, --headline, --bio, --skills, --picture, --background-picture.\n");
|
|
457
|
+
process.exit(2);
|
|
458
|
+
}
|
|
459
|
+
if (flags.preview) {
|
|
460
|
+
const previewBody = { ...body };
|
|
461
|
+
if (previewBody.picture) previewBody.picture = "<base64 image>";
|
|
462
|
+
if (previewBody.background_picture) previewBody.background_picture = "<base64 image>";
|
|
463
|
+
const preview = buildPreviewOutput({ method: "users.update", args: { user_id: "me" }, body: previewBody, account: accountId });
|
|
464
|
+
out.stdout.write(JSON.stringify(preview) + "\n");
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
const ns = client.account(accountId);
|
|
468
|
+
const outOpts = resolveOutputOpts(flags);
|
|
469
|
+
try {
|
|
470
|
+
const result = await ns.users.update("me", body);
|
|
471
|
+
renderSuccess(result, outOpts, out);
|
|
472
|
+
} catch (err) {
|
|
473
|
+
await handleSdkError(err, outOpts, out);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
async function runProfileFollow(client, flags, out) {
|
|
477
|
+
const accountId = requireAccount(flags.account, out);
|
|
478
|
+
const ns = client.account(accountId);
|
|
479
|
+
const outOpts = resolveOutputOpts(flags);
|
|
480
|
+
let providerId;
|
|
481
|
+
try {
|
|
482
|
+
providerId = await resolveMemberProviderId(ns, flags.id ?? "");
|
|
483
|
+
} catch (err) {
|
|
484
|
+
await handleSdkError(err, outOpts, out);
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
if (flags.preview) {
|
|
488
|
+
const preview = buildPreviewOutput({ method: "users.follow", args: { user_id: providerId }, body: {}, account: accountId });
|
|
489
|
+
out.stdout.write(JSON.stringify(preview) + "\n");
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
try {
|
|
493
|
+
const result = await ns.users.follow(providerId);
|
|
494
|
+
renderSuccess(result, outOpts, out);
|
|
495
|
+
} catch (err) {
|
|
496
|
+
await handleSdkError(err, outOpts, out);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
async function runProfileUnfollow(client, flags, out) {
|
|
500
|
+
const accountId = requireAccount(flags.account, out);
|
|
501
|
+
const ns = client.account(accountId);
|
|
502
|
+
const outOpts = resolveOutputOpts(flags);
|
|
503
|
+
let providerId;
|
|
504
|
+
try {
|
|
505
|
+
providerId = await resolveMemberProviderId(ns, flags.id ?? "");
|
|
506
|
+
} catch (err) {
|
|
507
|
+
await handleSdkError(err, outOpts, out);
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
if (flags.preview) {
|
|
511
|
+
const preview = buildPreviewOutput({ method: "users.unfollow", args: { user_id: providerId }, body: {}, account: accountId });
|
|
512
|
+
out.stdout.write(JSON.stringify(preview) + "\n");
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
try {
|
|
516
|
+
const result = await ns.users.unfollow(providerId);
|
|
517
|
+
renderSuccess(result, outOpts, out);
|
|
518
|
+
} catch (err) {
|
|
519
|
+
await handleSdkError(err, outOpts, out);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
async function runProfileFollowers(client, flags, out) {
|
|
523
|
+
rejectPreviewOnRead(flags.preview, out);
|
|
524
|
+
const accountId = requireAccount(flags.account, out);
|
|
525
|
+
const resolvedId = resolveIdentifier(flags.id ?? "");
|
|
526
|
+
const ns = client.account(accountId);
|
|
527
|
+
const outOpts = resolveOutputOpts(flags);
|
|
528
|
+
const all = flags.all ?? false;
|
|
529
|
+
const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
|
|
530
|
+
const params = {};
|
|
531
|
+
if (flags.limit) params.limit = parseInt(flags.limit, 10);
|
|
532
|
+
if (flags.cursor) params.cursor = flags.cursor;
|
|
533
|
+
try {
|
|
534
|
+
if (all) {
|
|
535
|
+
const fn = (p) => ns.users.listFollowers(resolvedId, p);
|
|
536
|
+
for await (const item of streamAll(fn, params, {
|
|
537
|
+
maxPages,
|
|
538
|
+
out,
|
|
539
|
+
pageDelayMs: pageDelayFromFlags(flags)
|
|
540
|
+
})) {
|
|
541
|
+
out.stdout.write(JSON.stringify(item) + "\n");
|
|
542
|
+
}
|
|
543
|
+
} else {
|
|
544
|
+
const result = await ns.users.listFollowers(resolvedId, params);
|
|
545
|
+
renderSuccess(result, outOpts, out);
|
|
546
|
+
}
|
|
547
|
+
} catch (err) {
|
|
548
|
+
await handleSdkError(err, outOpts, out);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
async function runProfileFollowing(client, flags, out) {
|
|
552
|
+
rejectPreviewOnRead(flags.preview, out);
|
|
553
|
+
const accountId = requireAccount(flags.account, out);
|
|
554
|
+
const resolvedId = resolveIdentifier(flags.id ?? "");
|
|
555
|
+
const ns = client.account(accountId);
|
|
556
|
+
const outOpts = resolveOutputOpts(flags);
|
|
557
|
+
const all = flags.all ?? false;
|
|
558
|
+
const maxPages = flags["max-pages"] ? parseInt(flags["max-pages"], 10) : 100;
|
|
559
|
+
const params = {};
|
|
560
|
+
if (flags.limit) params.limit = parseInt(flags.limit, 10);
|
|
561
|
+
if (flags.cursor) params.cursor = flags.cursor;
|
|
562
|
+
try {
|
|
563
|
+
if (all) {
|
|
564
|
+
const fn = (p) => ns.users.listFollowing(resolvedId, p);
|
|
565
|
+
for await (const item of streamAll(fn, params, {
|
|
566
|
+
maxPages,
|
|
567
|
+
out,
|
|
568
|
+
pageDelayMs: pageDelayFromFlags(flags)
|
|
569
|
+
})) {
|
|
570
|
+
out.stdout.write(JSON.stringify(item) + "\n");
|
|
571
|
+
}
|
|
572
|
+
} else {
|
|
573
|
+
const result = await ns.users.listFollowing(resolvedId, params);
|
|
574
|
+
renderSuccess(result, outOpts, out);
|
|
575
|
+
}
|
|
576
|
+
} catch (err) {
|
|
577
|
+
await handleSdkError(err, outOpts, out);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
var profileMeCommand = defineCommand({
|
|
581
|
+
meta: { name: "me", description: "Get your own profile, or list own activity with --posts/--comments/--reactions/--followers." },
|
|
582
|
+
args: {
|
|
583
|
+
...GLOBAL_FLAGS,
|
|
584
|
+
sections: {
|
|
585
|
+
type: "string",
|
|
586
|
+
description: "Comma-separated LinkedIn sections to fetch \u2014 linkedin_experience, linkedin_education, linkedin_languages, linkedin_skills, linkedin_certifications, linkedin_volunteer_experience, linkedin_projects, linkedin_recommendations, linkedin_interests, or linkedin_* for all (each also has a _preview variant). A bare value (e.g. skills) is auto-prefixed to linkedin_skills. Only applies to the base getMe call (no activity flag)."
|
|
587
|
+
},
|
|
588
|
+
posts: {
|
|
589
|
+
type: "boolean",
|
|
590
|
+
description: "List own activity feed (posts + reposts). For authored-only posts, use 'post list'.",
|
|
591
|
+
default: false
|
|
592
|
+
},
|
|
593
|
+
comments: {
|
|
594
|
+
type: "boolean",
|
|
595
|
+
description: "List own comments.",
|
|
596
|
+
default: false
|
|
597
|
+
},
|
|
598
|
+
reactions: {
|
|
599
|
+
type: "boolean",
|
|
600
|
+
description: "List own reactions.",
|
|
601
|
+
default: false
|
|
602
|
+
},
|
|
603
|
+
followers: {
|
|
604
|
+
type: "boolean",
|
|
605
|
+
description: "List own followers.",
|
|
606
|
+
default: false
|
|
607
|
+
}
|
|
608
|
+
},
|
|
609
|
+
async run({ args }) {
|
|
610
|
+
const flags = args;
|
|
611
|
+
const cfg = await resolveEffectiveConfig({
|
|
612
|
+
apiKey: flags["api-key"],
|
|
613
|
+
baseUrl: flags["base-url"],
|
|
614
|
+
timeout: flags.timeout,
|
|
615
|
+
account: flags.account,
|
|
616
|
+
profile: flags.profile
|
|
617
|
+
});
|
|
618
|
+
if (!cfg.apiKey) {
|
|
619
|
+
process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
|
|
620
|
+
process.exit(3);
|
|
621
|
+
}
|
|
622
|
+
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
623
|
+
const out = buildOutputStreams();
|
|
624
|
+
await runProfileMe(client, { ...flags, account: flags.account ?? cfg.account }, out);
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
var profileRelationsCommand = defineCommand({
|
|
628
|
+
meta: { name: "relations", description: "List your 1st-degree connections." },
|
|
629
|
+
args: { ...GLOBAL_FLAGS },
|
|
630
|
+
async run({ args }) {
|
|
631
|
+
const flags = args;
|
|
632
|
+
const cfg = await resolveEffectiveConfig({
|
|
633
|
+
apiKey: flags["api-key"],
|
|
634
|
+
baseUrl: flags["base-url"],
|
|
635
|
+
timeout: flags.timeout,
|
|
636
|
+
account: flags.account,
|
|
637
|
+
profile: flags.profile
|
|
638
|
+
});
|
|
639
|
+
if (!cfg.apiKey) {
|
|
640
|
+
process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
|
|
641
|
+
process.exit(3);
|
|
642
|
+
}
|
|
643
|
+
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
644
|
+
const out = buildOutputStreams();
|
|
645
|
+
await runProfileRelations(client, { ...flags, account: flags.account ?? cfg.account }, out);
|
|
646
|
+
}
|
|
647
|
+
});
|
|
648
|
+
var profileEndorseCommand = defineCommand({
|
|
649
|
+
meta: { name: "endorse", description: "Endorse a skill on a member's profile." },
|
|
650
|
+
args: {
|
|
651
|
+
...GLOBAL_FLAGS,
|
|
652
|
+
id: { type: "positional", description: "Member identifier (URL, slug, or provider id). A URL/slug is resolved to the provider id automatically (a slug is not accepted directly by the endorse endpoint)." },
|
|
653
|
+
"endorsement-id": {
|
|
654
|
+
type: "string",
|
|
655
|
+
description: "Endorsement ID to endorse \u2014 get it from the target's skills section via `profile <id> --sections linkedin_skills`.",
|
|
656
|
+
required: true
|
|
657
|
+
}
|
|
658
|
+
},
|
|
659
|
+
async run({ args }) {
|
|
660
|
+
const flags = args;
|
|
661
|
+
const cfg = await resolveEffectiveConfig({
|
|
662
|
+
apiKey: args["api-key"],
|
|
663
|
+
baseUrl: args["base-url"],
|
|
664
|
+
timeout: args.timeout,
|
|
665
|
+
account: flags.account,
|
|
666
|
+
profile: args.profile
|
|
667
|
+
});
|
|
668
|
+
if (!cfg.apiKey) {
|
|
669
|
+
process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
|
|
670
|
+
process.exit(3);
|
|
671
|
+
}
|
|
672
|
+
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
673
|
+
const out = buildOutputStreams();
|
|
674
|
+
await runProfileEndorse(client, { ...flags, account: flags.account ?? cfg.account }, out);
|
|
675
|
+
}
|
|
676
|
+
});
|
|
677
|
+
async function withClient(flags, fn) {
|
|
678
|
+
const cfg = await resolveEffectiveConfig({
|
|
679
|
+
apiKey: flags["api-key"],
|
|
680
|
+
baseUrl: flags["base-url"],
|
|
681
|
+
timeout: flags.timeout,
|
|
682
|
+
account: flags.account,
|
|
683
|
+
profile: flags.profile
|
|
684
|
+
});
|
|
685
|
+
if (!cfg.apiKey) {
|
|
686
|
+
process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
|
|
687
|
+
process.exit(3);
|
|
688
|
+
}
|
|
689
|
+
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
690
|
+
const out = buildOutputStreams();
|
|
691
|
+
await fn(client, { ...flags, account: flags.account ?? cfg.account }, out);
|
|
692
|
+
}
|
|
693
|
+
var profileUpdateCommand = defineCommand({
|
|
694
|
+
meta: { name: "update", description: "Update your own profile (headline, bio, name, skills, photos)." },
|
|
695
|
+
args: {
|
|
696
|
+
...WRITE_SINGLE_FLAGS,
|
|
697
|
+
headline: { type: "string", description: "New headline." },
|
|
698
|
+
bio: { type: "string", description: "New about/bio text." },
|
|
699
|
+
"first-name": { type: "string", description: "New first name." },
|
|
700
|
+
"last-name": { type: "string", description: "New last name." },
|
|
701
|
+
skills: { type: "string", description: "Comma-separated skill names to add (add-only)." },
|
|
702
|
+
picture: { type: "string", description: "New profile photo \u2014 path to an image file." },
|
|
703
|
+
"background-picture": { type: "string", description: "New cover/banner photo \u2014 path to an image file." }
|
|
704
|
+
},
|
|
705
|
+
async run({ args }) {
|
|
706
|
+
await withClient(args, runProfileUpdate);
|
|
707
|
+
}
|
|
708
|
+
});
|
|
709
|
+
var profileFollowCommand = defineCommand({
|
|
710
|
+
meta: { name: "follow", description: "Follow a member (sends a connect request if their profile is private)." },
|
|
711
|
+
args: {
|
|
712
|
+
...WRITE_SINGLE_FLAGS,
|
|
713
|
+
id: { type: "positional", description: "Member identifier (URL, slug, provider id)." }
|
|
714
|
+
},
|
|
715
|
+
async run({ args }) {
|
|
716
|
+
await withClient(args, runProfileFollow);
|
|
717
|
+
}
|
|
718
|
+
});
|
|
719
|
+
var profileUnfollowCommand = defineCommand({
|
|
720
|
+
meta: { name: "unfollow", description: "Unfollow a member (idempotent)." },
|
|
721
|
+
args: {
|
|
722
|
+
...WRITE_SINGLE_FLAGS,
|
|
723
|
+
id: { type: "positional", description: "Member identifier (URL, slug, provider id)." }
|
|
724
|
+
},
|
|
725
|
+
async run({ args }) {
|
|
726
|
+
await withClient(args, runProfileUnfollow);
|
|
727
|
+
}
|
|
728
|
+
});
|
|
729
|
+
var profileFollowersCommand = defineCommand({
|
|
730
|
+
meta: { name: "followers", description: "List a member's followers (accepts 'me')." },
|
|
731
|
+
args: {
|
|
732
|
+
...GLOBAL_FLAGS,
|
|
733
|
+
id: { type: "positional", description: "Member identifier (URL, slug, provider id, or 'me')." }
|
|
734
|
+
},
|
|
735
|
+
async run({ args }) {
|
|
736
|
+
await withClient(args, runProfileFollowers);
|
|
737
|
+
}
|
|
738
|
+
});
|
|
739
|
+
var profileFollowingCommand = defineCommand({
|
|
740
|
+
meta: { name: "following", description: "List who a member follows (accepts 'me')." },
|
|
741
|
+
args: {
|
|
742
|
+
...GLOBAL_FLAGS,
|
|
743
|
+
id: { type: "positional", description: "Member identifier (URL, slug, provider id, or 'me')." }
|
|
744
|
+
},
|
|
745
|
+
async run({ args }) {
|
|
746
|
+
await withClient(args, runProfileFollowing);
|
|
747
|
+
}
|
|
748
|
+
});
|
|
749
|
+
var profileCommand = defineCommand({
|
|
750
|
+
meta: { name: "profile", description: "LinkedIn profile operations." },
|
|
751
|
+
args: {
|
|
752
|
+
...GLOBAL_FLAGS,
|
|
753
|
+
id: { type: "positional", description: "Member identifier (URL, slug, or URN). Optional for subcommands.", required: false },
|
|
754
|
+
posts: { type: "boolean", description: "List the profile's posts.", default: false },
|
|
755
|
+
comments: { type: "boolean", description: "List the profile's comments.", default: false },
|
|
756
|
+
reactions: { type: "boolean", description: "List the profile's reactions.", default: false },
|
|
757
|
+
followers: { type: "boolean", description: "List the profile's followers.", default: false },
|
|
758
|
+
"is-company": { type: "boolean", description: "When listing posts, treat the profile as a company page.", default: false },
|
|
759
|
+
sections: {
|
|
760
|
+
type: "string",
|
|
761
|
+
description: "Comma-separated LinkedIn sections to fetch \u2014 linkedin_experience, linkedin_education, linkedin_languages, linkedin_skills, linkedin_certifications, linkedin_volunteer_experience, linkedin_projects, linkedin_recommendations, linkedin_interests, or linkedin_* for all (each also has a _preview variant). A bare value (e.g. skills) is auto-prefixed to linkedin_skills."
|
|
762
|
+
}
|
|
763
|
+
},
|
|
764
|
+
subCommands: {
|
|
765
|
+
me: profileMeCommand,
|
|
766
|
+
relations: profileRelationsCommand,
|
|
767
|
+
endorse: profileEndorseCommand,
|
|
768
|
+
update: profileUpdateCommand,
|
|
769
|
+
follow: profileFollowCommand,
|
|
770
|
+
unfollow: profileUnfollowCommand,
|
|
771
|
+
followers: profileFollowersCommand,
|
|
772
|
+
following: profileFollowingCommand
|
|
773
|
+
},
|
|
774
|
+
async run({ args }) {
|
|
775
|
+
const flags = args;
|
|
776
|
+
if (!flags.id) {
|
|
777
|
+
process.stderr.write(
|
|
778
|
+
"Usage: curviate profile <id> [--posts|--comments|--reactions|--followers]\n curviate profile me\n curviate profile relations\n curviate profile followers <id> | following <id>\n curviate profile follow <id> | unfollow <id>\n curviate profile update [--headline|--bio|--first-name|--last-name|--skills|--picture]\n curviate profile endorse <id> --endorsement-id <id>\n"
|
|
779
|
+
);
|
|
780
|
+
process.exit(2);
|
|
781
|
+
}
|
|
782
|
+
const cfg = await resolveEffectiveConfig({
|
|
783
|
+
apiKey: flags["api-key"],
|
|
784
|
+
baseUrl: flags["base-url"],
|
|
785
|
+
timeout: flags.timeout,
|
|
786
|
+
account: flags.account,
|
|
787
|
+
profile: flags.profile
|
|
788
|
+
});
|
|
789
|
+
if (!cfg.apiKey) {
|
|
790
|
+
process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
|
|
791
|
+
process.exit(3);
|
|
792
|
+
}
|
|
793
|
+
const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
|
|
794
|
+
const out = buildOutputStreams();
|
|
795
|
+
await runProfileGet(client, { ...flags, account: flags.account ?? cfg.account }, out);
|
|
796
|
+
}
|
|
797
|
+
});
|
|
798
|
+
export {
|
|
799
|
+
profileCommand,
|
|
800
|
+
runProfileEndorse,
|
|
801
|
+
runProfileFollow,
|
|
802
|
+
runProfileFollowers,
|
|
803
|
+
runProfileFollowing,
|
|
804
|
+
runProfileGet,
|
|
805
|
+
runProfileMe,
|
|
806
|
+
runProfileRelations,
|
|
807
|
+
runProfileUnfollow,
|
|
808
|
+
runProfileUpdate
|
|
809
|
+
};
|