@curviate/cli 0.1.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.
@@ -0,0 +1,566 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ BinaryOutputError,
4
+ writeBinaryOutput
5
+ } from "./chunk-UWO2D4HW.js";
6
+ import {
7
+ AttachError,
8
+ readAttachment
9
+ } from "./chunk-Q43HZUN3.js";
10
+ import {
11
+ buildPreviewOutput
12
+ } from "./chunk-R3VLWLVV.js";
13
+ import {
14
+ resolveIdentifier
15
+ } from "./chunk-BNUTM6KD.js";
16
+ import {
17
+ createClient,
18
+ renderError,
19
+ renderSuccess,
20
+ renderUnexpectedError,
21
+ resolveEffectiveConfig
22
+ } from "./chunk-2NCPJJPC.js";
23
+ import {
24
+ GLOBAL_FLAGS
25
+ } from "./chunk-6JNCLLNY.js";
26
+
27
+ // src/commands/message.ts
28
+ import { defineCommand } from "citty";
29
+ function buildOutputStreams() {
30
+ return {
31
+ stdout: { write: (s) => process.stdout.write(s) },
32
+ stderr: { write: (s) => process.stderr.write(s) }
33
+ };
34
+ }
35
+ function requireAccount(account, out) {
36
+ if (!account) {
37
+ out.stderr.write("error: --account is required for this command. Set it via --account, CURVIATE_ACCOUNT, or `curviate config set-account`.\n");
38
+ process.exit(2);
39
+ }
40
+ return account;
41
+ }
42
+ function rejectPreviewOnRead(preview, out) {
43
+ if (preview) {
44
+ out.stderr.write("error: --preview is only valid on write commands (mutations). Reads just run.\n");
45
+ process.exit(2);
46
+ }
47
+ }
48
+ function rejectAllOnNonPaginated(all, out) {
49
+ if (all) {
50
+ out.stderr.write("error: --all is not supported on non-paginated commands.\n");
51
+ process.exit(2);
52
+ }
53
+ }
54
+ function resolveOutputOpts(flags) {
55
+ return {
56
+ json: (flags.json ?? false) || !process.stdout.isTTY,
57
+ isTTY: process.stdout.isTTY ?? false,
58
+ fields: flags.fields
59
+ };
60
+ }
61
+ function normalizeAttachPaths(attach) {
62
+ if (!attach) return [];
63
+ return Array.isArray(attach) ? attach : [attach];
64
+ }
65
+ async function handleSdkError(err, outOpts, out) {
66
+ const { CurviateError } = await import("@curviate/sdk");
67
+ if (err instanceof CurviateError) {
68
+ const { getExitCode } = await import("./exit-codes-NFIR57ZA.js");
69
+ renderError(err, outOpts, out);
70
+ process.exit(getExitCode(err.code));
71
+ }
72
+ renderUnexpectedError(err, out);
73
+ process.exit(1);
74
+ }
75
+ async function runMessageNew(client, flags, out) {
76
+ const accountId = requireAccount(flags.account, out);
77
+ const attendeeId = flags.to ?? "";
78
+ const text = flags.text ?? "";
79
+ const attachPaths = normalizeAttachPaths(flags.attach);
80
+ let attachBuffers = [];
81
+ try {
82
+ attachBuffers = await Promise.all(attachPaths.map((p) => readAttachment(p)));
83
+ } catch (err) {
84
+ if (err instanceof AttachError) {
85
+ out.stderr.write(`error: ${err.message}
86
+ `);
87
+ process.exit(err.exitCode);
88
+ }
89
+ throw err;
90
+ }
91
+ const body = {
92
+ attendees_ids: [attendeeId],
93
+ text
94
+ };
95
+ if (flags.preview) {
96
+ const preview = buildPreviewOutput({
97
+ method: "messaging.startChat",
98
+ args: { attendees_ids: [attendeeId] },
99
+ body: { ...body },
100
+ account: accountId,
101
+ attachments: attachBuffers.map((buf, i) => ({
102
+ name: attachPaths[i] ? attachPaths[i].split("/").pop() ?? attachPaths[i] : `attachment_${i}`,
103
+ buffer: buf
104
+ }))
105
+ });
106
+ out.stdout.write(JSON.stringify(preview) + "\n");
107
+ return;
108
+ }
109
+ if (attachBuffers.length > 0) {
110
+ body["attachments"] = attachBuffers;
111
+ }
112
+ const ns = client.account(accountId);
113
+ const outOpts = resolveOutputOpts(flags);
114
+ try {
115
+ const result = await ns.messaging.startChat(body);
116
+ renderSuccess(result, outOpts, out);
117
+ } catch (err) {
118
+ await handleSdkError(err, outOpts, out);
119
+ }
120
+ }
121
+ async function runMessageSend(client, flags, out) {
122
+ const accountId = requireAccount(flags.account, out);
123
+ const chatId = flags.chatId ?? "";
124
+ const text = flags.text ?? "";
125
+ const attachPaths = normalizeAttachPaths(flags.attach);
126
+ let attachBuffers = [];
127
+ try {
128
+ attachBuffers = await Promise.all(attachPaths.map((p) => readAttachment(p)));
129
+ } catch (err) {
130
+ if (err instanceof AttachError) {
131
+ out.stderr.write(`error: ${err.message}
132
+ `);
133
+ process.exit(err.exitCode);
134
+ }
135
+ throw err;
136
+ }
137
+ const body = { text };
138
+ if (flags.preview) {
139
+ const preview = buildPreviewOutput({
140
+ method: "messaging.sendMessage",
141
+ args: { chat_id: chatId },
142
+ body: { ...body },
143
+ account: accountId,
144
+ attachments: attachBuffers.map((buf, i) => ({
145
+ name: attachPaths[i] ? attachPaths[i].split("/").pop() ?? attachPaths[i] : `attachment_${i}`,
146
+ buffer: buf
147
+ }))
148
+ });
149
+ out.stdout.write(JSON.stringify(preview) + "\n");
150
+ return;
151
+ }
152
+ if (attachBuffers.length > 0) {
153
+ body["attachments"] = attachBuffers;
154
+ }
155
+ const ns = client.account(accountId);
156
+ const outOpts = resolveOutputOpts(flags);
157
+ try {
158
+ const result = await ns.messaging.sendMessage(chatId, body);
159
+ renderSuccess(result, outOpts, out);
160
+ } catch (err) {
161
+ await handleSdkError(err, outOpts, out);
162
+ }
163
+ }
164
+ async function runMessageGet(client, flags, out) {
165
+ rejectPreviewOnRead(flags.preview, out);
166
+ rejectAllOnNonPaginated(flags.all, out);
167
+ const accountId = requireAccount(flags.account, out);
168
+ const messageId = flags.messageId ?? "";
169
+ const ns = client.account(accountId);
170
+ const outOpts = resolveOutputOpts(flags);
171
+ try {
172
+ const result = await ns.messaging.getMessage(messageId);
173
+ renderSuccess(result, outOpts, out);
174
+ } catch (err) {
175
+ await handleSdkError(err, outOpts, out);
176
+ }
177
+ }
178
+ async function runMessageEdit(client, flags, out) {
179
+ const accountId = requireAccount(flags.account, out);
180
+ const messageId = flags.messageId ?? "";
181
+ const text = flags.text ?? "";
182
+ if (flags.preview) {
183
+ const preview = buildPreviewOutput({
184
+ method: "messaging.editMessage",
185
+ args: { message_id: messageId },
186
+ body: { text },
187
+ account: accountId
188
+ });
189
+ out.stdout.write(JSON.stringify(preview) + "\n");
190
+ return;
191
+ }
192
+ const ns = client.account(accountId);
193
+ const outOpts = resolveOutputOpts(flags);
194
+ try {
195
+ const result = await ns.messaging.editMessage(messageId, { text });
196
+ renderSuccess(result, outOpts, out);
197
+ } catch (err) {
198
+ await handleSdkError(err, outOpts, out);
199
+ }
200
+ }
201
+ async function runMessageDelete(client, flags, out) {
202
+ const accountId = requireAccount(flags.account, out);
203
+ const messageId = flags.messageId ?? "";
204
+ if (flags.preview) {
205
+ const preview = buildPreviewOutput({
206
+ method: "messaging.deleteMessage",
207
+ args: { message_id: messageId },
208
+ body: {},
209
+ account: accountId
210
+ });
211
+ out.stdout.write(JSON.stringify(preview) + "\n");
212
+ return;
213
+ }
214
+ const ns = client.account(accountId);
215
+ const outOpts = resolveOutputOpts(flags);
216
+ try {
217
+ const result = await ns.messaging.deleteMessage(messageId);
218
+ renderSuccess(result, outOpts, out);
219
+ } catch (err) {
220
+ await handleSdkError(err, outOpts, out);
221
+ }
222
+ }
223
+ async function runMessageReact(client, flags, out) {
224
+ const accountId = requireAccount(flags.account, out);
225
+ const messageId = flags.messageId ?? "";
226
+ const reaction = flags.emoji ?? "";
227
+ if (flags.preview) {
228
+ const preview = buildPreviewOutput({
229
+ method: "messaging.addReaction",
230
+ args: { message_id: messageId },
231
+ body: { reaction },
232
+ account: accountId
233
+ });
234
+ out.stdout.write(JSON.stringify(preview) + "\n");
235
+ return;
236
+ }
237
+ const ns = client.account(accountId);
238
+ const outOpts = resolveOutputOpts(flags);
239
+ try {
240
+ const result = await ns.messaging.addReaction(messageId, { reaction });
241
+ renderSuccess(result, outOpts, out);
242
+ } catch (err) {
243
+ await handleSdkError(err, outOpts, out);
244
+ }
245
+ }
246
+ async function runMessageAttachment(client, flags, out, isTTY) {
247
+ rejectPreviewOnRead(flags.preview, out);
248
+ const accountId = requireAccount(flags.account, out);
249
+ const messageId = flags.messageId ?? "";
250
+ const attachmentId = flags.attachmentId ?? "";
251
+ const ns = client.account(accountId);
252
+ try {
253
+ const data = await ns.messaging.getAttachment(messageId, attachmentId);
254
+ await writeBinaryOutput(data, {
255
+ outputPath: flags.output,
256
+ isTTY,
257
+ stdout: process.stdout
258
+ });
259
+ } catch (err) {
260
+ if (err instanceof BinaryOutputError) {
261
+ out.stderr.write(`error: ${err.message}
262
+ `);
263
+ process.exit(err.exitCode);
264
+ }
265
+ const outOpts = resolveOutputOpts(flags);
266
+ await handleSdkError(err, outOpts, out);
267
+ }
268
+ }
269
+ async function runMessageInMail(client, flags, out) {
270
+ const accountId = requireAccount(flags.account, out);
271
+ const recipientUrn = resolveIdentifier(flags.to ?? "");
272
+ const subject = flags.subject ?? "";
273
+ const text = flags.text ?? "";
274
+ const body = {
275
+ recipient_urn: recipientUrn,
276
+ subject,
277
+ text
278
+ };
279
+ if (flags.preview) {
280
+ const preview = buildPreviewOutput({
281
+ method: "messaging.sendInMail",
282
+ args: { recipient_urn: recipientUrn },
283
+ body,
284
+ account: accountId
285
+ });
286
+ out.stdout.write(JSON.stringify(preview) + "\n");
287
+ return;
288
+ }
289
+ const ns = client.account(accountId);
290
+ const outOpts = resolveOutputOpts(flags);
291
+ try {
292
+ const result = await ns.messaging.sendInMail(body);
293
+ renderSuccess(result, outOpts, out);
294
+ } catch (err) {
295
+ await handleSdkError(err, outOpts, out);
296
+ }
297
+ }
298
+ async function runMessageInMailBalance(client, flags, out) {
299
+ rejectPreviewOnRead(flags.preview, out);
300
+ rejectAllOnNonPaginated(flags.all, out);
301
+ const accountId = requireAccount(flags.account, out);
302
+ const ns = client.account(accountId);
303
+ const outOpts = resolveOutputOpts(flags);
304
+ try {
305
+ const result = await ns.messaging.getInMailBalance();
306
+ renderSuccess(result, outOpts, out);
307
+ } catch (err) {
308
+ await handleSdkError(err, outOpts, out);
309
+ }
310
+ }
311
+ var messageNewCommand = defineCommand({
312
+ meta: { name: "new", description: "Start a new chat with one or more members." },
313
+ args: {
314
+ ...GLOBAL_FLAGS,
315
+ to: { type: "string", description: "Attendee provider ID (e.g. ACo\u2026).", required: true },
316
+ text: { type: "positional", description: "Opening message text." },
317
+ attach: { type: "string", description: "File to attach (repeatable)." }
318
+ },
319
+ async run({ args }) {
320
+ const flags = args;
321
+ const cfg = await resolveEffectiveConfig({
322
+ apiKey: flags["api-key"],
323
+ baseUrl: flags["base-url"],
324
+ timeout: flags.timeout,
325
+ account: flags.account,
326
+ profile: flags.profile
327
+ });
328
+ if (!cfg.apiKey) {
329
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
330
+ process.exit(3);
331
+ }
332
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
333
+ const out = buildOutputStreams();
334
+ await runMessageNew(client, { ...flags, account: flags.account ?? cfg.account }, out);
335
+ }
336
+ });
337
+ var messageGetCommand = defineCommand({
338
+ meta: { name: "get", description: "Get a message by ID." },
339
+ args: {
340
+ ...GLOBAL_FLAGS,
341
+ messageId: { type: "positional", description: "Message ID." }
342
+ },
343
+ async run({ args }) {
344
+ const flags = args;
345
+ const cfg = await resolveEffectiveConfig({
346
+ apiKey: flags["api-key"],
347
+ baseUrl: flags["base-url"],
348
+ timeout: flags.timeout,
349
+ account: flags.account,
350
+ profile: flags.profile
351
+ });
352
+ if (!cfg.apiKey) {
353
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
354
+ process.exit(3);
355
+ }
356
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
357
+ const out = buildOutputStreams();
358
+ await runMessageGet(client, { ...flags, account: flags.account ?? cfg.account }, out);
359
+ }
360
+ });
361
+ var messageEditCommand = defineCommand({
362
+ meta: { name: "edit", description: "Edit a message (within the allowed window)." },
363
+ args: {
364
+ ...GLOBAL_FLAGS,
365
+ messageId: { type: "positional", description: "Message ID." },
366
+ text: { type: "positional", description: "Replacement text." }
367
+ },
368
+ async run({ args }) {
369
+ const flags = args;
370
+ const cfg = await resolveEffectiveConfig({
371
+ apiKey: flags["api-key"],
372
+ baseUrl: flags["base-url"],
373
+ timeout: flags.timeout,
374
+ account: flags.account,
375
+ profile: flags.profile
376
+ });
377
+ if (!cfg.apiKey) {
378
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
379
+ process.exit(3);
380
+ }
381
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
382
+ const out = buildOutputStreams();
383
+ await runMessageEdit(client, { ...flags, account: flags.account ?? cfg.account }, out);
384
+ }
385
+ });
386
+ var messageDeleteCommand = defineCommand({
387
+ meta: { name: "delete", description: "Delete a message." },
388
+ args: {
389
+ ...GLOBAL_FLAGS,
390
+ messageId: { type: "positional", description: "Message ID." }
391
+ },
392
+ async run({ args }) {
393
+ const flags = args;
394
+ const cfg = await resolveEffectiveConfig({
395
+ apiKey: flags["api-key"],
396
+ baseUrl: flags["base-url"],
397
+ timeout: flags.timeout,
398
+ account: flags.account,
399
+ profile: flags.profile
400
+ });
401
+ if (!cfg.apiKey) {
402
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
403
+ process.exit(3);
404
+ }
405
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
406
+ const out = buildOutputStreams();
407
+ await runMessageDelete(client, { ...flags, account: flags.account ?? cfg.account }, out);
408
+ }
409
+ });
410
+ var messageReactCommand = defineCommand({
411
+ meta: { name: "react", description: "Add an emoji reaction to a message." },
412
+ args: {
413
+ ...GLOBAL_FLAGS,
414
+ messageId: { type: "positional", description: "Message ID." },
415
+ emoji: { type: "string", description: "Native emoji reaction value (e.g. \u{1F44D}).", required: true }
416
+ },
417
+ async run({ args }) {
418
+ const flags = args;
419
+ const cfg = await resolveEffectiveConfig({
420
+ apiKey: flags["api-key"],
421
+ baseUrl: flags["base-url"],
422
+ timeout: flags.timeout,
423
+ account: flags.account,
424
+ profile: flags.profile
425
+ });
426
+ if (!cfg.apiKey) {
427
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
428
+ process.exit(3);
429
+ }
430
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
431
+ const out = buildOutputStreams();
432
+ await runMessageReact(client, { ...flags, account: flags.account ?? cfg.account }, out);
433
+ }
434
+ });
435
+ var messageAttachmentCommand = defineCommand({
436
+ meta: { name: "attachment", description: "Download a message attachment." },
437
+ args: {
438
+ ...GLOBAL_FLAGS,
439
+ messageId: { type: "positional", description: "Message ID." },
440
+ attachmentId: { type: "positional", description: "Attachment ID." },
441
+ output: { type: "string", alias: "o", description: "Path to write the file to." }
442
+ },
443
+ async run({ args }) {
444
+ const flags = args;
445
+ const cfg = await resolveEffectiveConfig({
446
+ apiKey: flags["api-key"],
447
+ baseUrl: flags["base-url"],
448
+ timeout: flags.timeout,
449
+ account: flags.account,
450
+ profile: flags.profile
451
+ });
452
+ if (!cfg.apiKey) {
453
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
454
+ process.exit(3);
455
+ }
456
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
457
+ const out = buildOutputStreams();
458
+ await runMessageAttachment(
459
+ client,
460
+ { ...flags, account: flags.account ?? cfg.account },
461
+ out,
462
+ process.stdout.isTTY ?? false
463
+ );
464
+ }
465
+ });
466
+ var messageInMailCommand = defineCommand({
467
+ meta: { name: "inmail", description: "Send an InMail to a member." },
468
+ args: {
469
+ ...GLOBAL_FLAGS,
470
+ to: { type: "string", description: "Recipient LinkedIn URN, URL, or slug.", required: true },
471
+ subject: { type: "string", description: "InMail subject line.", required: true },
472
+ text: { type: "positional", description: "InMail body text." }
473
+ },
474
+ async run({ args }) {
475
+ const flags = args;
476
+ const cfg = await resolveEffectiveConfig({
477
+ apiKey: flags["api-key"],
478
+ baseUrl: flags["base-url"],
479
+ timeout: flags.timeout,
480
+ account: flags.account,
481
+ profile: flags.profile
482
+ });
483
+ if (!cfg.apiKey) {
484
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
485
+ process.exit(3);
486
+ }
487
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
488
+ const out = buildOutputStreams();
489
+ await runMessageInMail(client, { ...flags, account: flags.account ?? cfg.account }, out);
490
+ }
491
+ });
492
+ var messageInMailBalanceCommand = defineCommand({
493
+ meta: { name: "inmail-balance", description: "Get InMail credit balance." },
494
+ args: { ...GLOBAL_FLAGS },
495
+ async run({ args }) {
496
+ const flags = args;
497
+ const cfg = await resolveEffectiveConfig({
498
+ apiKey: flags["api-key"],
499
+ baseUrl: flags["base-url"],
500
+ timeout: flags.timeout,
501
+ account: flags.account,
502
+ profile: flags.profile
503
+ });
504
+ if (!cfg.apiKey) {
505
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
506
+ process.exit(3);
507
+ }
508
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
509
+ const out = buildOutputStreams();
510
+ await runMessageInMailBalance(client, { ...flags, account: flags.account ?? cfg.account }, out);
511
+ }
512
+ });
513
+ var messageCommand = defineCommand({
514
+ meta: { name: "message", description: "Send and manage LinkedIn messages." },
515
+ args: {
516
+ ...GLOBAL_FLAGS,
517
+ chatId: { type: "positional", description: "Chat ID to send a message to.", required: false },
518
+ text: { type: "positional", description: "Message text.", required: false },
519
+ attach: { type: "string", description: "File to attach (repeatable)." }
520
+ },
521
+ subCommands: {
522
+ new: messageNewCommand,
523
+ get: messageGetCommand,
524
+ edit: messageEditCommand,
525
+ delete: messageDeleteCommand,
526
+ react: messageReactCommand,
527
+ attachment: messageAttachmentCommand,
528
+ inmail: messageInMailCommand,
529
+ "inmail-balance": messageInMailBalanceCommand
530
+ },
531
+ async run({ args }) {
532
+ const flags = args;
533
+ if (!flags.chatId) {
534
+ process.stderr.write(
535
+ 'Usage: curviate message new --to <attendee> "<text>" [--attach <file>\u2026]\n curviate message <chat_id> "<text>" [--attach <file>\u2026]\n curviate message get <message_id>\n curviate message edit <message_id> "<text>"\n curviate message delete <message_id>\n curviate message react <message_id> --emoji <e>\n curviate message attachment <message_id> <attachment_id> [-o <file>]\n curviate message inmail --to <id> --subject <s> "<text>"\n curviate message inmail-balance\n'
536
+ );
537
+ return;
538
+ }
539
+ const cfg = await resolveEffectiveConfig({
540
+ apiKey: flags["api-key"],
541
+ baseUrl: flags["base-url"],
542
+ timeout: flags.timeout,
543
+ account: flags.account,
544
+ profile: flags.profile
545
+ });
546
+ if (!cfg.apiKey) {
547
+ process.stderr.write("error: no API key \u2014 run `curviate login` or pass --api-key.\n");
548
+ process.exit(3);
549
+ }
550
+ const client = createClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl, timeout: cfg.timeout });
551
+ const out = buildOutputStreams();
552
+ await runMessageSend(client, { ...flags, account: flags.account ?? cfg.account }, out);
553
+ }
554
+ });
555
+ export {
556
+ messageCommand,
557
+ runMessageAttachment,
558
+ runMessageDelete,
559
+ runMessageEdit,
560
+ runMessageGet,
561
+ runMessageInMail,
562
+ runMessageInMailBalance,
563
+ runMessageNew,
564
+ runMessageReact,
565
+ runMessageSend
566
+ };