@usesocial/cli 0.3.6 → 0.4.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @usesocial/cli
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#25](https://github.com/usesocial/monorepo/pull/25) [`1121b7c`](https://github.com/usesocial/monorepo/commit/1121b7c938bfb213606722247d50a5eafca138c4) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - Add `social feedback bug|feature` — submit a bug report or feature request by piping text via stdin (`echo "..." | social feedback bug`). Each submission is captured server-side and acknowledged with a reference id.
8
+
3
9
  ## 0.3.6
4
10
 
5
11
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -1392,6 +1392,9 @@ declare const createSocialCommand: (deps?: {
1392
1392
  summary: any;
1393
1393
  list: any;
1394
1394
  };
1395
+ feedback: {
1396
+ submit: any;
1397
+ };
1395
1398
  };
1396
1399
  api: KyInstance;
1397
1400
  parseResourceId: (name: string, value: unknown) => string;
package/dist/index.mjs CHANGED
@@ -9740,6 +9740,14 @@ pgTable("profiles", {
9740
9740
  index$1("profiles_platform_handle_idx").on(table.platform, table.handle),
9741
9741
  check("profiles_platform_check", sql`${table.platform} in ('linkedin', 'x')`)
9742
9742
  ]);
9743
+ pgTable("feedback_submissions", {
9744
+ id: text$1("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
9745
+ userId: text$1("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
9746
+ type: text$1("type", { enum: ["bug", "feature"] }).notNull(),
9747
+ text: text$1("text").notNull(),
9748
+ issueNumber: integer$1("issue_number"),
9749
+ createdAt: timestamptz("created_at").notNull().defaultNow()
9750
+ }, (table) => [index$1("feedback_submissions_user_created_idx").on(table.userId, table.createdAt.desc()), check("feedback_submissions_type_check", sql`${table.type} in ('bug', 'feature')`)]);
9743
9751
  pgTable("cli_session_grants", {
9744
9752
  sessionId: text$1("session_id").primaryKey().references(() => session.id, { onDelete: "cascade" }),
9745
9753
  userId: text$1("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
@@ -13333,8 +13341,8 @@ const dataWithAuditableWriteTarget = (op, data, body) => {
13333
13341
  post_id: postId
13334
13342
  };
13335
13343
  };
13336
- const trimTrailingNewline$1 = (value) => value.endsWith("\r\n") ? value.slice(0, -2) : value.endsWith("\n") ? value.slice(0, -1) : value;
13337
- const noBodyTextError$1 = (commandLabel) => new UsageError(`No body text. Pipe it via stdin: \`echo "..." | ${commandLabel}\`.`);
13344
+ const trimTrailingNewline$2 = (value) => value.endsWith("\r\n") ? value.slice(0, -2) : value.endsWith("\n") ? value.slice(0, -1) : value;
13345
+ const noBodyTextError$2 = (commandLabel) => new UsageError(`No body text. Pipe it via stdin: \`echo "..." | ${commandLabel}\`.`);
13338
13346
  const parseStdinBody$1 = (deps, bodyTextName, bodyTextKey, value) => {
13339
13347
  try {
13340
13348
  JSON.parse(value);
@@ -13350,12 +13358,12 @@ const resolveBodyTextFromStdin$1 = async (op, deps, args, commandLabel) => {
13350
13358
  const displayTextArg = bodyTextDisplayKeyFor$1(op) ?? bodyTextArg;
13351
13359
  const required = stdinBodyTextRequired$1(op);
13352
13360
  if (deps.isStdinTTY()) {
13353
- if (required) throw noBodyTextError$1(commandLabel);
13361
+ if (required) throw noBodyTextError$2(commandLabel);
13354
13362
  return;
13355
13363
  }
13356
- const piped = trimTrailingNewline$1(await deps.readStdin());
13364
+ const piped = trimTrailingNewline$2(await deps.readStdin());
13357
13365
  if (piped.length > 0) args.body = JSON.stringify(parseStdinBody$1(deps, displayTextArg, bodyTextArg, piped));
13358
- else if (required) throw noBodyTextError$1(commandLabel);
13366
+ else if (required) throw noBodyTextError$2(commandLabel);
13359
13367
  };
13360
13368
  const runOperation$1 = async (op, contract, deps, args, rawArgs = []) => {
13361
13369
  rejectUnsupportedArgs(commandPathFor(op), args, Object.keys(buildArgs$1(op)));
@@ -14002,11 +14010,11 @@ const buildMessageEdit = (deps) => {
14002
14010
  const account = typeof args.account === "string" ? args.account : void 0;
14003
14011
  const message_id = messageIdFrom(deps, args.message_id ?? positionals[1]);
14004
14012
  let textInput;
14005
- if (deps.isStdinTTY()) throw noBodyTextError$1("social linkedin message <target> edit message_id:<id>");
14006
- const piped = trimTrailingNewline$1(await deps.readStdin());
14013
+ if (deps.isStdinTTY()) throw noBodyTextError$2("social linkedin message <target> edit message_id:<id>");
14014
+ const piped = trimTrailingNewline$2(await deps.readStdin());
14007
14015
  if (piped.length > 0) textInput = piped;
14008
14016
  const text = textInput === void 0 ? void 0 : deps.parseBodyText("<text>", textInput);
14009
- if (text === void 0) throw noBodyTextError$1("social linkedin message <target> edit message_id:<id>");
14017
+ if (text === void 0) throw noBodyTextError$2("social linkedin message <target> edit message_id:<id>");
14010
14018
  const resolved = [];
14011
14019
  const chatIdResolved = await deps.resolveTarget("target", args.target ?? positionals[0], {
14012
14020
  platform: "linkedin",
@@ -14085,10 +14093,10 @@ const buildMessage$1 = (deps, sendCommand) => {
14085
14093
  }
14086
14094
  const target = args.target ?? (Array.isArray(args._) && args._.length > 0 ? args._[0] : void 0);
14087
14095
  let body;
14088
- if (deps.isStdinTTY()) throw noBodyTextError$1("social linkedin message <target>");
14089
- const piped = trimTrailingNewline$1(await deps.readStdin());
14096
+ if (deps.isStdinTTY()) throw noBodyTextError$2("social linkedin message <target>");
14097
+ const piped = trimTrailingNewline$2(await deps.readStdin());
14090
14098
  if (piped.length > 0) body = parseStdinBody$1(deps, "text", "text", piped);
14091
- else throw noBodyTextError$1("social linkedin message <target>");
14099
+ else throw noBodyTextError$2("social linkedin message <target>");
14092
14100
  if (target === void 0) throw new UsageError("Pass a conversation or person target.");
14093
14101
  if (body === void 0 || typeof body.text !== "string") throw new UsageError("Pass body text via stdin.");
14094
14102
  const account = typeof args.account === "string" ? args.account : void 0;
@@ -17423,8 +17431,8 @@ const withEchoedTargetId = (op, data, body) => {
17423
17431
  }
17424
17432
  };
17425
17433
  };
17426
- const trimTrailingNewline = (value) => value.endsWith("\r\n") ? value.slice(0, -2) : value.endsWith("\n") ? value.slice(0, -1) : value;
17427
- const noBodyTextError = (commandLabel) => new UsageError(`No body text. Pipe it via stdin: \`echo "..." | ${commandLabel}\`.`);
17434
+ const trimTrailingNewline$1 = (value) => value.endsWith("\r\n") ? value.slice(0, -2) : value.endsWith("\n") ? value.slice(0, -1) : value;
17435
+ const noBodyTextError$1 = (commandLabel) => new UsageError(`No body text. Pipe it via stdin: \`echo "..." | ${commandLabel}\`.`);
17428
17436
  const parseStdinBody = (deps, bodyTextName, bodyTextKey, value) => {
17429
17437
  try {
17430
17438
  JSON.parse(value);
@@ -17440,12 +17448,12 @@ const resolveBodyTextFromStdin = async (op, deps, args, commandLabel) => {
17440
17448
  const displayTextArg = bodyTextDisplayKeyFor(op) ?? bodyTextArg;
17441
17449
  const required = stdinBodyTextRequired(op);
17442
17450
  if (deps.isStdinTTY()) {
17443
- if (required) throw noBodyTextError(commandLabel);
17451
+ if (required) throw noBodyTextError$1(commandLabel);
17444
17452
  return;
17445
17453
  }
17446
- const piped = trimTrailingNewline(await deps.readStdin());
17454
+ const piped = trimTrailingNewline$1(await deps.readStdin());
17447
17455
  if (piped.length > 0) args.body = JSON.stringify(parseStdinBody(deps, displayTextArg, bodyTextArg, piped));
17448
- else if (required) throw noBodyTextError(commandLabel);
17456
+ else if (required) throw noBodyTextError$1(commandLabel);
17449
17457
  };
17450
17458
  const runOperation = async (op, contract, deps, args, rawArgs = []) => {
17451
17459
  rejectUnknownArgs(op, args);
@@ -18019,14 +18027,14 @@ const buildMessage = (deps) => {
18019
18027
  if (typeof args.body === "string") throw new UsageError("Unsupported option --body for x message.");
18020
18028
  const recipientsInput = args.recipients ?? args.target ?? (Array.isArray(args._) && args._.length > 0 ? args._[0] : void 0);
18021
18029
  let body;
18022
- if (deps.isStdinTTY()) throw noBodyTextError("social x message <recipients>");
18023
- const piped = trimTrailingNewline(await deps.readStdin());
18030
+ if (deps.isStdinTTY()) throw noBodyTextError$1("social x message <recipients>");
18031
+ const piped = trimTrailingNewline$1(await deps.readStdin());
18024
18032
  if (piped.length > 0) body = parseStdinBody(deps, "text", "text", piped);
18025
- else throw noBodyTextError("social x message <recipients>");
18033
+ else throw noBodyTextError$1("social x message <recipients>");
18026
18034
  if (recipientsInput === void 0) throw new UsageError("Pass a conversation or user target.");
18027
18035
  const recipients = String(recipientsInput).split(",").map((recipient) => recipient.trim()).filter((recipient) => recipient.length > 0);
18028
18036
  if (recipients.length === 0) throw new UsageError("Pass at least one recipient.");
18029
- if (body === void 0) throw noBodyTextError("social x message <recipients>");
18037
+ if (body === void 0) throw noBodyTextError$1("social x message <recipients>");
18030
18038
  const resolved = [];
18031
18039
  const account = typeof args.account === "string" ? args.account : void 0;
18032
18040
  const selectedAccount = await deps.resolveAccount({
@@ -21102,7 +21110,7 @@ const createInstance = (defaults) => {
21102
21110
  const ky = createInstance();
21103
21111
  //#endregion
21104
21112
  //#region package.json
21105
- var version$1 = "0.3.6";
21113
+ var version$1 = "0.4.0";
21106
21114
  //#endregion
21107
21115
  //#region src/lib/env.ts
21108
21116
  const URLWithTrailingSlash = url().transform(ensureTrailingSlash);
@@ -28493,6 +28501,66 @@ const createAccountCommand = (deps) => {
28493
28501
  });
28494
28502
  };
28495
28503
  //#endregion
28504
+ //#region src/lib/stdin.ts
28505
+ const trimTrailingNewline = (value) => value.endsWith("\r\n") ? value.slice(0, -2) : value.endsWith("\n") ? value.slice(0, -1) : value;
28506
+ const noBodyTextError = (commandLabel) => new UsageError(`No body text. Pipe it via stdin: \`echo "..." | ${commandLabel}\`.`);
28507
+ const readPipedText = async (deps, commandLabel) => {
28508
+ if (deps.isStdinTTY()) throw noBodyTextError(commandLabel);
28509
+ const text = trimTrailingNewline(await deps.readStdin());
28510
+ if (text.length === 0) throw noBodyTextError(commandLabel);
28511
+ return text;
28512
+ };
28513
+ //#endregion
28514
+ //#region src/feedback/index.ts
28515
+ const submitContract = {
28516
+ capability: "write",
28517
+ auth: {
28518
+ required: true,
28519
+ scope: "read,write"
28520
+ },
28521
+ mutates: true,
28522
+ outputSchema: object({
28523
+ id: string(),
28524
+ type: _enum(["bug", "feature"]),
28525
+ issueNumber: number().int().nullable(),
28526
+ createdAt: string()
28527
+ }),
28528
+ confirmation: false,
28529
+ hazards: [{
28530
+ code: "feedback_submit",
28531
+ message: "Sends your text to the maintainers as a tracked report."
28532
+ }]
28533
+ };
28534
+ const createSubmitCommand = (deps, type) => {
28535
+ const noun = type === "bug" ? "bug report" : "feature request";
28536
+ const label = `social feedback ${type}`;
28537
+ return defineCommand({
28538
+ meta: commandMeta({
28539
+ name: type,
28540
+ description: `Submit a ${noun} [write] | usage: \`echo "..." | ${label}\``,
28541
+ capability: "write",
28542
+ contract: submitContract
28543
+ }),
28544
+ run: async () => {
28545
+ const text = await readPipedText(deps, label);
28546
+ deps.printData(await deps.client.feedback.submit({
28547
+ type,
28548
+ text
28549
+ }));
28550
+ }
28551
+ });
28552
+ };
28553
+ const createFeedbackCommand = (deps) => defineCommand({
28554
+ meta: {
28555
+ name: "feedback",
28556
+ description: "Report a bug or request a feature."
28557
+ },
28558
+ subCommands: {
28559
+ bug: createSubmitCommand(deps, "bug"),
28560
+ feature: createSubmitCommand(deps, "feature")
28561
+ }
28562
+ });
28563
+ //#endregion
28496
28564
  //#region src/lib/account.ts
28497
28565
  const LEADING_AT_PATTERN = /^@+/;
28498
28566
  const normalizeAccountIdentifier = (value) => value.trim().replace(LEADING_AT_PATTERN, "").toLowerCase();
@@ -28651,7 +28719,8 @@ const createCLIDeps = () => {
28651
28719
  usage: {
28652
28720
  summary: client.usage.summary,
28653
28721
  list: client.usage.list
28654
- }
28722
+ },
28723
+ feedback: { submit: client.feedback.submit }
28655
28724
  },
28656
28725
  api,
28657
28726
  parseResourceId,
@@ -29199,6 +29268,7 @@ const createSocialCommand = (deps = createCLIDeps()) => {
29199
29268
  const accountCommand = createAccountCommand(deps);
29200
29269
  const linkedinCommand = createLinkedinCommands(deps);
29201
29270
  const xCommand = createXCommands(deps);
29271
+ const feedbackCommand = createFeedbackCommand(deps);
29202
29272
  const socialCommand = defineCommand({
29203
29273
  meta: {
29204
29274
  name: "social",
@@ -29209,7 +29279,8 @@ const createSocialCommand = (deps = createCLIDeps()) => {
29209
29279
  account: accountCommand,
29210
29280
  schema: schemaCommand,
29211
29281
  x: xCommand,
29212
- linkedin: linkedinCommand
29282
+ linkedin: linkedinCommand,
29283
+ feedback: feedbackCommand
29213
29284
  }
29214
29285
  });
29215
29286
  setSchemaRootCommand(socialCommand);