@usesocial/cli 0.2.6 → 0.3.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/dist/index.mjs CHANGED
@@ -130,13 +130,13 @@ var CancelledError = class extends Error {
130
130
  }
131
131
  };
132
132
  //#endregion
133
- //#region ../../packages/local-sqlite/src/migrations.generated.ts
133
+ //#region ../../packages/sync-engine/src/migrations.generated.ts
134
134
  const MIGRATIONS = [{
135
135
  "tag": "0000_modern_stephen_strange",
136
136
  "sql": "CREATE TABLE `li_connections` (\n `id` text PRIMARY KEY NOT NULL,\n `created_at` integer,\n `object` text,\n `url` text,\n `user_id` text,\n `user_object` text,\n `user_type` text,\n `user_display_name` text,\n `user_public_identifier` text,\n `user_profile_url` text,\n `user_public_picture_url` text,\n `user_description` text,\n `raw` text NOT NULL,\n `synced_at` integer NOT NULL\n);\n--> statement-breakpoint\nCREATE INDEX `li_connections_created_at_idx` ON `li_connections` (`created_at`);--> statement-breakpoint\nCREATE TABLE `li_conversations` (\n `id` text PRIMARY KEY NOT NULL,\n `created_at` integer,\n `last_message_timestamp` integer,\n `muted_until` integer,\n `creator_id` text,\n `headline` text,\n `image_url` text,\n `name` text,\n `object` text,\n `provider` text,\n `type` text,\n `user_id` text,\n `is_1to1` integer,\n `is_archived` integer,\n `is_channel` integer,\n `is_group` integer,\n `is_pinned` integer,\n `is_readonly` integer,\n `unread_count` integer,\n `user_object` text,\n `user_type` text,\n `user_display_name` text,\n `user_public_identifier` text,\n `user_profile_url` text,\n `user_public_picture_url` text,\n `user_description` text,\n `user_specifics_network_distance` text,\n `raw` text NOT NULL,\n `synced_at` integer NOT NULL\n);\n--> statement-breakpoint\nCREATE INDEX `li_conversations_created_at_idx` ON `li_conversations` (`created_at`);--> statement-breakpoint\nCREATE INDEX `li_conversations_last_message_timestamp_idx` ON `li_conversations` (`last_message_timestamp`);--> statement-breakpoint\nCREATE TABLE `li_messages` (\n `id` text PRIMARY KEY NOT NULL,\n `timestamp` integer,\n `chat_id` text,\n `object` text,\n `provider` text,\n `text` text,\n `sender_id` text,\n `is_deleted` integer,\n `is_delivered` integer,\n `is_edited` integer,\n `is_event` integer,\n `is_hidden` integer,\n `is_mentionned` integer,\n `is_pinned` integer,\n `is_seen` integer,\n `is_sender` integer,\n `sender_object` text,\n `sender_type` text,\n `sender_display_name` text,\n `sender_public_identifier` text,\n `sender_profile_url` text,\n `sender_public_picture_url` text,\n `sender_description` text,\n `sender_specifics_network_distance` text,\n `raw` text NOT NULL,\n `synced_at` integer NOT NULL\n);\n--> statement-breakpoint\nCREATE INDEX `li_messages_timestamp_idx` ON `li_messages` (`timestamp`);--> statement-breakpoint\nCREATE INDEX `li_messages_chat_id_idx` ON `li_messages` (`chat_id`);--> statement-breakpoint\nCREATE TABLE `li_posts` (\n `id` text PRIMARY KEY NOT NULL,\n `created_at` integer,\n `object` text,\n `share_url` text,\n `text` text,\n `url` text,\n `is_repost` integer,\n `user_reacted` text,\n `comments_counter` integer,\n `reposts_counter` integer,\n `analytics_impressions_counter` integer,\n `author_id` text,\n `author_object` text,\n `author_type` text,\n `author_display_name` text,\n `author_public_identifier` text,\n `author_profile_url` text,\n `author_public_picture_url` text,\n `author_description` text,\n `author_specifics_network_distance` text,\n `permissions_can_post_comments` integer,\n `permissions_can_react` integer,\n `permissions_can_share` integer,\n `poll_id` text,\n `poll_question` text,\n `poll_is_open` integer,\n `poll_total_votes_count` integer,\n `quoted_post_id` text,\n `quoted_post_object` text,\n `quoted_post_created_at` integer,\n `quoted_post_text` text,\n `quoted_post_share_url` text,\n `quoted_post_user_reacted` text,\n `quoted_post_comments_counter` integer,\n `quoted_post_reposts_counter` integer,\n `quoted_post_permissions_can_post_comments` integer,\n `quoted_post_permissions_can_react` integer,\n `quoted_post_permissions_can_share` integer,\n `quoted_post_author_id` text,\n `quoted_post_author_object` text,\n `quoted_post_author_type` text,\n `quoted_post_author_display_name` text,\n `quoted_post_author_public_identifier` text,\n `quoted_post_author_profile_url` text,\n `quoted_post_author_public_picture_url` text,\n `quoted_post_author_description` text,\n `quoted_post_author_specifics_network_distance` text,\n `reposted_by_id` text,\n `reposted_by_object` text,\n `reposted_by_type` text,\n `reposted_by_display_name` text,\n `reposted_by_public_identifier` text,\n `reposted_by_profile_url` text,\n `reposted_by_public_picture_url` text,\n `raw` text NOT NULL,\n `synced_at` integer NOT NULL\n);\n--> statement-breakpoint\nCREATE INDEX `li_posts_created_at_idx` ON `li_posts` (`created_at`);--> statement-breakpoint\nCREATE TABLE `li_requests` (\n `id` text PRIMARY KEY NOT NULL,\n `created_at` integer,\n `object` text,\n `type` text,\n `user_id` text,\n `user_object` text,\n `user_type` text,\n `user_display_name` text,\n `user_public_identifier` text,\n `user_profile_url` text,\n `user_public_picture_url` text,\n `user_description` text,\n `raw` text NOT NULL,\n `synced_at` integer NOT NULL\n);\n--> statement-breakpoint\nCREATE INDEX `li_requests_created_at_idx` ON `li_requests` (`created_at`);--> statement-breakpoint\nCREATE TABLE `sync_state` (\n `collection` text PRIMARY KEY NOT NULL,\n `cursor` text,\n `last_synced` integer,\n `object_count` integer\n);\n--> statement-breakpoint\nCREATE TABLE `x_bookmarks` (\n `id` text PRIMARY KEY NOT NULL,\n `created_at` integer,\n `author_id` text,\n `conversation_id` text,\n `in_reply_to_user_id` text,\n `lang` text,\n `reply_settings` text,\n `text` text,\n `url` text,\n `paid_partnership` integer,\n `possibly_sensitive` integer,\n `edit_controls_editable_until` integer,\n `edit_controls_edits_remaining` integer,\n `edit_controls_is_edit_eligible` integer,\n `like_count` integer,\n `retweet_count` integer,\n `reply_count` integer,\n `quote_count` integer,\n `bookmark_count` integer,\n `impression_count` integer,\n `article_cover_media` text,\n `article_plain_text` text,\n `article_preview_text` text,\n `article_title` text,\n `note_tweet_text` text,\n `raw` text NOT NULL,\n `synced_at` integer NOT NULL\n);\n--> statement-breakpoint\nCREATE INDEX `x_bookmarks_created_at_idx` ON `x_bookmarks` (`created_at`);--> statement-breakpoint\nCREATE TABLE `x_followers` (\n `id` text PRIMARY KEY NOT NULL,\n `created_at` integer,\n `username` text,\n `name` text,\n `description` text,\n `location` text,\n `url` text,\n `is_identity_verified` integer,\n `protected` integer,\n `verified` integer,\n `verified_type` text,\n `subscription_type` text,\n `parody` integer,\n `most_recent_tweet_id` text,\n `pinned_tweet_id` text,\n `profile_banner_url` text,\n `profile_image_url` text,\n `affiliation_badge_url` text,\n `affiliation_description` text,\n `affiliation_url` text,\n `subscription_subscribes_to_you` integer,\n `followers_count` integer,\n `following_count` integer,\n `tweet_count` integer,\n `listed_count` integer,\n `like_count` integer,\n `media_count` integer,\n `raw` text NOT NULL,\n `synced_at` integer NOT NULL\n);\n--> statement-breakpoint\nCREATE INDEX `x_followers_created_at_idx` ON `x_followers` (`created_at`);--> statement-breakpoint\nCREATE TABLE `x_following` (\n `id` text PRIMARY KEY NOT NULL,\n `created_at` integer,\n `username` text,\n `name` text,\n `description` text,\n `location` text,\n `url` text,\n `is_identity_verified` integer,\n `protected` integer,\n `verified` integer,\n `verified_type` text,\n `subscription_type` text,\n `parody` integer,\n `most_recent_tweet_id` text,\n `pinned_tweet_id` text,\n `profile_banner_url` text,\n `profile_image_url` text,\n `affiliation_badge_url` text,\n `affiliation_description` text,\n `affiliation_url` text,\n `subscription_subscribes_to_you` integer,\n `followers_count` integer,\n `following_count` integer,\n `tweet_count` integer,\n `listed_count` integer,\n `like_count` integer,\n `media_count` integer,\n `raw` text NOT NULL,\n `synced_at` integer NOT NULL\n);\n--> statement-breakpoint\nCREATE INDEX `x_following_created_at_idx` ON `x_following` (`created_at`);--> statement-breakpoint\nCREATE TABLE `x_tweets` (\n `id` text PRIMARY KEY NOT NULL,\n `created_at` integer,\n `author_id` text,\n `conversation_id` text,\n `in_reply_to_user_id` text,\n `lang` text,\n `reply_settings` text,\n `text` text,\n `url` text,\n `paid_partnership` integer,\n `possibly_sensitive` integer,\n `edit_controls_editable_until` integer,\n `edit_controls_edits_remaining` integer,\n `edit_controls_is_edit_eligible` integer,\n `like_count` integer,\n `retweet_count` integer,\n `reply_count` integer,\n `quote_count` integer,\n `bookmark_count` integer,\n `impression_count` integer,\n `raw` text NOT NULL,\n `synced_at` integer NOT NULL\n);\n--> statement-breakpoint\nCREATE INDEX `x_tweets_created_at_idx` ON `x_tweets` (`created_at`);"
137
137
  }];
138
138
  //#endregion
139
- //#region ../../packages/local-sqlite/src/migrate.ts
139
+ //#region ../../packages/sync-engine/src/migrate.ts
140
140
  const readUserVersion = (db) => {
141
141
  const version = db.prepare("PRAGMA user_version").get()?.user_version;
142
142
  return typeof version === "number" ? version : Number(version ?? 0);
@@ -161,7 +161,7 @@ const assertAtLatest = (db) => {
161
161
  if (currentVersion < MIGRATIONS.length) throw new Error(`Local SQLite cache schema is at version ${currentVersion}; expected ${MIGRATIONS.length}`);
162
162
  };
163
163
  //#endregion
164
- //#region ../../packages/local-sqlite/src/sqlite.ts
164
+ //#region ../../packages/sync-engine/src/sqlite.ts
165
165
  const loadModule = createRequire(import.meta.url);
166
166
  const isBunRuntime = () => typeof Bun !== "undefined";
167
167
  const normalizeValue = (value) => {
@@ -219,7 +219,7 @@ const openDatabase = (path, opts) => {
219
219
  };
220
220
  };
221
221
  //#endregion
222
- //#region ../../packages/local-sqlite/src/cache.ts
222
+ //#region ../../packages/sync-engine/src/cache.ts
223
223
  const cacheTables = new Set([
224
224
  "x_tweets",
225
225
  "x_followers",
@@ -307,8 +307,8 @@ const createCache = (path, db) => ({
307
307
  }
308
308
  });
309
309
  //#endregion
310
- //#region ../../packages/local-sqlite/src/collections/linkedin.ts
311
- const linkedinPagination = {
310
+ //#region ../../packages/sync-engine/src/collections/linkedin.ts
311
+ const linkedinCursorPagination = {
312
312
  style: "cursor",
313
313
  limitParam: "limit",
314
314
  cursorParam: "cursor",
@@ -316,6 +316,13 @@ const linkedinPagination = {
316
316
  totalCountPath: "total_count",
317
317
  itemsPath: "data"
318
318
  };
319
+ const linkedinOffsetPagination = {
320
+ style: "offset",
321
+ limitParam: "limit",
322
+ offsetParam: "offset",
323
+ totalCountPath: "total_count",
324
+ itemsPath: "data"
325
+ };
319
326
  const asRecord$1 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
320
327
  const read$1 = (value) => value === null || value === void 0 ? null : value;
321
328
  const readReaction = (value) => typeof value === "string" ? value : null;
@@ -504,7 +511,7 @@ const LINKEDIN_COLLECTIONS = [
504
511
  key: "li_conversations",
505
512
  platform: "linkedin",
506
513
  requests: [{ path: "/chats" }],
507
- pagination: linkedinPagination,
514
+ pagination: linkedinCursorPagination,
508
515
  pageSize: 20,
509
516
  estCostBPS: 100,
510
517
  estUnitsPerPage: 10,
@@ -517,7 +524,7 @@ const LINKEDIN_COLLECTIONS = [
517
524
  requests: [{ path: "/chats/:chat_id/messages" }],
518
525
  parentCollection: "li_conversations",
519
526
  parentIdToken: ":chat_id",
520
- pagination: linkedinPagination,
527
+ pagination: linkedinCursorPagination,
521
528
  pageSize: 250,
522
529
  estCostBPS: 100,
523
530
  estUnitsPerPage: 5,
@@ -528,7 +535,7 @@ const LINKEDIN_COLLECTIONS = [
528
535
  key: "li_connections",
529
536
  platform: "linkedin",
530
537
  requests: [{ path: "/users/connections" }],
531
- pagination: linkedinPagination,
538
+ pagination: linkedinCursorPagination,
532
539
  pageSize: 100,
533
540
  estCostBPS: 10,
534
541
  estUnitsPerPage: 100,
@@ -540,7 +547,7 @@ const LINKEDIN_COLLECTIONS = [
540
547
  platform: "linkedin",
541
548
  requests: [{ path: "/users/:identifier/posts" }],
542
549
  ownIdToken: ":identifier",
543
- pagination: linkedinPagination,
550
+ pagination: linkedinCursorPagination,
544
551
  pageSize: 50,
545
552
  estCostBPS: 50,
546
553
  estUnitsPerPage: 50,
@@ -557,7 +564,7 @@ const LINKEDIN_COLLECTIONS = [
557
564
  path: "/users/me/relation-requests/sent",
558
565
  bakedQuery: { type: "sent" }
559
566
  }],
560
- pagination: linkedinPagination,
567
+ pagination: linkedinOffsetPagination,
561
568
  pageSize: 100,
562
569
  estCostBPS: 100,
563
570
  estUnitsPerPage: 100,
@@ -565,7 +572,7 @@ const LINKEDIN_COLLECTIONS = [
565
572
  }
566
573
  ];
567
574
  //#endregion
568
- //#region ../../packages/local-sqlite/src/collections/x.ts
575
+ //#region ../../packages/sync-engine/src/collections/x.ts
569
576
  const xPagination = {
570
577
  style: "cursor",
571
578
  limitParam: "max_results",
@@ -664,7 +671,7 @@ const liftXUser = (item) => {
664
671
  };
665
672
  };
666
673
  //#endregion
667
- //#region ../../packages/local-sqlite/src/collections/index.ts
674
+ //#region ../../packages/sync-engine/src/collections/index.ts
668
675
  const COLLECTIONS = [...[
669
676
  {
670
677
  key: "x_tweets",
@@ -9753,7 +9760,7 @@ const createPricing = (resources) => {
9753
9760
  };
9754
9761
  };
9755
9762
  //#endregion
9756
- //#region ../../packages/local-sqlite/src/cost.ts
9763
+ //#region ../../packages/sync-engine/src/cost.ts
9757
9764
  const creditsToUSD = (credits) => credits / 1e3;
9758
9765
  const usdToCredits = (usd) => Math.round(usd * 1e3);
9759
9766
  const estimatePageCredits = (estCostBPS, estUnitsPerPage) => creditsForBPS(billedBPSFor(estCostBPS * estUnitsPerPage));
@@ -10352,7 +10359,7 @@ function index(name) {
10352
10359
  return new IndexBuilderOn(name, false);
10353
10360
  }
10354
10361
  //#endregion
10355
- //#region ../../packages/local-sqlite/src/schema.ts
10362
+ //#region ../../packages/sync-engine/src/schema.ts
10356
10363
  const idColumn = () => text("id").primaryKey();
10357
10364
  const rawColumns = () => ({
10358
10365
  raw: text("raw").notNull(),
@@ -10592,7 +10599,7 @@ sqliteTable("sync_state", {
10592
10599
  objectCount: integer("object_count")
10593
10600
  });
10594
10601
  //#endregion
10595
- //#region ../../packages/local-sqlite/src/since.ts
10602
+ //#region ../../packages/sync-engine/src/since.ts
10596
10603
  const durationPattern = /^(\d+):(hours|days|weeks)$/;
10597
10604
  const isoPattern = /^\d{4}-\d{2}-\d{2}(?:T\d{2}:\d{2}:\d{2}Z)?$/;
10598
10605
  const unitMs = {
@@ -10645,10 +10652,11 @@ const substitutePath = (path, args) => {
10645
10652
  if (args.parentIdToken && args.chatId !== void 0) resolved = resolved.replaceAll(args.parentIdToken, args.chatId);
10646
10653
  return resolved;
10647
10654
  };
10648
- const buildQuery = (pagination, pageSize, cursor, bakedQuery) => {
10655
+ const buildQuery = (pagination, pageSize, cursor, offset, bakedQuery) => {
10649
10656
  const params = new URLSearchParams();
10650
10657
  if (pagination.style !== "none" && pagination.limitParam) params.set(pagination.limitParam, String(pageSize));
10651
10658
  if (pagination.style !== "none" && cursor && pagination.cursorParam) params.set(pagination.cursorParam, cursor);
10659
+ if (pagination.style === "offset" && pagination.offsetParam) params.set(pagination.offsetParam, String(offset));
10652
10660
  for (const [key, value] of Object.entries(bakedQuery ?? {})) params.set(key, value);
10653
10661
  const query = params.toString();
10654
10662
  return query ? `?${query}` : "";
@@ -10690,6 +10698,7 @@ const walkRequest = async (args) => {
10690
10698
  const checkpoint = args.useCheckpoint ? args.deps.cache.getCursor(args.collection.key)?.cursor ?? null : null;
10691
10699
  const ids = [];
10692
10700
  let cursor = null;
10701
+ let offset = 0;
10693
10702
  let newestId = null;
10694
10703
  let lastPageCredits = null;
10695
10704
  let pages = 0;
@@ -10707,7 +10716,7 @@ const walkRequest = async (args) => {
10707
10716
  ownIdToken: args.collection.ownIdToken,
10708
10717
  chatId: args.parentId,
10709
10718
  parentIdToken: args.parentIdToken
10710
- }) + buildQuery(args.collection.pagination, args.collection.pageSize, cursor, args.request.bakedQuery);
10719
+ }) + buildQuery(args.collection.pagination, args.collection.pageSize, cursor, offset, args.request.bakedQuery);
10711
10720
  const response = await args.deps.api.get(path, { headers: args.deps.accountHeaders });
10712
10721
  const credits = creditsFromHeader(response.headers);
10713
10722
  args.tracker.add(credits);
@@ -10744,6 +10753,15 @@ const walkRequest = async (args) => {
10744
10753
  args.deps.cache.upsert(args.collection.key, rows);
10745
10754
  upserted += rows.length;
10746
10755
  if (hitStop) break;
10756
+ if (args.collection.pagination.style === "offset") {
10757
+ const nextOffset = offset + args.collection.pageSize;
10758
+ if (page.items.length === 0 || page.totalCount != null && nextOffset >= page.totalCount || page.totalCount == null && page.items.length < args.collection.pageSize) {
10759
+ stoppedReason = "complete";
10760
+ break;
10761
+ }
10762
+ offset = nextOffset;
10763
+ continue;
10764
+ }
10747
10765
  cursor = page.cursor;
10748
10766
  if (!cursor) {
10749
10767
  stoppedReason = "complete";
@@ -11349,10 +11367,18 @@ const { costBPSForCategory: costBPSForCategory$1 } = createPricing([
11349
11367
  "unitPriceUSD": .015,
11350
11368
  "featureId": "user_interaction_create_request"
11351
11369
  },
11370
+ {
11371
+ "key": "following_read",
11372
+ "label": "Following/Followers: Read",
11373
+ "description": "Read LinkedIn connections, priced to match X following and followers reads.",
11374
+ "unit": "per_resource",
11375
+ "unitPriceUSD": .01,
11376
+ "featureId": "following_followers_read_resource"
11377
+ },
11352
11378
  {
11353
11379
  "key": "owned_read",
11354
11380
  "label": "Owned: Read",
11355
- "description": "Read the connected LinkedIn account's own profile or first-party relation data.",
11381
+ "description": "Read the connected LinkedIn account's own profile.",
11356
11382
  "unit": "per_resource",
11357
11383
  "unitPriceUSD": .001,
11358
11384
  "featureId": "owned_read_resource"
@@ -11442,7 +11468,6 @@ const LINKEDIN_OPERATIONS = [
11442
11468
  style: "cursor",
11443
11469
  limitParam: "limit",
11444
11470
  cursorParam: "cursor",
11445
- offsetParam: "offset",
11446
11471
  cursorPath: "next_cursor",
11447
11472
  totalCountPath: "total_count",
11448
11473
  itemsPath: "data"
@@ -11557,10 +11582,9 @@ const LINKEDIN_OPERATIONS = [
11557
11582
  capability: "read",
11558
11583
  mutates: false,
11559
11584
  pagination: {
11560
- style: "cursor",
11585
+ style: "offset",
11561
11586
  limitParam: "limit",
11562
11587
  offsetParam: "offset",
11563
- cursorPath: "next_cursor",
11564
11588
  totalCountPath: "total_count",
11565
11589
  itemsPath: "data"
11566
11590
  },
@@ -11612,11 +11636,9 @@ const LINKEDIN_OPERATIONS = [
11612
11636
  capability: "read",
11613
11637
  mutates: false,
11614
11638
  pagination: {
11615
- style: "cursor",
11639
+ style: "offset",
11616
11640
  limitParam: "limit",
11617
- cursorParam: "cursor",
11618
11641
  offsetParam: "offset",
11619
- cursorPath: "next_cursor",
11620
11642
  totalCountPath: "total_count",
11621
11643
  itemsPath: "data"
11622
11644
  },
@@ -11630,7 +11652,7 @@ const LINKEDIN_OPERATIONS = [
11630
11652
  in: "query",
11631
11653
  required: false,
11632
11654
  kind: "integer",
11633
- description: "An offset used for pagination, if supported by the provider, else use cursor."
11655
+ description: "Pagination offset"
11634
11656
  },
11635
11657
  {
11636
11658
  name: "limit",
@@ -11639,13 +11661,6 @@ const LINKEDIN_OPERATIONS = [
11639
11661
  kind: "integer",
11640
11662
  description: "Rows to return (1-100)"
11641
11663
  },
11642
- {
11643
- name: "cursor",
11644
- in: "query",
11645
- required: false,
11646
- kind: "string",
11647
- description: "Pagination cursor"
11648
- },
11649
11664
  {
11650
11665
  name: "sort_by",
11651
11666
  in: "query",
@@ -11683,11 +11698,9 @@ const LINKEDIN_OPERATIONS = [
11683
11698
  capability: "read",
11684
11699
  mutates: false,
11685
11700
  pagination: {
11686
- style: "cursor",
11701
+ style: "offset",
11687
11702
  limitParam: "limit",
11688
- cursorParam: "cursor",
11689
11703
  offsetParam: "offset",
11690
- cursorPath: "next_cursor",
11691
11704
  totalCountPath: "total_count",
11692
11705
  itemsPath: "data"
11693
11706
  },
@@ -11701,7 +11714,7 @@ const LINKEDIN_OPERATIONS = [
11701
11714
  in: "query",
11702
11715
  required: false,
11703
11716
  kind: "integer",
11704
- description: "An offset used for pagination, if supported by the provider, else use cursor."
11717
+ description: "Pagination offset"
11705
11718
  },
11706
11719
  {
11707
11720
  name: "limit",
@@ -11710,13 +11723,6 @@ const LINKEDIN_OPERATIONS = [
11710
11723
  kind: "integer",
11711
11724
  description: "Rows to return (1-100)"
11712
11725
  },
11713
- {
11714
- name: "cursor",
11715
- in: "query",
11716
- required: false,
11717
- kind: "string",
11718
- description: "Pagination cursor"
11719
- },
11720
11726
  {
11721
11727
  name: "post_id",
11722
11728
  in: "path",
@@ -11746,10 +11752,9 @@ const LINKEDIN_OPERATIONS = [
11746
11752
  capability: "read",
11747
11753
  mutates: false,
11748
11754
  pagination: {
11749
- style: "cursor",
11755
+ style: "offset",
11750
11756
  limitParam: "limit",
11751
11757
  offsetParam: "offset",
11752
- cursorPath: "next_cursor",
11753
11758
  totalCountPath: "total_count",
11754
11759
  itemsPath: "data"
11755
11760
  },
@@ -11800,10 +11805,9 @@ const LINKEDIN_OPERATIONS = [
11800
11805
  capability: "read",
11801
11806
  mutates: false,
11802
11807
  pagination: {
11803
- style: "cursor",
11808
+ style: "offset",
11804
11809
  limitParam: "limit",
11805
11810
  offsetParam: "offset",
11806
- cursorPath: "next_cursor",
11807
11811
  totalCountPath: "total_count",
11808
11812
  itemsPath: "data"
11809
11813
  },
@@ -11854,10 +11858,9 @@ const LINKEDIN_OPERATIONS = [
11854
11858
  capability: "read",
11855
11859
  mutates: false,
11856
11860
  pagination: {
11857
- style: "cursor",
11861
+ style: "offset",
11858
11862
  limitParam: "limit",
11859
11863
  offsetParam: "offset",
11860
- cursorPath: "next_cursor",
11861
11864
  totalCountPath: "total_count",
11862
11865
  itemsPath: "data"
11863
11866
  },
@@ -11908,10 +11911,9 @@ const LINKEDIN_OPERATIONS = [
11908
11911
  capability: "read",
11909
11912
  mutates: false,
11910
11913
  pagination: {
11911
- style: "cursor",
11914
+ style: "offset",
11912
11915
  limitParam: "limit",
11913
11916
  offsetParam: "offset",
11914
- cursorPath: "next_cursor",
11915
11917
  totalCountPath: "total_count",
11916
11918
  itemsPath: "data"
11917
11919
  },
@@ -12013,11 +12015,9 @@ const LINKEDIN_OPERATIONS = [
12013
12015
  capability: "read",
12014
12016
  mutates: false,
12015
12017
  pagination: {
12016
- style: "cursor",
12018
+ style: "offset",
12017
12019
  limitParam: "limit",
12018
- cursorParam: "cursor",
12019
12020
  offsetParam: "offset",
12020
- cursorPath: "next_cursor",
12021
12021
  totalCountPath: "total_count",
12022
12022
  itemsPath: "data"
12023
12023
  },
@@ -12031,7 +12031,7 @@ const LINKEDIN_OPERATIONS = [
12031
12031
  in: "query",
12032
12032
  required: false,
12033
12033
  kind: "integer",
12034
- description: "An offset used for pagination, if supported by the provider, else use cursor."
12034
+ description: "Pagination offset"
12035
12035
  },
12036
12036
  {
12037
12037
  name: "limit",
@@ -12040,13 +12040,6 @@ const LINKEDIN_OPERATIONS = [
12040
12040
  kind: "integer",
12041
12041
  description: "The limit of items to be returned."
12042
12042
  },
12043
- {
12044
- name: "cursor",
12045
- in: "query",
12046
- required: false,
12047
- kind: "string",
12048
- description: "A cursor used for pagination. If supported by the provider, use next_cursor given by the previous page of the list, else use offset."
12049
- },
12050
12043
  {
12051
12044
  name: "identifier",
12052
12045
  in: "path",
@@ -12079,16 +12072,14 @@ const LINKEDIN_OPERATIONS = [
12079
12072
  capability: "read",
12080
12073
  mutates: false,
12081
12074
  pagination: {
12082
- style: "cursor",
12075
+ style: "offset",
12083
12076
  limitParam: "limit",
12084
- cursorParam: "cursor",
12085
12077
  offsetParam: "offset",
12086
- cursorPath: "next_cursor",
12087
12078
  totalCountPath: "total_count",
12088
12079
  itemsPath: "data"
12089
12080
  },
12090
- costBPS: 10,
12091
- billingCategory: "owned_read",
12081
+ costBPS: 100,
12082
+ billingCategory: "following_read",
12092
12083
  kind: "users"
12093
12084
  },
12094
12085
  parameters: [
@@ -12097,7 +12088,7 @@ const LINKEDIN_OPERATIONS = [
12097
12088
  in: "query",
12098
12089
  required: false,
12099
12090
  kind: "integer",
12100
- description: "An offset used for pagination, if supported by the provider, else use cursor."
12091
+ description: "Pagination offset"
12101
12092
  },
12102
12093
  {
12103
12094
  name: "limit",
@@ -12106,13 +12097,6 @@ const LINKEDIN_OPERATIONS = [
12106
12097
  kind: "integer",
12107
12098
  description: "Rows to return (1-1000)"
12108
12099
  },
12109
- {
12110
- name: "cursor",
12111
- in: "query",
12112
- required: false,
12113
- kind: "string",
12114
- description: "Pagination cursor"
12115
- },
12116
12100
  {
12117
12101
  name: "user_id",
12118
12102
  in: "query",
@@ -12147,11 +12131,9 @@ const LINKEDIN_OPERATIONS = [
12147
12131
  capability: "read",
12148
12132
  mutates: false,
12149
12133
  pagination: {
12150
- style: "cursor",
12134
+ style: "offset",
12151
12135
  limitParam: "limit",
12152
- cursorParam: "cursor",
12153
12136
  offsetParam: "offset",
12154
- cursorPath: "next_cursor",
12155
12137
  totalCountPath: "total_count",
12156
12138
  itemsPath: "data"
12157
12139
  },
@@ -12159,29 +12141,19 @@ const LINKEDIN_OPERATIONS = [
12159
12141
  billingCategory: "user_read",
12160
12142
  kind: "users"
12161
12143
  },
12162
- parameters: [
12163
- {
12164
- name: "offset",
12165
- in: "query",
12166
- required: false,
12167
- kind: "integer",
12168
- description: "Pagination offset"
12169
- },
12170
- {
12171
- name: "limit",
12172
- in: "query",
12173
- required: false,
12174
- kind: "integer",
12175
- description: "Rows to return (1-100)"
12176
- },
12177
- {
12178
- name: "cursor",
12179
- in: "query",
12180
- required: false,
12181
- kind: "string",
12182
- description: "Pagination cursor"
12183
- }
12184
- ]
12144
+ parameters: [{
12145
+ name: "offset",
12146
+ in: "query",
12147
+ required: false,
12148
+ kind: "integer",
12149
+ description: "Pagination offset"
12150
+ }, {
12151
+ name: "limit",
12152
+ in: "query",
12153
+ required: false,
12154
+ kind: "integer",
12155
+ description: "Rows to return (1-100)"
12156
+ }]
12185
12157
  },
12186
12158
  {
12187
12159
  schemaBaseName: "RequestsSent",
@@ -12200,11 +12172,9 @@ const LINKEDIN_OPERATIONS = [
12200
12172
  capability: "read",
12201
12173
  mutates: false,
12202
12174
  pagination: {
12203
- style: "cursor",
12175
+ style: "offset",
12204
12176
  limitParam: "limit",
12205
- cursorParam: "cursor",
12206
12177
  offsetParam: "offset",
12207
- cursorPath: "next_cursor",
12208
12178
  totalCountPath: "total_count",
12209
12179
  itemsPath: "data"
12210
12180
  },
@@ -12212,29 +12182,19 @@ const LINKEDIN_OPERATIONS = [
12212
12182
  billingCategory: "user_read",
12213
12183
  kind: "users"
12214
12184
  },
12215
- parameters: [
12216
- {
12217
- name: "offset",
12218
- in: "query",
12219
- required: false,
12220
- kind: "integer",
12221
- description: "Pagination offset"
12222
- },
12223
- {
12224
- name: "limit",
12225
- in: "query",
12226
- required: false,
12227
- kind: "integer",
12228
- description: "Rows to return (1-100)"
12229
- },
12230
- {
12231
- name: "cursor",
12232
- in: "query",
12233
- required: false,
12234
- kind: "string",
12235
- description: "Pagination cursor"
12236
- }
12237
- ]
12185
+ parameters: [{
12186
+ name: "offset",
12187
+ in: "query",
12188
+ required: false,
12189
+ kind: "integer",
12190
+ description: "Pagination offset"
12191
+ }, {
12192
+ name: "limit",
12193
+ in: "query",
12194
+ required: false,
12195
+ kind: "integer",
12196
+ description: "Rows to return (1-100)"
12197
+ }]
12238
12198
  },
12239
12199
  {
12240
12200
  schemaBaseName: "MessagesMessage",
@@ -12640,7 +12600,6 @@ const CompaniesJobsOutput = object({
12640
12600
  const PostsCommentsInput = object({
12641
12601
  offset: union([string(), number()]).optional(),
12642
12602
  limit: union([string(), number()]).optional(),
12643
- cursor: string().optional(),
12644
12603
  sort_by: _enum(["MOST_RECENT", "MOST_RELEVANT"]).optional(),
12645
12604
  post_id: string()
12646
12605
  });
@@ -12652,7 +12611,6 @@ const PostsCommentsOutput = object({
12652
12611
  const PostsReactionsInput = object({
12653
12612
  offset: union([string(), number()]).optional(),
12654
12613
  limit: union([string(), number()]).optional(),
12655
- cursor: string().optional(),
12656
12614
  post_id: string()
12657
12615
  });
12658
12616
  const PostsReactionsOutput = object({
@@ -12709,7 +12667,6 @@ const UserProfileOutput = record(string(), unknown());
12709
12667
  const UserPostsInput = object({
12710
12668
  offset: union([string(), number()]).optional(),
12711
12669
  limit: union([string(), number()]).optional(),
12712
- cursor: string().optional(),
12713
12670
  identifier: string().optional()
12714
12671
  });
12715
12672
  const UserPostsOutput = object({
@@ -12720,7 +12677,6 @@ const UserPostsOutput = object({
12720
12677
  const UserConnectionsInput = object({
12721
12678
  offset: union([string(), number()]).optional(),
12722
12679
  limit: union([string(), number()]).optional(),
12723
- cursor: string().optional(),
12724
12680
  user_id: string().optional(),
12725
12681
  filter: string().optional()
12726
12682
  });
@@ -12731,8 +12687,7 @@ const UserConnectionsOutput = object({
12731
12687
  }).passthrough();
12732
12688
  const RequestsReceivedInput = object({
12733
12689
  offset: union([string(), number()]).optional(),
12734
- limit: union([string(), number()]).optional(),
12735
- cursor: string().optional()
12690
+ limit: union([string(), number()]).optional()
12736
12691
  });
12737
12692
  const RequestsReceivedOutput = object({
12738
12693
  data: array(record(string(), unknown())),
@@ -12741,8 +12696,7 @@ const RequestsReceivedOutput = object({
12741
12696
  }).passthrough();
12742
12697
  const RequestsSentInput = object({
12743
12698
  offset: union([string(), number()]).optional(),
12744
- limit: union([string(), number()]).optional(),
12745
- cursor: string().optional()
12699
+ limit: union([string(), number()]).optional()
12746
12700
  });
12747
12701
  const RequestsSentOutput = object({
12748
12702
  data: array(record(string(), unknown())),
@@ -13015,6 +12969,8 @@ const targetKindsFor = (op) => {
13015
12969
  };
13016
12970
  const positionalDisplayKeyFor$1 = (op, param) => op.config.paramLabels?.[param.name] ?? flagName(param.name);
13017
12971
  const bodyTextDisplayKeyFor$1 = (op) => op.config.bodyTextArg === void 0 ? void 0 : op.config.paramLabels?.[op.config.bodyTextArg] ?? op.config.bodyTextArg;
12972
+ const hasStdinBodyText$1 = (op) => op.config.bodyTextArg !== void 0;
12973
+ const stdinBodyTextRequired$1 = (op) => hasStdinBodyText$1(op) && op.config.bodyTextRequired !== false;
13018
12974
  const idempotencyFor$1 = (op) => {
13019
12975
  if (op.endpoint.capability === "read") return {
13020
12976
  safe: true,
@@ -13105,6 +13061,7 @@ const exampleCommandFor$1 = (op, commandName, root) => {
13105
13061
  const hint = `<${positionalDisplayKeyFor$1(op, param)}>`;
13106
13062
  parts.push(param.in === "path" || param.kind !== "array" ? hint : `${hint}...`);
13107
13063
  }
13064
+ if (hasStdinBodyText$1(op)) return `echo "..." | ${parts.join(" ")}`;
13108
13065
  if (op.hasBody) parts.push("--body", "'{...}'");
13109
13066
  return parts.join(" ");
13110
13067
  };
@@ -13119,16 +13076,19 @@ const signaturePartFor$1 = (op, name, arg) => {
13119
13076
  return arg.required === true ? `<${valueHint}>` : `[${valueHint}]`;
13120
13077
  }
13121
13078
  if (name === "limit") return "--limit N";
13122
- if (name === "body" && op.config.bodyTextArg === void 0) return "--body JSON";
13079
+ if (name === "body" && !hasStdinBodyText$1(op)) return "--body JSON";
13123
13080
  };
13081
+ const stdinSignaturePart$1 = (op) => hasStdinBodyText$1(op) ? "< body-text" : void 0;
13124
13082
  const usageFor$1 = (op, commandName, root) => {
13125
- const signature = Object.entries(buildArgs$1(op)).map(([name, arg]) => {
13083
+ const signatureParts = Object.entries(buildArgs$1(op)).map(([name, arg]) => {
13126
13084
  const part = signaturePartFor$1(op, name, arg);
13127
13085
  return part === void 0 ? void 0 : {
13128
13086
  positional: isObjectRecord$2(arg) && arg.type === "positional",
13129
13087
  part
13130
13088
  };
13131
- }).filter((entry) => entry !== void 0).sort((left, right) => Number(right.positional) - Number(left.positional)).map((entry) => entry.part).join(" ");
13089
+ }).filter((entry) => entry !== void 0).sort((left, right) => Number(right.positional) - Number(left.positional)).map((entry) => entry.part);
13090
+ const stdinPart = stdinSignaturePart$1(op);
13091
+ const signature = [...signatureParts, ...stdinPart ? [stdinPart] : []].join(" ");
13132
13092
  return [
13133
13093
  "social",
13134
13094
  "linkedin",
@@ -13138,7 +13098,15 @@ const usageFor$1 = (op, commandName, root) => {
13138
13098
  ].filter(Boolean).join(" ");
13139
13099
  };
13140
13100
  const helpDescriptionFor$1 = (op, commandName, root) => {
13141
- return `${`${op.config.summary} [${operationModeFor$1(op)}]`} | usage: \`${usageFor$1(op, commandName, root)}\``;
13101
+ const description = `${op.config.summary} [${operationModeFor$1(op)}]`;
13102
+ const usage = `usage: \`${usageFor$1(op, commandName, root)}\``;
13103
+ const label = [
13104
+ "social",
13105
+ "linkedin",
13106
+ ...root ? [] : [op.config.group],
13107
+ commandName
13108
+ ].join(" ");
13109
+ return `${description} | ${usage}${hasStdinBodyText$1(op) ? ` | body text is read from stdin: \`echo "..." | ${label}\` (or pass --body)` : ""}`;
13142
13110
  };
13143
13111
  const commandPathFor = (op) => `linkedin ${op.config.root ? op.config.command : `${op.config.group} ${op.config.command}`}`;
13144
13112
  const contractInputSchemaName = (op) => op.hasBody ? `${op.schemaBaseName}ContractInput` : `${op.schemaBaseName}Input`;
@@ -13196,15 +13164,6 @@ const buildArgs$1 = (op) => {
13196
13164
  type: "string",
13197
13165
  description: "JSON request body"
13198
13166
  };
13199
- if (op.config.bodyTextArg) {
13200
- const displayKey = bodyTextDisplayKeyFor$1(op) ?? op.config.bodyTextArg;
13201
- args[displayKey] = {
13202
- type: "positional",
13203
- required: false,
13204
- description: "Body value.",
13205
- valueHint: displayKey
13206
- };
13207
- }
13208
13167
  for (const [name, param] of Object.entries(op.config.bodyParams ?? {})) {
13209
13168
  const argName = bodyParamArg(name, param);
13210
13169
  args[flagName(argName)] = {
@@ -13294,7 +13253,7 @@ const buildBody = (deps, op, input) => {
13294
13253
  const bodyParamEntries = Object.entries(op.config.bodyParams ?? {});
13295
13254
  if (!bodyTextArg && bodyParamEntries.length === 0) return input.body === void 0 ? void 0 : deps.parseJSONObject("--body", input.body);
13296
13255
  const bodyFromJSON = input.body === void 0 ? void 0 : deps.parseJSONObject("--body", input.body);
13297
- const bodyText = bodyTextArg && input[bodyTextArg] !== void 0 ? deps.parseQueryString(`<${bodyTextDisplayKeyFor$1(op) ?? bodyTextArg}>`, input[bodyTextArg]) : void 0;
13256
+ const bodyText = bodyTextArg && input[bodyTextArg] !== void 0 ? deps.parseBodyText(`<${bodyTextDisplayKeyFor$1(op) ?? bodyTextArg}>`, input[bodyTextArg]) : void 0;
13298
13257
  const bodyParamValues = /* @__PURE__ */ new Map();
13299
13258
  for (const [name, param] of bodyParamEntries) {
13300
13259
  const value = input[name];
@@ -13329,8 +13288,29 @@ const dataWithAuditableWriteTarget = (op, data, body) => {
13329
13288
  post_id: postId
13330
13289
  };
13331
13290
  };
13291
+ const trimTrailingNewline$1 = (value) => value.endsWith("\r\n") ? value.slice(0, -2) : value.endsWith("\n") ? value.slice(0, -1) : value;
13292
+ const noBodyTextError$1 = (commandLabel) => new UsageError(`No body text. Pipe it via stdin: \`echo "..." | ${commandLabel}\` (or pass --body '<json>').`);
13293
+ const resolveBodyTextFromStdin$1 = async (op, deps, args, commandLabel) => {
13294
+ if (!hasStdinBodyText$1(op)) return;
13295
+ const bodyTextArg = bodyTextDisplayKeyFor$1(op) ?? op.config.bodyTextArg;
13296
+ if (bodyTextArg === void 0) return;
13297
+ const required = stdinBodyTextRequired$1(op) && typeof args.body !== "string";
13298
+ if (deps.isStdinTTY()) {
13299
+ if (required) throw noBodyTextError$1(commandLabel);
13300
+ return;
13301
+ }
13302
+ const piped = trimTrailingNewline$1(await deps.readStdin());
13303
+ if (piped.length > 0) args[bodyTextArg] = piped;
13304
+ else if (required) throw noBodyTextError$1(commandLabel);
13305
+ };
13332
13306
  const runOperation$1 = async (op, contract, deps, args, rawArgs = []) => {
13333
13307
  rejectUnsupportedArgs(commandPathFor(op), args, Object.keys(buildArgs$1(op)));
13308
+ await resolveBodyTextFromStdin$1(op, deps, args, [
13309
+ "social",
13310
+ "linkedin",
13311
+ ...op.config.root ? [] : [op.config.group],
13312
+ op.config.command
13313
+ ].join(" "));
13334
13314
  checkBodyRequired(op, args);
13335
13315
  const account = typeof args.account === "string" ? args.account : void 0;
13336
13316
  const input = buildInput$1(op, args);
@@ -13487,7 +13467,8 @@ const defineOperationCommand$1 = (op, deps) => {
13487
13467
  method: op.endpoint.method,
13488
13468
  capability: op.endpoint.capability,
13489
13469
  mutates: op.endpoint.mutates,
13490
- schemaContract: contract
13470
+ schemaContract: contract,
13471
+ ...hasStdinBodyText$1(op) ? { stdin: true } : {}
13491
13472
  }),
13492
13473
  args: buildArgs$1(op),
13493
13474
  run: async ({ args, rawArgs }) => runOperation$1(op, contract, deps, args, rawArgs)
@@ -13718,7 +13699,7 @@ const buildMark = (deps) => {
13718
13699
  reason: "Setting a LinkedIn chat read status is safe to retry."
13719
13700
  },
13720
13701
  confirmation: { required: false },
13721
- pagination: null,
13702
+ pagination: { style: "none" },
13722
13703
  responseShaping: {
13723
13704
  supported: true,
13724
13705
  formats: ["json"],
@@ -13839,7 +13820,7 @@ const buildMessageDelete = (deps) => {
13839
13820
  required: true,
13840
13821
  reason: "Deletes a LinkedIn message immediately."
13841
13822
  },
13842
- pagination: null,
13823
+ pagination: { style: "none" },
13843
13824
  responseShaping: {
13844
13825
  supported: true,
13845
13826
  formats: ["json"],
@@ -13909,7 +13890,7 @@ const buildMessageEdit = (deps) => {
13909
13890
  return defineCommand({
13910
13891
  meta: commandMeta$2({
13911
13892
  name: "edit",
13912
- description: "Edit one of your LinkedIn messages [write] | usage: `social linkedin message <target> edit message_id:<id> <text>`",
13893
+ description: "Edit one of your LinkedIn messages [write] | usage: `social linkedin message <target> edit message_id:<id> < body-text` | new text is read from stdin: `echo \"...\" | social linkedin message <target> edit message_id:<id>`",
13913
13894
  method: "POST",
13914
13895
  capability: "write",
13915
13896
  mutates: true,
@@ -13929,19 +13910,20 @@ const buildMessageEdit = (deps) => {
13929
13910
  reason: "Re-applying the same LinkedIn message edit is safe."
13930
13911
  },
13931
13912
  confirmation: { required: false },
13932
- pagination: null,
13913
+ pagination: { style: "none" },
13933
13914
  responseShaping: {
13934
13915
  supported: true,
13935
13916
  formats: ["json"],
13936
13917
  projection: true
13937
13918
  },
13938
13919
  cost: writeCost(creditsForCostBPS$1(DM_INTERACTION_ENDPOINT_BILLING.costBPS)),
13939
- examples: [{ command: "linkedin message <target> edit message_id:<id> \"fixed text\"" }],
13920
+ examples: [{ command: "echo \"fixed text\" | linkedin message <target> edit message_id:<id>" }],
13940
13921
  hazards: [{
13941
13922
  code: "remote_write",
13942
13923
  message: "Edits a LinkedIn message immediately."
13943
13924
  }]
13944
- }
13925
+ },
13926
+ stdin: true
13945
13927
  }),
13946
13928
  args: {
13947
13929
  target: {
@@ -13956,12 +13938,6 @@ const buildMessageEdit = (deps) => {
13956
13938
  description: "Message to edit, as message_id:<id> (from `messages <target>`)",
13957
13939
  valueHint: "message_id:<id>"
13958
13940
  },
13959
- text: {
13960
- type: "positional",
13961
- required: true,
13962
- description: "New message text",
13963
- valueHint: "text"
13964
- },
13965
13941
  account: {
13966
13942
  type: "string",
13967
13943
  description: "Account selector: @handle or profile_id:<id>; overrides config default"
@@ -13971,9 +13947,12 @@ const buildMessageEdit = (deps) => {
13971
13947
  const positionals = Array.isArray(args._) ? args._ : [];
13972
13948
  const account = typeof args.account === "string" ? args.account : void 0;
13973
13949
  const message_id = messageIdFrom(deps, args.message_id ?? positionals[1]);
13974
- const textInput = args.text ?? positionals[2];
13975
- const text = textInput === void 0 ? void 0 : deps.parseQueryString("<text>", textInput);
13976
- if (text === void 0) throw new UsageError("Pass the new message <text>.");
13950
+ let textInput;
13951
+ if (deps.isStdinTTY()) throw noBodyTextError$1("social linkedin message <target> edit message_id:<id>");
13952
+ const piped = trimTrailingNewline$1(await deps.readStdin());
13953
+ if (piped.length > 0) textInput = piped;
13954
+ const text = textInput === void 0 ? void 0 : deps.parseBodyText("<text>", textInput);
13955
+ if (text === void 0) throw noBodyTextError$1("social linkedin message <target> edit message_id:<id>");
13977
13956
  const resolved = [];
13978
13957
  const chatIdResolved = await deps.resolveTarget("target", args.target ?? positionals[0], {
13979
13958
  platform: "linkedin",
@@ -14010,11 +13989,16 @@ const buildMessage$1 = (deps, sendCommand) => {
14010
13989
  return defineCommand({
14011
13990
  meta: commandMeta$2({
14012
13991
  name: "message",
14013
- description: "Send a LinkedIn message to a person or conversation [write] | usage: `social linkedin message <target> [text]`",
13992
+ description: "Send a LinkedIn message to a person or conversation [write] | usage: `social linkedin message <target> < body-text` | body text is read from stdin: `echo \"...\" | social linkedin message <target>` (or pass --body)",
14014
13993
  method: "POST",
14015
13994
  capability: "write",
14016
13995
  mutates: true,
14017
- schemaContract
13996
+ schemaContract,
13997
+ stdin: true,
13998
+ schemaSubCommands: {
13999
+ delete: deleteCommand,
14000
+ edit: editCommand
14001
+ }
14018
14002
  }),
14019
14003
  args: {
14020
14004
  target: {
@@ -14023,11 +14007,9 @@ const buildMessage$1 = (deps, sendCommand) => {
14023
14007
  description: "LinkedIn person or conversation target: @handle, profile URL, profile_id:<id>, chat_id:<id>, or a messaging thread URL",
14024
14008
  valueHint: "target"
14025
14009
  },
14026
- text: {
14027
- type: "positional",
14028
- required: true,
14029
- description: "Message text",
14030
- valueHint: "text"
14010
+ body: {
14011
+ type: "string",
14012
+ description: "JSON request body"
14031
14013
  },
14032
14014
  account: {
14033
14015
  type: "string",
@@ -14044,18 +14026,25 @@ const buildMessage$1 = (deps, sendCommand) => {
14044
14026
  _: [],
14045
14027
  account: args.account,
14046
14028
  target: positionals[0],
14047
- message_id: positionals[2],
14048
- ...positionals[1] === "edit" ? { text: positionals[3] } : {}
14029
+ message_id: positionals[2]
14049
14030
  },
14050
14031
  cmd: verbCommand
14051
14032
  });
14052
14033
  return;
14053
14034
  }
14054
14035
  const target = args.target ?? (Array.isArray(args._) && args._.length > 0 ? args._[0] : void 0);
14055
- const textInput = args.text ?? (Array.isArray(args._) && args._.length > 1 ? args._[1] : void 0);
14036
+ const hasBody = typeof args.body === "string";
14037
+ let textInput;
14038
+ if (deps.isStdinTTY()) {
14039
+ if (!hasBody) throw noBodyTextError$1("social linkedin message <target>");
14040
+ } else {
14041
+ const piped = trimTrailingNewline$1(await deps.readStdin());
14042
+ if (piped.length > 0) textInput = piped;
14043
+ else if (!hasBody) throw noBodyTextError$1("social linkedin message <target>");
14044
+ }
14056
14045
  if (target === void 0) throw new UsageError("Pass a conversation or person target.");
14057
14046
  const bodyFromJSON = typeof args.body === "string" ? deps.parseJSONObject("--body", args.body) : void 0;
14058
- const text = textInput === void 0 ? void 0 : deps.parseQueryString("<text>", textInput);
14047
+ const text = textInput === void 0 ? void 0 : deps.parseBodyText("<text>", textInput);
14059
14048
  const body = text === void 0 ? bodyFromJSON : {
14060
14049
  ...bodyFromJSON ?? {},
14061
14050
  text
@@ -14147,7 +14136,8 @@ const buildMessages$1 = (deps, listCommand, readCommand) => {
14147
14136
  method: "GET",
14148
14137
  capability: "read",
14149
14138
  mutates: false,
14150
- schemaContract: listCommand.meta.schemaContract
14139
+ schemaContract: listCommand.meta.schemaContract,
14140
+ schemaSubCommands: { mark: markCommand }
14151
14141
  }),
14152
14142
  args: {
14153
14143
  target: {
@@ -14302,6 +14292,9 @@ createLinkedinCommands({
14302
14292
  },
14303
14293
  parseResourceId: unconfigured$1,
14304
14294
  parseQueryString: unconfigured$1,
14295
+ parseBodyText: unconfigured$1,
14296
+ readStdin: unconfigured$1,
14297
+ isStdinTTY: unconfigured$1,
14305
14298
  parseIntegerString: unconfigured$1,
14306
14299
  parseEnumString: unconfigured$1,
14307
14300
  parseBooleanString: unconfigured$1,
@@ -17017,6 +17010,9 @@ const isRequired = (op, param, positional) => {
17017
17010
  };
17018
17011
  const positionalDisplayKeyFor = (op, param) => op.config.paramLabels?.[param.name] ?? flagName(param.name);
17019
17012
  const bodyTextDisplayKeyFor = (op) => op.config.bodyTextArg === void 0 ? void 0 : op.config.paramLabels?.[op.config.bodyTextArg] ?? op.config.bodyTextArg;
17013
+ const resolvesTargetArg = (op) => op.config.bodyTextArg !== void 0 && (op.config.resolveResourceParams ?? []).includes(op.config.bodyTextArg);
17014
+ const hasStdinBodyText = (op) => op.config.bodyTextArg !== void 0 && !resolvesTargetArg(op);
17015
+ const stdinBodyTextRequired = (op) => hasStdinBodyText(op) && op.config.bodyTextRequired !== false;
17020
17016
  const kindsOf = (targetKind, fallback) => {
17021
17017
  const kind = targetKind ?? fallback;
17022
17018
  if (kind === void 0) throw new Error("target_kind_missing");
@@ -17151,6 +17147,7 @@ const exampleCommandFor = (op, commandName, group) => {
17151
17147
  }
17152
17148
  }
17153
17149
  if (op.parameters.some((p) => p.name === "max_results")) parts.push("--limit", "10");
17150
+ if (hasStdinBodyText(op)) return `echo "Hello from social" | ${parts.join(" ")}`;
17154
17151
  if (op.hasBody) parts.push("--body", JSON.stringify(exampleBodyFor(op)));
17155
17152
  return parts.join(" ");
17156
17153
  };
@@ -17165,16 +17162,19 @@ const signaturePartFor = (op, name, arg) => {
17165
17162
  return arg.required === true ? `<${valueHint}>` : `[${valueHint}]`;
17166
17163
  }
17167
17164
  if (name === "limit") return "--limit N";
17168
- if (name === "body" && op.config.bodyTextArg === void 0) return "--body JSON";
17165
+ if (name === "body" && !hasStdinBodyText(op)) return "--body JSON";
17169
17166
  };
17167
+ const stdinSignaturePart = (op) => hasStdinBodyText(op) ? "< body-text" : void 0;
17170
17168
  const usageFor = (op, commandName, group) => {
17171
- const signature = Object.entries(buildArgs(op)).map(([name, arg]) => {
17169
+ const signatureParts = Object.entries(buildArgs(op)).map(([name, arg]) => {
17172
17170
  const part = signaturePartFor(op, name, arg);
17173
17171
  return part === void 0 ? void 0 : {
17174
17172
  positional: isObjectRecord$1(arg) && arg.type === "positional",
17175
17173
  part
17176
17174
  };
17177
- }).filter((entry) => entry !== void 0).sort((left, right) => Number(right.positional) - Number(left.positional)).map((entry) => entry.part).join(" ");
17175
+ }).filter((entry) => entry !== void 0).sort((left, right) => Number(right.positional) - Number(left.positional)).map((entry) => entry.part);
17176
+ const stdinPart = stdinSignaturePart(op);
17177
+ const signature = [...signatureParts, ...stdinPart ? [stdinPart] : []].join(" ");
17178
17178
  return [
17179
17179
  "social",
17180
17180
  "x",
@@ -17183,7 +17183,15 @@ const usageFor = (op, commandName, group) => {
17183
17183
  ].filter(Boolean).join(" ");
17184
17184
  };
17185
17185
  const helpDescriptionFor = (op, commandName, group) => {
17186
- return `${`${op.config.summary} [${operationModeFor(op)}]`} | usage: \`${usageFor(op, commandName, group)}\``;
17186
+ const description = `${op.config.summary} [${operationModeFor(op)}]`;
17187
+ const usage = `usage: \`${usageFor(op, commandName, group)}\``;
17188
+ const label = [
17189
+ "social",
17190
+ "x",
17191
+ group,
17192
+ commandName
17193
+ ].filter(Boolean).join(" ");
17194
+ return `${description} | ${usage}${hasStdinBodyText(op) ? ` | body text is read from stdin: \`echo "..." | ${label}\` (or pass --body)` : ""}`;
17187
17195
  };
17188
17196
  const contractFor$1 = (op, commandName, group) => {
17189
17197
  const mutates = op.endpoint.mutates;
@@ -17233,12 +17241,12 @@ const buildArgs = (op) => {
17233
17241
  type: "string",
17234
17242
  description: "JSON request body"
17235
17243
  };
17236
- if (op.config.bodyTextArg) {
17244
+ if (op.config.bodyTextArg && resolvesTargetArg(op)) {
17237
17245
  const displayKey = bodyTextDisplayKeyFor(op) ?? op.config.bodyTextArg;
17238
17246
  args[displayKey] = {
17239
17247
  type: "positional",
17240
17248
  required: false,
17241
- description: (op.config.resolveResourceParams ?? []).includes(op.config.bodyTextArg) ? targetDescriptionFor(op.config.targetKind) : "Body value.",
17249
+ description: targetDescriptionFor(op.config.targetKind),
17242
17250
  valueHint: displayKey
17243
17251
  };
17244
17252
  }
@@ -17374,8 +17382,29 @@ const withEchoedTargetId = (op, data, body) => {
17374
17382
  }
17375
17383
  };
17376
17384
  };
17385
+ const trimTrailingNewline = (value) => value.endsWith("\r\n") ? value.slice(0, -2) : value.endsWith("\n") ? value.slice(0, -1) : value;
17386
+ const noBodyTextError = (commandLabel) => new UsageError(`No body text. Pipe it via stdin: \`echo "..." | ${commandLabel}\` (or pass --body '<json>').`);
17387
+ const resolveBodyTextFromStdin = async (op, deps, args, commandLabel) => {
17388
+ if (!hasStdinBodyText(op)) return;
17389
+ const bodyTextArg = bodyTextDisplayKeyFor(op) ?? op.config.bodyTextArg;
17390
+ if (bodyTextArg === void 0) return;
17391
+ const required = stdinBodyTextRequired(op) && args.body === void 0;
17392
+ if (deps.isStdinTTY()) {
17393
+ if (required) throw noBodyTextError(commandLabel);
17394
+ return;
17395
+ }
17396
+ const piped = trimTrailingNewline(await deps.readStdin());
17397
+ if (piped.length > 0) args[bodyTextArg] = piped;
17398
+ else if (required) throw noBodyTextError(commandLabel);
17399
+ };
17377
17400
  const runOperation = async (op, contract, deps, args, rawArgs = []) => {
17378
17401
  rejectUnknownArgs(op, args);
17402
+ await resolveBodyTextFromStdin(op, deps, args, [
17403
+ "social",
17404
+ "x",
17405
+ op.config.root ? "" : op.config.group,
17406
+ op.config.command
17407
+ ].filter(Boolean).join(" "));
17379
17408
  const account = typeof args.account === "string" ? args.account : void 0;
17380
17409
  let ownAccount;
17381
17410
  const resolveOwnAccount = async () => {
@@ -17458,12 +17487,12 @@ const runOperation = async (op, contract, deps, args, rawArgs = []) => {
17458
17487
  const textArg = op.config.bodyTextArg;
17459
17488
  if (textArg) {
17460
17489
  const displayTextArg = bodyTextDisplayKeyFor(op) ?? textArg;
17461
- const bodyText = input[textArg] === void 0 ? void 0 : deps.parseQueryString(`<${displayTextArg}>`, input[textArg]);
17490
+ const bodyText = input[textArg] === void 0 ? void 0 : deps.parseBodyText(`<${displayTextArg}>`, input[textArg]);
17462
17491
  body = bodyText === void 0 ? bodyFromJSON : {
17463
17492
  ...bodyFromJSON ?? {},
17464
17493
  [textArg]: bodyText
17465
17494
  };
17466
- if (body === void 0 && op.config.bodyTextRequired === true) throw new UsageError(`Pass <${displayTextArg}> or --body.`);
17495
+ if (body === void 0 && resolvesTargetArg(op) && op.config.bodyTextRequired === true) throw new UsageError(`Pass <${displayTextArg}> or --body.`);
17467
17496
  } else body = bodyFromJSON;
17468
17497
  body = await applyCreatePostReply(deps, op, input, body, resolved, account);
17469
17498
  }
@@ -17493,7 +17522,8 @@ const defineOperationCommand = (op, deps) => {
17493
17522
  method: op.endpoint.method,
17494
17523
  capability: op.endpoint.capability,
17495
17524
  mutates: op.endpoint.mutates,
17496
- contract
17525
+ contract,
17526
+ ...hasStdinBodyText(op) ? { stdin: true } : {}
17497
17527
  }),
17498
17528
  args: buildArgs(op),
17499
17529
  run: async ({ args, rawArgs }) => runOperation(op, contract, deps, args, rawArgs)
@@ -17916,11 +17946,12 @@ const buildMessage = (deps) => {
17916
17946
  return defineCommand({
17917
17947
  meta: commandMeta$1({
17918
17948
  name: "message",
17919
- description: "Send a DM to a participant or conversation [write] | usage: `social x message <recipients> [text]`",
17949
+ description: "Send a DM to a participant or conversation [write] | usage: `social x message <recipients> < body-text` | body text is read from stdin: `echo \"...\" | social x message <recipients>` (or pass --body)",
17920
17950
  method: "POST",
17921
17951
  capability: "write",
17922
17952
  mutates: true,
17923
- contract
17953
+ contract,
17954
+ stdin: true
17924
17955
  }),
17925
17956
  args: {
17926
17957
  recipients: {
@@ -17929,12 +17960,6 @@ const buildMessage = (deps) => {
17929
17960
  description: "Recipient(s): chat URL, chat_id:<id>, @handle, profile URL, or profile_id:<id>; comma-separate profiles for a group",
17930
17961
  valueHint: "recipients"
17931
17962
  },
17932
- text: {
17933
- type: "positional",
17934
- required: false,
17935
- description: "Message text",
17936
- valueHint: "text"
17937
- },
17938
17963
  body: {
17939
17964
  type: "string",
17940
17965
  description: "JSON request body"
@@ -17946,12 +17971,20 @@ const buildMessage = (deps) => {
17946
17971
  },
17947
17972
  run: async ({ args }) => {
17948
17973
  const recipientsInput = args.recipients ?? args.target ?? (Array.isArray(args._) && args._.length > 0 ? args._[0] : void 0);
17949
- const textInput = args.text ?? (Array.isArray(args._) && args._.length > 1 ? args._[1] : void 0);
17974
+ const hasBody = typeof args.body === "string";
17975
+ let textInput;
17976
+ if (deps.isStdinTTY()) {
17977
+ if (!hasBody) throw noBodyTextError("social x message <recipients>");
17978
+ } else {
17979
+ const piped = trimTrailingNewline(await deps.readStdin());
17980
+ if (piped.length > 0) textInput = piped;
17981
+ else if (!hasBody) throw noBodyTextError("social x message <recipients>");
17982
+ }
17950
17983
  if (recipientsInput === void 0) throw new UsageError("Pass a conversation or user target.");
17951
17984
  const recipients = String(recipientsInput).split(",").map((recipient) => recipient.trim()).filter((recipient) => recipient.length > 0);
17952
17985
  if (recipients.length === 0) throw new UsageError("Pass at least one recipient.");
17953
17986
  const bodyFromJSON = typeof args.body === "string" ? deps.parseJSONObject("--body", args.body) : void 0;
17954
- const text = textInput === void 0 ? void 0 : deps.parseQueryString("--text", textInput);
17987
+ const text = textInput === void 0 ? void 0 : deps.parseBodyText("--text", textInput);
17955
17988
  const body = text === void 0 ? bodyFromJSON : {
17956
17989
  ...bodyFromJSON ?? {},
17957
17990
  text
@@ -18008,9 +18041,110 @@ const buildMessage = (deps) => {
18008
18041
  }
18009
18042
  });
18010
18043
  };
18044
+ const searchOp = (() => {
18045
+ const op = X_OPERATIONS.find((candidate) => candidate.config.command === "search");
18046
+ if (op === void 0) throw new Error("x_cli_search_operation_missing");
18047
+ return op;
18048
+ })();
18049
+ const repliesOp = {
18050
+ schemaBaseName: searchOp.schemaBaseName,
18051
+ hasBody: false,
18052
+ config: {
18053
+ command: "replies",
18054
+ group: "tweets",
18055
+ root: true,
18056
+ summary: "List replies to a post",
18057
+ itemUrlTemplate: "https://x.com/i/web/status/{id}",
18058
+ fieldPresets: searchOp.config.fieldPresets
18059
+ },
18060
+ endpoint: searchOp.endpoint,
18061
+ parameters: []
18062
+ };
18063
+ const conversationIdPrefix = "conversation_id:";
18064
+ const buildReplies = (deps) => {
18065
+ const contract = contractFor$1(repliesOp, "replies", "");
18066
+ const presets = repliesOp.config.fieldPresets ?? {};
18067
+ return defineCommand({
18068
+ meta: commandMeta$1({
18069
+ name: "replies",
18070
+ description: "List replies to a post [read] | usage: `social x replies <post-or-conversation> --limit N` | accepts conversation_id:<id>, post_id:<id>, or a post URL",
18071
+ method: "GET",
18072
+ capability: "read",
18073
+ mutates: false,
18074
+ contract
18075
+ }),
18076
+ args: {
18077
+ target: {
18078
+ type: "positional",
18079
+ required: true,
18080
+ description: "Post or conversation: conversation_id:<id>, post_id:<id>, or a post URL",
18081
+ valueHint: "target"
18082
+ },
18083
+ limit: {
18084
+ type: "string",
18085
+ description: "Rows to return (10-100)"
18086
+ },
18087
+ cursor: {
18088
+ type: "string",
18089
+ description: "Cursor from a previous response"
18090
+ },
18091
+ account: {
18092
+ type: "string",
18093
+ description: "Account selector: @handle or profile_id:<id>; overrides config default"
18094
+ }
18095
+ },
18096
+ run: async ({ args }) => {
18097
+ const positional = Array.isArray(args._) ? args._ : [];
18098
+ const targetInput = args.target ?? (positional.length > 0 ? positional[0] : void 0);
18099
+ if (targetInput === void 0) throw new UsageError("Pass a post or conversation target.");
18100
+ const target = String(targetInput).trim();
18101
+ const account = typeof args.account === "string" ? args.account : void 0;
18102
+ const selectedAccount = await deps.resolveAccount({
18103
+ platform: "x",
18104
+ account
18105
+ });
18106
+ const accountIdHeader = selectedAccount.selector;
18107
+ const headers = { ...accountIdHeader === void 0 ? {} : { "x-social-account-id": accountIdHeader } };
18108
+ const resolved = [];
18109
+ let conversationId;
18110
+ if (target.startsWith(conversationIdPrefix)) conversationId = deps.parseResourceId("conversation_id", target.slice(16));
18111
+ else {
18112
+ const resolution = await deps.resolveTarget("target", target, {
18113
+ platform: "x",
18114
+ expect: ["post"],
18115
+ account
18116
+ });
18117
+ resolved.push(resolution.record);
18118
+ const lookupData = await (await deps.api.get(`x/tweets/${encodeURIComponent(resolution.id)}?tweet.fields=conversation_id`, { headers })).json();
18119
+ const post = isObjectRecord(lookupData) ? lookupData.data : void 0;
18120
+ const candidate = isObjectRecord(post) ? post.conversation_id : void 0;
18121
+ if (typeof candidate !== "string" || candidate.length === 0) throw new UsageError(`Could not read conversation_id for ${target} (the post may be deleted or protected).`);
18122
+ conversationId = candidate;
18123
+ }
18124
+ const params = new URLSearchParams();
18125
+ params.set("query", `${conversationIdPrefix}${conversationId} is:reply`);
18126
+ if (args.limit !== void 0) params.set("max_results", String(deps.parseIntegerString("--limit", args.limit, {
18127
+ min: 10,
18128
+ max: 100
18129
+ })));
18130
+ if (args.cursor !== void 0) params.set("next_token", deps.parseQueryString("--cursor", args.cursor));
18131
+ for (const [field, value] of Object.entries(presets)) params.set(field, deps.parseQueryString(`--${field}`, value));
18132
+ const response = await deps.api.get(`x/tweets/search/recent?${params.toString()}`, { headers });
18133
+ const data = await response.json();
18134
+ await deps.printResult({
18135
+ account: selectedAccount,
18136
+ contract,
18137
+ data,
18138
+ resolved,
18139
+ responseHeaders: response.headers
18140
+ });
18141
+ }
18142
+ });
18143
+ };
18011
18144
  const createXCommands = (deps) => {
18012
18145
  const messages = buildMessages(deps);
18013
18146
  const message = buildMessage(deps);
18147
+ const replies = buildReplies(deps);
18014
18148
  const sync = buildSync(deps, "x");
18015
18149
  const sql = buildSql(deps, "x");
18016
18150
  const entries = X_OPERATIONS.map((op, index) => ({
@@ -18029,16 +18163,21 @@ const createXCommands = (deps) => {
18029
18163
  command: message,
18030
18164
  rank: 1,
18031
18165
  index: X_OPERATIONS.length + 1
18166
+ }, {
18167
+ name: "replies",
18168
+ command: replies,
18169
+ rank: 0,
18170
+ index: X_OPERATIONS.length + 2
18032
18171
  }, {
18033
18172
  name: "sync",
18034
18173
  command: sync,
18035
18174
  rank: 0,
18036
- index: X_OPERATIONS.length + 2
18175
+ index: X_OPERATIONS.length + 3
18037
18176
  }, {
18038
18177
  name: "sql",
18039
18178
  command: sql,
18040
18179
  rank: 0,
18041
- index: X_OPERATIONS.length + 3
18180
+ index: X_OPERATIONS.length + 4
18042
18181
  });
18043
18182
  entries.sort((left, right) => left.rank - right.rank || left.index - right.index);
18044
18183
  return defineCommand({
@@ -18062,6 +18201,9 @@ createXCommands({
18062
18201
  },
18063
18202
  parseResourceId: unconfigured,
18064
18203
  parseQueryString: unconfigured,
18204
+ parseBodyText: unconfigured,
18205
+ readStdin: unconfigured,
18206
+ isStdinTTY: unconfigured,
18065
18207
  parseIntegerString: unconfigured,
18066
18208
  parseEnumString: unconfigured,
18067
18209
  parseBooleanString: unconfigured,
@@ -20922,7 +21064,7 @@ const createInstance = (defaults) => {
20922
21064
  const ky = createInstance();
20923
21065
  //#endregion
20924
21066
  //#region package.json
20925
- var version$1 = "0.2.6";
21067
+ var version$1 = "0.3.1";
20926
21068
  //#endregion
20927
21069
  //#region src/lib/env.ts
20928
21070
  const URLWithTrailingSlash = url().transform(ensureTrailingSlash);
@@ -21312,6 +21454,12 @@ let outputWriters = {
21312
21454
  stdout: writeStdout,
21313
21455
  stderr: (value) => process.stderr.write(`${value}\n`)
21314
21456
  };
21457
+ const readStdin = async () => {
21458
+ process.stdin.setEncoding("utf8");
21459
+ let input = "";
21460
+ for await (const chunk of process.stdin) input += chunk;
21461
+ return input;
21462
+ };
21315
21463
  const printLine = (value) => {
21316
21464
  outputWriters.stdout(value);
21317
21465
  };
@@ -21331,6 +21479,10 @@ const stringAtPath = (value, path) => {
21331
21479
  const found = valueAtPath(value, path);
21332
21480
  return typeof found === "string" && found.length > 0 ? found : void 0;
21333
21481
  };
21482
+ const numberAtPath = (value, path) => {
21483
+ const found = valueAtPath(value, path);
21484
+ return typeof found === "number" && Number.isFinite(found) ? found : void 0;
21485
+ };
21334
21486
  const idForRecord = (record) => {
21335
21487
  for (const key of [
21336
21488
  "id",
@@ -21424,11 +21576,18 @@ const nextCursorFrom = (contract, data) => {
21424
21576
  const response = pagination.response;
21425
21577
  return stringAtPath(data, isRecord$3(response) ? response.nextCursorPath : null) ?? stringAtPath(data, pagination.cursorPath);
21426
21578
  };
21579
+ const totalCountFrom = (contract, data) => {
21580
+ if (!isRecord$3(contract)) return;
21581
+ const pagination = contract.pagination;
21582
+ if (!isRecord$3(pagination)) return;
21583
+ return numberAtPath(data, pagination.totalCountPath);
21584
+ };
21427
21585
  const resultEnvelope = ({ account, contract, data, resolved = [], responseHeaders }) => {
21428
21586
  const payload = outputPayloadFor(data, itemURLTemplateFrom(contract), idFieldFrom(contract));
21429
21587
  const cache = cacheFromHeaders(responseHeaders);
21430
21588
  const itemCount = "items" in payload && Array.isArray(payload.items) ? payload.items.length : 1;
21431
21589
  const cursor = nextCursorFrom(contract, data);
21590
+ const totalCount = totalCountFrom(contract, data);
21432
21591
  return {
21433
21592
  account: {
21434
21593
  platform: account.platform,
@@ -21439,7 +21598,8 @@ const resultEnvelope = ({ account, contract, data, resolved = [], responseHeader
21439
21598
  resolved,
21440
21599
  cost: costFromContract(contract, itemCount, cache.hit, responseHeaders),
21441
21600
  cache,
21442
- ...cursor === void 0 ? {} : { cursor }
21601
+ ...cursor === void 0 ? {} : { cursor },
21602
+ ...totalCount === void 0 ? {} : { totalCount }
21443
21603
  }
21444
21604
  };
21445
21605
  };
@@ -21486,16 +21646,21 @@ const BOOLEAN_STRINGS = [
21486
21646
  "off"
21487
21647
  ];
21488
21648
  const hasControlCharacter = (value) => [...value].some((character) => character.charCodeAt(0) < 32);
21649
+ const hasDisallowedControlCharacter = (value) => [...value].some((character) => {
21650
+ const code = character.charCodeAt(0);
21651
+ return code < 32 && code !== 9 && code !== 10 && code !== 13;
21652
+ });
21489
21653
  const validationError = (path, message) => new ZodError([{
21490
21654
  code: "custom",
21491
21655
  path,
21492
21656
  message
21493
21657
  }]);
21494
21658
  const rejectControlCharacters = (name) => string().refine((value) => !hasControlCharacter(value), { message: `${name} must not contain control characters.` });
21659
+ const BodyText = (name) => string().refine((value) => !hasDisallowedControlCharacter(value), { message: `${name} must not contain control characters.` });
21495
21660
  const ResourceId = (name) => rejectControlCharacters(name).min(1, `${name} is required`).refine((value) => !UNSAFE_RESOURCE_CHARACTER_PATTERN.test(value), { message: `${name} must be a plain resource ID, not a URL, path, query string, or encoded value.` });
21496
21661
  const QueryString = (name) => rejectControlCharacters(name).check(/* @__PURE__ */ _minLength(1, `${name} must not be empty.`));
21497
21662
  const rejectControlCharactersInJSON = (name, value, path = []) => {
21498
- if (typeof value === "string" && hasControlCharacter(value)) throw validationError(path.length > 0 ? path : ["value"], `${name} must not contain control characters.`);
21663
+ if (typeof value === "string" && hasDisallowedControlCharacter(value)) throw validationError(path.length > 0 ? path : ["value"], `${name} must not contain control characters.`);
21499
21664
  if (Array.isArray(value)) {
21500
21665
  for (const [index, item] of value.entries()) rejectControlCharactersInJSON(name, item, [...path, String(index)]);
21501
21666
  return;
@@ -21509,6 +21674,7 @@ const parseWithSchema = (value, schema) => {
21509
21674
  };
21510
21675
  const parseResourceId = (name, value) => parseWithSchema(value, ResourceId(name));
21511
21676
  const parseQueryString = (name, value) => parseWithSchema(value, QueryString(name));
21677
+ const parseBodyText = (name, value) => parseWithSchema(value, BodyText(name));
21512
21678
  const parseResourceIdList = (name, values) => {
21513
21679
  const parsed = array(ResourceId(name)).min(1, `${name} requires at least one ID.`).safeParse(values.map((value) => String(value)));
21514
21680
  if (parsed.success) return parsed.data;
@@ -28350,6 +28516,9 @@ const createCLIDeps = () => {
28350
28516
  api,
28351
28517
  parseResourceId,
28352
28518
  parseQueryString,
28519
+ parseBodyText,
28520
+ readStdin,
28521
+ isStdinTTY: () => process.stdin.isTTY === true,
28353
28522
  parseIntegerString,
28354
28523
  parseEnumString,
28355
28524
  parseBooleanString,
@@ -28465,7 +28634,12 @@ const pathPartsFrom = (...values) => {
28465
28634
  const commandName = (command, fallback) => typeof command.meta?.name === "string" ? command.meta.name : fallback;
28466
28635
  const commandDescription = (command) => typeof command.meta?.description === "string" ? command.meta.description : "";
28467
28636
  const isHiddenCommand = (command) => command.meta?.hidden === true;
28637
+ const inputSourceFor = (command) => command.meta?.stdin === true ? { inputSource: "stdin" } : {};
28468
28638
  const isRecord = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
28639
+ const childCommandsFor = (command) => ({
28640
+ ...command.subCommands ?? {},
28641
+ ...isRecord(command.meta?.schemaSubCommands) ? command.meta.schemaSubCommands : {}
28642
+ });
28469
28643
  const firstDefined = (...values) => values.find((value) => value !== void 0);
28470
28644
  const JSONMetadata = lazy(() => union([
28471
28645
  _null(),
@@ -28624,7 +28798,8 @@ const compactSchemaForCommand = (command, path) => {
28624
28798
  description: commandDescription(command),
28625
28799
  ...method ? { method } : {},
28626
28800
  capability: capability ?? "unknown",
28627
- mutates: mutates ?? false
28801
+ mutates: mutates ?? false,
28802
+ ...inputSourceFor(command)
28628
28803
  };
28629
28804
  };
28630
28805
  const schemaForCommand = (command, path) => {
@@ -28644,6 +28819,7 @@ const schemaForCommand = (command, path) => {
28644
28819
  name: path.join(".") || commandName(command, "social"),
28645
28820
  description: commandDescription(command),
28646
28821
  ...method ? { method } : {},
28822
+ ...inputSourceFor(command),
28647
28823
  args: metadataValueFor(contract.args, `${label}.args`) ?? positionalArgs,
28648
28824
  flags: metadataValueFor(contract.flags, `${label}.flags`) ?? flags,
28649
28825
  params: metadataValueFor(contract.params, `${label}.params`) ?? args,
@@ -28663,25 +28839,26 @@ const schemaForCommand = (command, path) => {
28663
28839
  };
28664
28840
  };
28665
28841
  const treeForCommand = (command, path = []) => {
28666
- const subCommands = command.subCommands ?? {};
28842
+ const subCommands = childCommandsFor(command);
28667
28843
  return {
28668
28844
  ...compactSchemaForCommand(command, path),
28669
28845
  subCommands: Object.fromEntries(Object.entries(subCommands).filter(([, subCommand]) => !isHiddenCommand(subCommand)).map(([name, subCommand]) => [name, treeForCommand(subCommand, [...path, commandName(subCommand, name)])]))
28670
28846
  };
28671
28847
  };
28672
28848
  const leafSchemasForCommand = (command, path = []) => {
28673
- const subCommands = command.subCommands ?? {};
28674
- const entries = Object.entries(subCommands).filter(([, subCommand]) => !isHiddenCommand(subCommand));
28849
+ const subCommands = childCommandsFor(command);
28850
+ const allEntries = Object.entries(subCommands);
28851
+ const entries = allEntries.filter(([, subCommand]) => !isHiddenCommand(subCommand));
28675
28852
  const runnable = typeof command.run === "function";
28676
- return [...path.length > 0 && (runnable || entries.length === 0) ? [[path.join(" "), schemaForCommand(command, path)]] : [], ...entries.flatMap(([name, subCommand]) => leafSchemasForCommand(subCommand, [...path, commandName(subCommand, name)]))];
28853
+ return [...path.length > 0 && (runnable || allEntries.length === 0) ? [[path.join(" "), schemaForCommand(command, path)]] : [], ...entries.flatMap(([name, subCommand]) => leafSchemasForCommand(subCommand, [...path, commandName(subCommand, name)]))];
28677
28854
  };
28678
28855
  const commandAtPath = (command, path) => {
28679
28856
  let current = command;
28680
28857
  const parts = path[0] === commandName(command, "social") ? path.slice(1) : path;
28681
28858
  const resolved = [];
28682
28859
  for (const part of parts) {
28683
- const next = current.subCommands?.[part];
28684
- if (!next || isHiddenCommand(next)) throw new Error(`Unknown command path: ${path.join(".")}`);
28860
+ const next = childCommandsFor(current)[part];
28861
+ if (!next) throw new Error(`Unknown command path: ${path.join(".")}`);
28685
28862
  current = next;
28686
28863
  resolved.push(commandName(current, part));
28687
28864
  }