@usesocial/cli 0.10.0 → 0.10.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
@@ -334,11 +334,12 @@ const buildRuntimeArgs = (adapter, op) => {
334
334
  };
335
335
  for (const [name, param] of Object.entries(op.config.bodyParams ?? {})) {
336
336
  const argName = bodyParamArgFor(adapter, name, param);
337
+ const valueHint = param.valueHint ?? flagName(argName);
337
338
  args[flagName(argName)] = {
338
339
  type: param.positional ? "positional" : "string",
339
340
  required: param.required === true,
340
341
  description: param.description ?? `${name} body value`,
341
- valueHint: param.valueHint ?? flagName(argName)
342
+ valueHint: param.kind === "array" ? `${valueHint}...` : valueHint
342
343
  };
343
344
  }
344
345
  if (op.config.mediaArg) args[flagName(op.config.mediaArg)] = {
@@ -363,6 +364,7 @@ const buildRuntimeArgs = (adapter, op) => {
363
364
  type: "string",
364
365
  description: "Account selector: @username or profile_id:<id>; overrides config default"
365
366
  };
367
+ for (const [name, def] of Object.entries(adapter.extraArgsFor?.(op) ?? {})) args[name] = def;
366
368
  if (adapter.isCacheable(op.endpoint)) args.header = {
367
369
  type: "string",
368
370
  alias: "H",
@@ -432,7 +434,8 @@ const buildRuntimeInput = (adapter, op, args) => {
432
434
  input.body = args.body;
433
435
  if (op.config.bodyTextArg) input[op.config.bodyTextArg] = args[bodyTextDisplayKeyFor(op) ?? op.config.bodyTextArg];
434
436
  Object.entries(op.config.bodyParams ?? {}).forEach(([name, param], index) => {
435
- input[name] = args[flagName(bodyParamArgFor(adapter, name, param))] ?? (Array.isArray(args._) ? args._[index] : void 0);
437
+ const argName = bodyParamArgFor(adapter, name, param);
438
+ input[name] = param.positional && param.kind === "array" && Array.isArray(args._) && args._.length > 0 ? args._ : args[flagName(argName)] ?? (Array.isArray(args._) ? args._[index] : void 0);
436
439
  });
437
440
  if (op.config.replyToArg) input[op.config.replyToArg] = args[op.config.replyToArg];
438
441
  }
@@ -445,7 +448,10 @@ const checkBodyRequired = (adapter, op, args, bodyTextOptional) => {
445
448
  const expressions = [];
446
449
  const bodyTextArg = op.config.bodyTextArg;
447
450
  if (bodyTextArg && op.config.bodyTextRequired !== false) expressions.push(args[bodyTextDisplayKeyFor(op) ?? bodyTextArg] === void 0);
448
- for (const [name, param] of Object.entries(op.config.bodyParams ?? {})) if (param.required) expressions.push(args[flagName(bodyParamArgFor(adapter, name, param))] === void 0);
451
+ for (const [name, param] of Object.entries(op.config.bodyParams ?? {})) if (param.required) {
452
+ const positionalValuePresent = param.positional && Array.isArray(args._) && args._.length > 0;
453
+ expressions.push(args[flagName(bodyParamArgFor(adapter, name, param))] === void 0 && !positionalValuePresent);
454
+ }
449
455
  if (expressions.length > 0 && typeof args.body !== "string" && expressions.some(Boolean)) throw bodyRequiredPreparseError(adapter, op);
450
456
  };
451
457
  const buildBody = (adapter, deps, op, input, bodyTextOptional) => {
@@ -458,7 +464,8 @@ const buildBody = (adapter, deps, op, input, bodyTextOptional) => {
458
464
  const bodyParamValues = /* @__PURE__ */ new Map();
459
465
  for (const [name, param] of bodyParamEntries) {
460
466
  const value = input[name];
461
- bodyParamValues.set(name, value === void 0 ? param.default : deps.parseQueryString(param.positional ? bodyParamArgFor(adapter, name, param) : `--${bodyParamArgFor(adapter, name, param)}`, value));
467
+ const displayName = param.positional ? bodyParamArgFor(adapter, name, param) : `--${bodyParamArgFor(adapter, name, param)}`;
468
+ bodyParamValues.set(name, value === void 0 ? param.default : param.kind === "array" ? deps.parseResourceIdList(displayName, Array.isArray(value) ? value : [value]) : deps.parseQueryString(displayName, value));
462
469
  }
463
470
  const body = { ...bodyFromJSON ?? {} };
464
471
  for (const [name] of bodyParamEntries) {
@@ -626,6 +633,16 @@ const runRuntimeOperation = async (adapter, op, contract, deps, args, rawArgs =
626
633
  }
627
634
  }
628
635
  for (const param of op.parameters.filter((candidate) => candidate.in === "path")) {
636
+ if (input[param.name] === void 0) {
637
+ const seeded = await adapter.seedPathValue?.({
638
+ op,
639
+ param,
640
+ args,
641
+ deps,
642
+ account
643
+ });
644
+ if (seeded !== void 0) input[param.name] = seeded;
645
+ }
629
646
  const mode = ownMode$1(op, param.name);
630
647
  const display = positionalDisplayKeyFor$1(op, param);
631
648
  let resolution;
@@ -6549,6 +6566,12 @@ const decodePartialSyncCursor = (value) => {
6549
6566
  }
6550
6567
  };
6551
6568
  const encodePartialSyncCursor = (cursor) => `${PARTIAL_SYNC_CURSOR_PREFIX}${JSON.stringify(cursor)}`;
6569
+ const partialCursorMatchesSince = (cursor, since) => {
6570
+ const requestedSince = since ?? null;
6571
+ if (cursor.since === requestedSince) return true;
6572
+ return requestedSince !== null && (cursor.since === null || cursor.since <= requestedSince);
6573
+ };
6574
+ const preservesBroaderPartialOnSince = (cursor, since, stoppedReason) => cursor !== void 0 && cursor.since !== (since ?? null) && stoppedReason === "since";
6552
6575
  const isRateLimitError = (error) => isRecord$9(error) && error.status === 429;
6553
6576
  const retryAfterSecondsFromRateLimitError = (error) => {
6554
6577
  if (!(isRateLimitError(error) && isRecord$9(error))) return;
@@ -6745,7 +6768,7 @@ const walkRequest = async (args) => {
6745
6768
  cursor: state.cursor ?? "",
6746
6769
  checkpoint,
6747
6770
  newestId: state.newestId,
6748
- since: args.since ?? null,
6771
+ since: args.partialCursorSince === void 0 ? args.since ?? null : args.partialCursorSince,
6749
6772
  ...args.parentId === void 0 ? {} : { parentId: args.parentId }
6750
6773
  }),
6751
6774
  objectCount: upserted,
@@ -6825,7 +6848,7 @@ const walkRequest = async (args) => {
6825
6848
  upserted += step.rows.length;
6826
6849
  ids.push(...step.ids);
6827
6850
  state = step.nextState;
6828
- persistPartialCursor();
6851
+ if (!(args.preservePartialCursorOnSince && step.done && step.stoppedReason === "since")) persistPartialCursor();
6829
6852
  await args.onPage?.({
6830
6853
  collectionKey: args.collection.key,
6831
6854
  pagesCompleted: pages,
@@ -6853,10 +6876,11 @@ const singleRequestCheckpoint = (args) => ({
6853
6876
  objectCount: args.result.upserted,
6854
6877
  lastSynced: Date.now()
6855
6878
  });
6856
- const parentIdsFromCache = (deps, collection) => {
6879
+ const parentIdsFromCache = (deps, collection, since) => {
6857
6880
  const table = collection.table ?? collection.key;
6858
6881
  const orderBy = collection.sinceField ? `${collection.sinceField} DESC, id` : "id";
6859
- return deps.cache.query(`SELECT id FROM ${table} ORDER BY ${orderBy}`).map((row) => String(row.id));
6882
+ const sinceFilter = since != null && collection.sinceField ? ` WHERE ${collection.sinceField} >= ${since}` : "";
6883
+ return deps.cache.query(`SELECT id FROM ${table}${sinceFilter} ORDER BY ${orderBy}`).map((row) => String(row.id));
6860
6884
  };
6861
6885
  const runSync = async (deps, opts) => {
6862
6886
  const { collection } = opts;
@@ -6890,13 +6914,14 @@ const runSync = async (deps, opts) => {
6890
6914
  const parentCollection = collectionByKey(collection.parentCollection);
6891
6915
  if (!parentCollection) throw new Error(`Missing parent collection ${collection.parentCollection}`);
6892
6916
  const storedPartialCursor = decodePartialSyncCursor(deps.cache.getCursor(collection.key)?.cursor);
6893
- let activePartialCursor = storedPartialCursor?.since === (opts.since ?? null) ? storedPartialCursor : void 0;
6917
+ let activePartialCursor = storedPartialCursor && partialCursorMatchesSince(storedPartialCursor, opts.since) ? storedPartialCursor : void 0;
6894
6918
  if (activePartialCursor?.phase !== "parent" && activePartialCursor?.phase !== "child") activePartialCursor = void 0;
6919
+ const resumedPartialCursor = activePartialCursor;
6895
6920
  const parentIds = [];
6896
6921
  const parentPersistsCheckpoint = parentCollection.requests.length === 1;
6897
6922
  let parentCheckpoint;
6898
6923
  if (activePartialCursor?.phase === "child") {
6899
- const cachedParentIds = parentIdsFromCache(deps, parentCollection);
6924
+ const cachedParentIds = parentIdsFromCache(deps, parentCollection, opts.since);
6900
6925
  if (activePartialCursor.parentId && cachedParentIds.includes(activePartialCursor.parentId)) parentIds.push(...cachedParentIds);
6901
6926
  else activePartialCursor = void 0;
6902
6927
  }
@@ -6913,6 +6938,8 @@ const runSync = async (deps, opts) => {
6913
6938
  collectIds: true,
6914
6939
  resumeCursor: activePartialCursor?.phase === "parent" && activePartialCursor.requestIndex === requestIndex ? activePartialCursor : void 0,
6915
6940
  allowPartialResume: true,
6941
+ partialCursorSince: activePartialCursor?.since,
6942
+ preservePartialCursorOnSince: activePartialCursor?.since !== (opts.since ?? null),
6916
6943
  partialCursorCollection: collection.key,
6917
6944
  partialCursorPhase: "parent",
6918
6945
  credits,
@@ -6937,7 +6964,7 @@ const runSync = async (deps, opts) => {
6937
6964
  lastSynced: Date.now()
6938
6965
  };
6939
6966
  if (parentCheckpoint) writePendingCursor(parentCheckpoint);
6940
- if (activePartialCursor?.phase === "parent") parentIds.splice(0, parentIds.length, ...parentIdsFromCache(deps, parentCollection));
6967
+ if (activePartialCursor?.phase === "parent") parentIds.splice(0, parentIds.length, ...parentIdsFromCache(deps, parentCollection, opts.since));
6941
6968
  }
6942
6969
  let reachedResumeParent = activePartialCursor?.phase !== "child";
6943
6970
  for (const parentId of parentIds) {
@@ -6956,6 +6983,8 @@ const runSync = async (deps, opts) => {
6956
6983
  useCheckpoint: false,
6957
6984
  resumeCursor: activePartialCursor?.phase === "child" && activePartialCursor.parentId === parentId && activePartialCursor.requestIndex === requestIndex ? activePartialCursor : void 0,
6958
6985
  allowPartialResume: true,
6986
+ partialCursorSince: activePartialCursor?.since,
6987
+ preservePartialCursorOnSince: activePartialCursor?.since !== (opts.since ?? null),
6959
6988
  partialCursorCollection: collection.key,
6960
6989
  partialCursorPhase: "child",
6961
6990
  parentId,
@@ -6971,7 +7000,7 @@ const runSync = async (deps, opts) => {
6971
7000
  if (activePartialCursor?.phase === "child" && activePartialCursor.parentId === parentId) activePartialCursor = void 0;
6972
7001
  }
6973
7002
  }
6974
- pendingCursors.push({
7003
+ if (!preservesBroaderPartialOnSince(resumedPartialCursor, opts.since, stoppedReason)) pendingCursors.push({
6975
7004
  collection: collection.key,
6976
7005
  cursor: null,
6977
7006
  objectCount: upserted,
@@ -6980,7 +7009,7 @@ const runSync = async (deps, opts) => {
6980
7009
  } else {
6981
7010
  const useCheckpoint = collection.requests.length === 1;
6982
7011
  const partialCursor = decodePartialSyncCursor(deps.cache.getCursor(collection.key)?.cursor ?? null);
6983
- const activePartialCursor = partialCursor && partialCursor.since === (opts.since ?? null) && partialCursor.requestIndex < collection.requests.length ? partialCursor : void 0;
7012
+ const activePartialCursor = partialCursor && partialCursorMatchesSince(partialCursor, opts.since) && partialCursor.requestIndex < collection.requests.length ? partialCursor : void 0;
6984
7013
  for (const [requestIndex, request] of collection.requests.entries()) {
6985
7014
  if (activePartialCursor && requestIndex < activePartialCursor.requestIndex) continue;
6986
7015
  const result = await walkRequest({
@@ -6992,6 +7021,8 @@ const runSync = async (deps, opts) => {
6992
7021
  useCheckpoint,
6993
7022
  resumeCursor: activePartialCursor?.requestIndex === requestIndex ? activePartialCursor : void 0,
6994
7023
  allowPartialResume: true,
7024
+ partialCursorSince: activePartialCursor?.since,
7025
+ preservePartialCursorOnSince: activePartialCursor?.since !== (opts.since ?? null),
6995
7026
  credits,
6996
7027
  pageDelayState,
6997
7028
  rateLimit: opts.rateLimit,
@@ -7001,12 +7032,12 @@ const runSync = async (deps, opts) => {
7001
7032
  onProgress: opts.onProgress
7002
7033
  });
7003
7034
  addResult(result);
7004
- if (useCheckpoint) pendingCursors.push(singleRequestCheckpoint({
7035
+ if (!preservesBroaderPartialOnSince(activePartialCursor, opts.since, result.stoppedReason) && useCheckpoint) pendingCursors.push(singleRequestCheckpoint({
7005
7036
  collection,
7006
7037
  result
7007
7038
  }));
7008
7039
  }
7009
- if (!useCheckpoint) pendingCursors.push({
7040
+ if (!(useCheckpoint || preservesBroaderPartialOnSince(activePartialCursor, opts.since, stoppedReason))) pendingCursors.push({
7010
7041
  collection: collection.key,
7011
7042
  cursor: null,
7012
7043
  objectCount: upserted,
@@ -7519,6 +7550,30 @@ const { costBPSForCategory: costBPSForCategory$1 } = createPricing([
7519
7550
  "unitPriceUSD": .015,
7520
7551
  "featureId": "user_interaction_create_request"
7521
7552
  },
7553
+ {
7554
+ "key": "page_analytics_read",
7555
+ "label": "Page Analytics: Read",
7556
+ "description": "Read LinkedIn company Page analytics through the raw LinkedIn passthrough.",
7557
+ "unit": "per_resource",
7558
+ "unitPriceUSD": .02,
7559
+ "featureId": "user_read_resource"
7560
+ },
7561
+ {
7562
+ "key": "page_invite_create",
7563
+ "label": "Page Invite: Create",
7564
+ "description": "Invite LinkedIn users to follow a company Page.",
7565
+ "unit": "per_request",
7566
+ "unitPriceUSD": .015,
7567
+ "featureId": "user_interaction_create_request"
7568
+ },
7569
+ {
7570
+ "key": "proxy_passthrough",
7571
+ "label": "Proxy Passthrough",
7572
+ "description": "Forward a raw LinkedIn passthrough envelope with conservative write-tier pricing.",
7573
+ "unit": "per_request",
7574
+ "unitPriceUSD": .2,
7575
+ "featureId": "content_create_with_url_request"
7576
+ },
7522
7577
  {
7523
7578
  "key": "following_read",
7524
7579
  "label": "Following/Followers: Read",
@@ -10441,6 +10496,54 @@ const LINKEDIN_OPERATIONS = [
10441
10496
  }
10442
10497
  ]
10443
10498
  },
10499
+ {
10500
+ schemaBaseName: "PageVisitors",
10501
+ hasBody: false,
10502
+ config: {
10503
+ command: "visitors",
10504
+ group: "page",
10505
+ root: false,
10506
+ summary: "Read company Page visitor analytics",
10507
+ paramLabels: { companyId: "company" },
10508
+ targetKind: "company"
10509
+ },
10510
+ endpoint: {
10511
+ method: "GET",
10512
+ path: "/page/:companyId/visitors",
10513
+ upstreamMethod: "POST",
10514
+ upstreamPath: "/v2/{account_id}/linkedin/",
10515
+ capability: "read",
10516
+ mutates: false,
10517
+ pagination: { style: "none" },
10518
+ costBPS: 200,
10519
+ billingCategory: "page_analytics_read",
10520
+ kind: "page"
10521
+ },
10522
+ parameters: [
10523
+ {
10524
+ name: "since",
10525
+ in: "query",
10526
+ required: false,
10527
+ kind: "string",
10528
+ description: "Start of the analytics window as an ISO timestamp"
10529
+ },
10530
+ {
10531
+ name: "until",
10532
+ in: "query",
10533
+ required: false,
10534
+ kind: "string",
10535
+ description: "End of the analytics window as an ISO timestamp"
10536
+ },
10537
+ {
10538
+ name: "companyId",
10539
+ in: "path",
10540
+ required: true,
10541
+ kind: "string",
10542
+ valueHint: "company",
10543
+ description: "Company Page selector: company_id:ID, a company URL, or a vanity; supplied by --page or config"
10544
+ }
10545
+ ]
10546
+ },
10444
10547
  {
10445
10548
  schemaBaseName: "PostsComments",
10446
10549
  hasBody: false,
@@ -10883,7 +10986,7 @@ const LINKEDIN_OPERATIONS = [
10883
10986
  summary: "List a user's LinkedIn connections",
10884
10987
  itemUrlTemplate: "https://www.linkedin.com/in/{id}",
10885
10988
  paramLabels: { user_id: "target" },
10886
- positionalQueryParams: ["user_id"],
10989
+ optionalPositionalQueryParams: ["user_id"],
10887
10990
  outputGuardMessage: "Unexpected LinkedIn connections response. Expected a relations list.",
10888
10991
  resolveResourceParams: ["user_id"],
10889
10992
  targetKind: "profile"
@@ -10923,10 +11026,10 @@ const LINKEDIN_OPERATIONS = [
10923
11026
  {
10924
11027
  name: "user_id",
10925
11028
  in: "query",
10926
- required: true,
11029
+ required: false,
10927
11030
  kind: "string",
10928
11031
  valueHint: "target",
10929
- description: "LinkedIn profile target: @public-identifier, profile_id:<id>, a LinkedIn profile URL, or a profile URN. Required for live reads; use `social linkedin sync connections` plus `social linkedin sql` for your own graph."
11032
+ description: "Optional profile target: @public-identifier, profile_id:<id>, a LinkedIn profile URL, or a profile URN. Omit for account-level connections"
10930
11033
  },
10931
11034
  {
10932
11035
  name: "filter",
@@ -11052,6 +11155,44 @@ const LINKEDIN_OPERATIONS = [
11052
11155
  description: "Conversation target: chat_id:<id> or a LinkedIn messaging thread URL"
11053
11156
  }]
11054
11157
  },
11158
+ {
11159
+ schemaBaseName: "PageInvite",
11160
+ hasBody: true,
11161
+ config: {
11162
+ command: "invite",
11163
+ group: "page",
11164
+ root: false,
11165
+ summary: "Invite users to follow a company Page",
11166
+ bodyParams: { invitees: {
11167
+ kind: "array",
11168
+ positional: true,
11169
+ required: true,
11170
+ valueHint: "user",
11171
+ description: "Users to invite: @username, profile_id:<id>, profile URL, or profile URN"
11172
+ } },
11173
+ paramLabels: { companyId: "company" },
11174
+ targetKind: "company"
11175
+ },
11176
+ endpoint: {
11177
+ method: "POST",
11178
+ path: "/page/:companyId/invite",
11179
+ upstreamPath: "/v2/{account_id}/linkedin/",
11180
+ capability: "write",
11181
+ mutates: true,
11182
+ pagination: { style: "none" },
11183
+ costBPS: 150,
11184
+ billingCategory: "page_invite_create",
11185
+ kind: "page"
11186
+ },
11187
+ parameters: [{
11188
+ name: "companyId",
11189
+ in: "path",
11190
+ required: true,
11191
+ kind: "string",
11192
+ valueHint: "company",
11193
+ description: "Company Page selector: company_id:ID, a company URL, or a vanity; supplied by --page or config"
11194
+ }]
11195
+ },
11055
11196
  {
11056
11197
  schemaBaseName: "PostsPost",
11057
11198
  hasBody: true,
@@ -11164,6 +11305,29 @@ const LINKEDIN_OPERATIONS = [
11164
11305
  },
11165
11306
  parameters: []
11166
11307
  },
11308
+ {
11309
+ schemaBaseName: "LinkedinProxy",
11310
+ hasBody: true,
11311
+ config: {
11312
+ command: "proxy",
11313
+ group: "linkedin",
11314
+ root: true,
11315
+ summary: "Forward a raw request to LinkedIn (advanced escape hatch)",
11316
+ bodyTextArg: "body"
11317
+ },
11318
+ endpoint: {
11319
+ method: "POST",
11320
+ path: "/proxy",
11321
+ upstreamPath: "/v2/{account_id}/linkedin/",
11322
+ capability: "write",
11323
+ mutates: true,
11324
+ pagination: { style: "none" },
11325
+ costBPS: 2e3,
11326
+ billingCategory: "proxy_passthrough",
11327
+ kind: "proxy"
11328
+ },
11329
+ parameters: []
11330
+ },
11167
11331
  {
11168
11332
  schemaBaseName: "RequestsSend",
11169
11333
  hasBody: true,
@@ -11420,6 +11584,12 @@ const CompaniesJobsOutput = object({
11420
11584
  total_count: number().optional(),
11421
11585
  next_cursor: string().optional()
11422
11586
  }).passthrough();
11587
+ const PageVisitorsInput = object({
11588
+ since: string().optional(),
11589
+ until: string().optional(),
11590
+ companyId: string().optional()
11591
+ });
11592
+ const PageVisitorsOutput = object({}).passthrough();
11423
11593
  const PostsCommentsInput = object({
11424
11594
  offset: union([string(), number()]).optional(),
11425
11595
  limit: union([string(), number()]).optional(),
@@ -11500,7 +11670,7 @@ const UserPostsOutput = object({
11500
11670
  const UserConnectionsInput = object({
11501
11671
  limit: union([string(), number()]).optional(),
11502
11672
  cursor: string().optional(),
11503
- user_id: string(),
11673
+ user_id: string().optional(),
11504
11674
  filter: string().optional()
11505
11675
  });
11506
11676
  const UserConnectionsOutput = object({
@@ -11549,6 +11719,16 @@ const MessagesMessageOutput = object({
11549
11719
  unknown()
11550
11720
  ])
11551
11721
  }).passthrough();
11722
+ const PageInviteInput = object({
11723
+ companyId: string().optional(),
11724
+ body: string().optional(),
11725
+ invitees: union([array(string()), string()]).optional()
11726
+ });
11727
+ const PageInviteContractInput = PageInviteInput.extend({
11728
+ body: object({ invitees: array(string()) }).passthrough().optional(),
11729
+ invitees: union([array(string()), string()]).optional()
11730
+ });
11731
+ const PageInviteOutput = object({}).passthrough();
11552
11732
  const PostsPostInput = object({
11553
11733
  body: string().optional(),
11554
11734
  text: string().optional(),
@@ -11631,6 +11811,9 @@ const PostsReactContractInput = PostsReactInput.extend({
11631
11811
  reaction_type: string().optional()
11632
11812
  });
11633
11813
  const PostsReactOutput = object({ object: _enum(["PostReactionAdded"]) }).passthrough();
11814
+ const LinkedinProxyInput = object({ body: string().optional() });
11815
+ const LinkedinProxyContractInput = LinkedinProxyInput.extend({ body: object({}).passthrough().optional() });
11816
+ const LinkedinProxyOutput = object({}).passthrough();
11634
11817
  const RequestsSendInput = object({
11635
11818
  id: string(),
11636
11819
  body: string().optional(),
@@ -11645,6 +11828,8 @@ const schemas$1 = {
11645
11828
  CompaniesCompanyOutput,
11646
11829
  CompaniesJobsInput,
11647
11830
  CompaniesJobsOutput,
11831
+ PageVisitorsInput,
11832
+ PageVisitorsOutput,
11648
11833
  PostsCommentsInput,
11649
11834
  PostsCommentsOutput,
11650
11835
  PostsReactionsInput,
@@ -11670,6 +11855,9 @@ const schemas$1 = {
11670
11855
  MessagesMessageInput,
11671
11856
  MessagesMessageContractInput,
11672
11857
  MessagesMessageOutput,
11858
+ PageInviteInput,
11859
+ PageInviteContractInput,
11860
+ PageInviteOutput,
11673
11861
  PostsPostInput,
11674
11862
  PostsPostContractInput,
11675
11863
  PostsPostOutput,
@@ -11679,6 +11867,9 @@ const schemas$1 = {
11679
11867
  PostsReactInput,
11680
11868
  PostsReactContractInput,
11681
11869
  PostsReactOutput,
11870
+ LinkedinProxyInput,
11871
+ LinkedinProxyContractInput,
11872
+ LinkedinProxyOutput,
11682
11873
  RequestsSendInput,
11683
11874
  RequestsSendContractInput: RequestsSendInput.extend({
11684
11875
  body: object({
@@ -11792,6 +11983,12 @@ const targetKindsFor = (op) => {
11792
11983
  if (kinds === void 0) throw new Error(`Missing targetKind for ${commandPathFor(op)}.`);
11793
11984
  return Array.isArray(kinds) ? kinds : [kinds];
11794
11985
  };
11986
+ const isSeededPageCompanyParam = (op, param) => op.config.group === "page" && param.in === "path" && param.name === "companyId";
11987
+ const pageParametersForRuntimeInput = (op) => op.config.group === "page" ? op.parameters.filter((param) => !isSeededPageCompanyParam(op, param)) : op.parameters;
11988
+ const pageSelectorForTargetResolution = (page) => {
11989
+ if (NumericCompanyId.safeParse(page).success || !(page.startsWith("company_id:") || page.startsWith("http") || page.startsWith("urn:"))) return `company_id:${page}`;
11990
+ return page;
11991
+ };
11795
11992
  const positionalDisplayKeyFor = (op, param) => op.config.paramLabels?.[param.name] ?? flagName(param.name);
11796
11993
  const idempotencyFor$1 = (op) => {
11797
11994
  if (op.endpoint.capability === "read") return {
@@ -11841,7 +12038,7 @@ const exampleCommandFor$1 = (op, root) => {
11841
12038
  op.config.command
11842
12039
  ];
11843
12040
  for (const param of op.parameters) {
11844
- if (!(param.in === "path" || positionalQuery.has(param.name)) || op.config.ownAccountPathParams?.[param.name] === "optional") continue;
12041
+ if (!(param.in === "path" || positionalQuery.has(param.name)) || op.config.ownAccountPathParams?.[param.name] === "optional" || isSeededPageCompanyParam(op, param)) continue;
11845
12042
  const hint = `<${positionalDisplayKeyFor(op, param)}>`;
11846
12043
  parts.push(param.in === "path" || param.kind !== "array" ? hint : `${hint}...`);
11847
12044
  }
@@ -11935,10 +12132,21 @@ const linkedinRuntimeAdapter = {
11935
12132
  includeIdField: true,
11936
12133
  maximumItemsHintFor: maximumItemsHintFor$1,
11937
12134
  queryArrayMode: (op, param) => param.kind === "array" || op.schemaBaseName === "UserProfile" && param.name === "with_sections" ? "repeat" : "set",
12135
+ parametersForArgs: pageParametersForRuntimeInput,
12136
+ parametersForInput: pageParametersForRuntimeInput,
11938
12137
  setUnexposedFieldPresets: true,
11939
12138
  signaturePartFor: signaturePartFor$1,
11940
12139
  stdinBodyTextRequired: (op) => op.config.bodyTextArg !== void 0 && op.config.bodyTextRequired !== false,
11941
12140
  targetKinds: targetKindsFor,
12141
+ seedPathValue: async ({ op, param, args, deps }) => {
12142
+ if (op.config.group !== "page" || param.name !== "companyId") return;
12143
+ const page = typeof args.page === "string" ? args.page : void 0;
12144
+ return pageSelectorForTargetResolution(await deps.resolveLinkedinPage({ page }));
12145
+ },
12146
+ extraArgsFor: (op) => op.config.group === "page" ? { page: {
12147
+ type: "string",
12148
+ description: "Company Page selector: company_id:<id>, a company URL, or a vanity; overrides the configured default Page"
12149
+ } } : void 0,
11942
12150
  useGETMaxUsageUnitsEstimate: true,
11943
12151
  transformPathResolution: async ({ args, deps, op, param, rawArgs, resolution, resolveSelectedAccount }) => {
11944
12152
  if ((op.schemaBaseName === "PostsComments" || op.schemaBaseName === "PostsReactions") && param.name === "post_id") {
@@ -11983,6 +12191,26 @@ const linkedinRuntimeAdapter = {
11983
12191
  }]
11984
12192
  };
11985
12193
  }
12194
+ if (op.config.group === "page" && param.name === "companyId" && !NumericCompanyId.safeParse(resolution.id).success) {
12195
+ const companyAccount = await resolveSelectedAccount();
12196
+ const company = await deps.api.get(`linkedin/companies/${encodeURIComponent(resolution.id)}`, { headers: {
12197
+ ...await deps.commandHeaders({
12198
+ headers: args.header,
12199
+ rawArgs
12200
+ }),
12201
+ ...companyAccount.selector === void 0 ? {} : { "x-social-account-id": companyAccount.selector }
12202
+ } }).json();
12203
+ const companyId = NumericCompanyId.safeParse(companyProfileIdFrom(company));
12204
+ if (!companyId.success) throw new Error(`Could not resolve LinkedIn company ID for ${resolution.id}.`);
12205
+ return {
12206
+ pathValue: companyId.data,
12207
+ records: [{
12208
+ ...resolution.record,
12209
+ id: companyId.data,
12210
+ source: "lookup"
12211
+ }]
12212
+ };
12213
+ }
11986
12214
  },
11987
12215
  afterQueryParams: ({ op, params, pathResolutions }) => {
11988
12216
  if (op.schemaBaseName === "UserPosts" && pathResolutions.identifier?.kind === "company") params.set("is_company", "true");
@@ -12036,6 +12264,20 @@ const linkedinRuntimeAdapter = {
12036
12264
  });
12037
12265
  input.post_as = companyId.data;
12038
12266
  }
12267
+ if (op.schemaBaseName === "PageInvite" && input.invitees !== void 0) {
12268
+ const invitees = Array.isArray(input.invitees) ? input.invitees : [input.invitees];
12269
+ const profileIds = [];
12270
+ for (const invitee of invitees) {
12271
+ const resolution = await deps.resolveTarget("invitee", invitee, {
12272
+ platform: "linkedin",
12273
+ account,
12274
+ expect: ["profile"]
12275
+ });
12276
+ resolved.push(resolution.record);
12277
+ profileIds.push(resolution.id);
12278
+ }
12279
+ input.invitees = profileIds;
12280
+ }
12039
12281
  },
12040
12282
  transformOutput: ({ body, data, op }) => {
12041
12283
  const outputData = dataWithAuditableWriteTarget(op, data, body);
@@ -13567,6 +13809,7 @@ createLinkedinCommands({
13567
13809
  printResult: unconfigured$1,
13568
13810
  resolveAccount: unconfigured$1,
13569
13811
  resolveAccountId: unconfigured$1,
13812
+ resolveLinkedinPage: unconfigured$1,
13570
13813
  resolveOwnLinkedinAccount: unconfigured$1
13571
13814
  });
13572
13815
  //#endregion
@@ -21156,7 +21399,7 @@ function createEnv(opts) {
21156
21399
  }
21157
21400
  //#endregion
21158
21401
  //#region package.json
21159
- var version$1 = "0.10.0";
21402
+ var version$1 = "0.10.1";
21160
21403
  //#endregion
21161
21404
  //#region src/lib/env.ts
21162
21405
  const URLWithTrailingSlash = url().transform(ensureTrailingSlash);
@@ -21570,8 +21813,17 @@ const authWhoamiOutput = async (client, apiURL = env.SOCIAL_API_URL) => {
21570
21813
  }
21571
21814
  };
21572
21815
  const MAX_CACHE_TTL_SECONDS = 10080 * 60;
21573
- const CLIConfig = object({ cache: object({ cacheTTLSeconds: number().int().min(0).max(MAX_CACHE_TTL_SECONDS).default(900) }).default({ cacheTTLSeconds: 900 }) });
21574
- const defaultCLIConfig = () => ({ cache: { cacheTTLSeconds: 900 } });
21816
+ const CLIConfig = object({
21817
+ cache: object({ cacheTTLSeconds: number().int().min(0).max(MAX_CACHE_TTL_SECONDS).default(900) }).default({ cacheTTLSeconds: 900 }),
21818
+ defaults: object({
21819
+ account: string().optional(),
21820
+ linkedinPage: string().optional()
21821
+ }).default({})
21822
+ });
21823
+ const defaultCLIConfig = () => ({
21824
+ cache: { cacheTTLSeconds: 900 },
21825
+ defaults: {}
21826
+ });
21575
21827
  const configPath = () => join(process.env.HOME ?? homedir(), ".social", "config.json");
21576
21828
  const parseCLIConfig = (serialized) => CLIConfig.parse(JSON.parse(serialized));
21577
21829
  const readCLIConfig = async () => {
@@ -21597,6 +21849,30 @@ const setCacheTTLSeconds = async (cacheTTLSeconds) => {
21597
21849
  await writeCLIConfig(next);
21598
21850
  return next;
21599
21851
  };
21852
+ const setDefaultAccount = async (selector) => {
21853
+ const config = await readCLIConfig();
21854
+ const next = {
21855
+ ...config,
21856
+ defaults: {
21857
+ ...config.defaults,
21858
+ account: selector
21859
+ }
21860
+ };
21861
+ await writeCLIConfig(next);
21862
+ return next;
21863
+ };
21864
+ const setDefaultLinkedinPage = async (companyId) => {
21865
+ const config = await readCLIConfig();
21866
+ const next = {
21867
+ ...config,
21868
+ defaults: {
21869
+ ...config.defaults,
21870
+ linkedinPage: companyId
21871
+ }
21872
+ };
21873
+ await writeCLIConfig(next);
21874
+ return next;
21875
+ };
21600
21876
  const cacheControlHeaderFromConfig = async () => `max-age=${(await readCLIConfig()).cache.cacheTTLSeconds}`;
21601
21877
  //#endregion
21602
21878
  //#region src/lib/output.ts
@@ -22106,24 +22382,70 @@ const commandMeta = (meta) => {
22106
22382
  };
22107
22383
  };
22108
22384
  const CacheStateOutput = object({ cacheTTLSeconds: number().int().nonnegative() });
22385
+ const AccountDefaultOutput = object({ account: string().nullable() });
22386
+ const PageDefaultOutput = object({ linkedinPage: string().nullable() });
22109
22387
  const cacheStateFrom = (config) => ({ cacheTTLSeconds: config.cache.cacheTTLSeconds });
22110
22388
  const printCacheState = (config) => {
22111
22389
  printData(cacheStateFrom(config));
22112
22390
  };
22391
+ const printDefaultAccount = (config) => {
22392
+ printData({ account: config.defaults.account ?? null });
22393
+ };
22394
+ const printDefaultLinkedinPage = (config) => {
22395
+ printData({ linkedinPage: config.defaults.linkedinPage ?? null });
22396
+ };
22397
+ const cacheCommand = defineCommand({
22398
+ meta: {
22399
+ name: "cache",
22400
+ description: "Read or configure proxy cache defaults."
22401
+ },
22402
+ subCommands: { ttl: defineCommand({
22403
+ meta: commandMeta({
22404
+ name: "ttl",
22405
+ description: "Read or set the default cache TTL in seconds.",
22406
+ contract: {
22407
+ capability: "none",
22408
+ auth: {
22409
+ local: true,
22410
+ required: false
22411
+ },
22412
+ mutates: true,
22413
+ outputSchema: CacheStateOutput,
22414
+ idempotency: "idempotent",
22415
+ responseShaping: { formats: ["json"] },
22416
+ hazards: [{
22417
+ code: "local_config_write",
22418
+ message: "Writes local CLI configuration when ttl_seconds is provided."
22419
+ }]
22420
+ }
22421
+ }),
22422
+ args: { ttl_seconds: {
22423
+ type: "positional",
22424
+ required: false,
22425
+ description: "Cache TTL in seconds."
22426
+ } },
22427
+ run: async ({ args }) => {
22428
+ if (args.ttl_seconds === void 0) {
22429
+ printCacheState(await readCLIConfig());
22430
+ return;
22431
+ }
22432
+ printCacheState(await setCacheTTLSeconds(parseIntegerString("--ttl-seconds", args.ttl_seconds, {
22433
+ min: 0,
22434
+ max: MAX_CACHE_TTL_SECONDS
22435
+ })));
22436
+ }
22437
+ }) }
22438
+ });
22113
22439
  const configCommand = defineCommand({
22114
22440
  meta: {
22115
22441
  name: "config",
22116
22442
  description: "Read or configure local social CLI settings."
22117
22443
  },
22118
- subCommands: { cache: defineCommand({
22119
- meta: {
22120
- name: "cache",
22121
- description: "Read or configure proxy cache defaults."
22122
- },
22123
- subCommands: { ttl: defineCommand({
22444
+ subCommands: {
22445
+ account: defineCommand({
22124
22446
  meta: commandMeta({
22125
- name: "ttl",
22126
- description: "Read or set the default cache TTL in seconds.",
22447
+ name: "account",
22448
+ description: "Read or set the default connected account selector.",
22127
22449
  contract: {
22128
22450
  capability: "none",
22129
22451
  auth: {
@@ -22131,32 +22453,63 @@ const configCommand = defineCommand({
22131
22453
  required: false
22132
22454
  },
22133
22455
  mutates: true,
22134
- outputSchema: CacheStateOutput,
22456
+ outputSchema: AccountDefaultOutput,
22135
22457
  idempotency: "idempotent",
22136
22458
  responseShaping: { formats: ["json"] },
22137
22459
  hazards: [{
22138
22460
  code: "local_config_write",
22139
- message: "Writes local CLI configuration when ttl_seconds is provided."
22461
+ message: "Writes local CLI configuration when selector is provided."
22140
22462
  }]
22141
22463
  }
22142
22464
  }),
22143
- args: { ttl_seconds: {
22465
+ args: { selector: {
22144
22466
  type: "positional",
22145
22467
  required: false,
22146
- description: "Cache TTL in seconds."
22468
+ description: "Default account selector."
22147
22469
  } },
22148
22470
  run: async ({ args }) => {
22149
- if (args.ttl_seconds === void 0) {
22150
- printCacheState(await readCLIConfig());
22471
+ if (args.selector === void 0) {
22472
+ printDefaultAccount(await readCLIConfig());
22151
22473
  return;
22152
22474
  }
22153
- printCacheState(await setCacheTTLSeconds(parseIntegerString("--ttl-seconds", args.ttl_seconds, {
22154
- min: 0,
22155
- max: MAX_CACHE_TTL_SECONDS
22156
- })));
22475
+ printDefaultAccount(await setDefaultAccount(String(args.selector)));
22157
22476
  }
22158
- }) }
22159
- }) }
22477
+ }),
22478
+ cache: cacheCommand,
22479
+ page: defineCommand({
22480
+ meta: commandMeta({
22481
+ name: "page",
22482
+ description: "Read or set the default LinkedIn company Page selector.",
22483
+ contract: {
22484
+ capability: "none",
22485
+ auth: {
22486
+ local: true,
22487
+ required: false
22488
+ },
22489
+ mutates: true,
22490
+ outputSchema: PageDefaultOutput,
22491
+ idempotency: "idempotent",
22492
+ responseShaping: { formats: ["json"] },
22493
+ hazards: [{
22494
+ code: "local_config_write",
22495
+ message: "Writes local CLI configuration when company_id is provided."
22496
+ }]
22497
+ }
22498
+ }),
22499
+ args: { company_id: {
22500
+ type: "positional",
22501
+ required: false,
22502
+ description: "Default LinkedIn Page selector."
22503
+ } },
22504
+ run: async ({ args }) => {
22505
+ if (args.company_id === void 0) {
22506
+ printDefaultLinkedinPage(await readCLIConfig());
22507
+ return;
22508
+ }
22509
+ printDefaultLinkedinPage(await setDefaultLinkedinPage(String(args.company_id)));
22510
+ }
22511
+ })
22512
+ }
22160
22513
  });
22161
22514
  //#endregion
22162
22515
  //#region src/billing/index.ts
@@ -34192,17 +34545,20 @@ const createCLIDeps = () => {
34192
34545
  }
34193
34546
  };
34194
34547
  const resolveAccount = async ({ account, platform }) => {
34195
- if (account) resolveAccountId({ account });
34548
+ const configDefault = (await readCLIConfig()).defaults.account;
34549
+ const selectorToTry = account ?? configDefault;
34550
+ if (selectorToTry) resolveAccountId({ account: selectorToTry });
34196
34551
  const accounts = await client.accounts.list({
34197
34552
  platform,
34198
34553
  includeDisconnected: false
34199
34554
  });
34200
- const selected = account ? accounts.find((candidate) => accountMatchesIdentifier(candidate, account)) : accounts[0];
34201
- if (account && !selected) throw new NotFoundError("account_not_found");
34555
+ const matched = selectorToTry ? accounts.find((candidate) => accountMatchesIdentifier(candidate, selectorToTry)) : void 0;
34556
+ if (account && !matched) throw new NotFoundError("account_not_found");
34557
+ const selected = matched ?? accounts[0];
34202
34558
  return {
34203
34559
  platform,
34204
- username: selected?.username ?? (account?.startsWith("@") ? account.slice(1) : account ?? "default"),
34205
- selector: selected ? accountSelectorFor(selected) : account
34560
+ username: selected?.username ?? (selectorToTry?.startsWith("@") ? selectorToTry.slice(1) : selectorToTry ?? "default"),
34561
+ selector: selected ? accountSelectorFor(selected) : selectorToTry
34206
34562
  };
34207
34563
  };
34208
34564
  const lookupXHandle = async (input, account) => {
@@ -34303,13 +34659,23 @@ const createCLIDeps = () => {
34303
34659
  printResult: printResultWithUsage,
34304
34660
  resolveAccount,
34305
34661
  resolveAccountId: async (args) => resolveAccountId(args),
34662
+ resolveLinkedinPage: async ({ page }) => {
34663
+ const selectedPage = page ?? (await readCLIConfig()).defaults.linkedinPage;
34664
+ if (!selectedPage) throw new UsageError("No Page selected — pass --page or run `social config page <id>`");
34665
+ return selectedPage;
34666
+ },
34306
34667
  resolveOwnXAccount: async ({ account }) => {
34668
+ const configDefault = (await readCLIConfig()).defaults.account;
34669
+ const selectorToTry = account ?? configDefault;
34670
+ if (selectorToTry) resolveAccountId({ account: selectorToTry });
34307
34671
  const accounts = await client.accounts.list({
34308
34672
  platform: "x",
34309
34673
  includeDisconnected: false
34310
34674
  });
34311
- const selected = account ? accounts.find((candidate) => accountMatchesIdentifier(candidate, account)) : accounts[0];
34312
- if (!selected) throw account ? new NotFoundError("x_account_not_found") : /* @__PURE__ */ new Error("x_account_not_connected");
34675
+ const matched = selectorToTry ? accounts.find((candidate) => accountMatchesIdentifier(candidate, selectorToTry)) : void 0;
34676
+ if (account && !matched) throw new NotFoundError("x_account_not_found");
34677
+ const selected = matched ?? accounts[0];
34678
+ if (!selected) throw new Error("x_account_not_connected");
34313
34679
  return {
34314
34680
  account: {
34315
34681
  platform: "x",
@@ -34321,14 +34687,18 @@ const createCLIDeps = () => {
34321
34687
  };
34322
34688
  },
34323
34689
  resolveOwnLinkedinAccount: async ({ account }) => {
34324
- if (account) resolveAccountId({ account });
34690
+ const configDefault = (await readCLIConfig()).defaults.account;
34691
+ const selectorToTry = account ?? configDefault;
34692
+ if (selectorToTry) resolveAccountId({ account: selectorToTry });
34325
34693
  const accounts = await client.accounts.list({
34326
34694
  platform: "linkedin",
34327
34695
  includeDisconnected: false
34328
34696
  });
34329
- const selected = account ? accounts.find((candidate) => accountMatchesIdentifier(candidate, account)) : accounts[0];
34330
- if (!selected) throw account ? new NotFoundError("linkedin_account_not_found") : /* @__PURE__ */ new Error("linkedin_account_not_connected");
34331
- const profile = await lookupLinkedinProfile("me", account, {
34697
+ const matched = selectorToTry ? accounts.find((candidate) => accountMatchesIdentifier(candidate, selectorToTry)) : void 0;
34698
+ if (account && !matched) throw new NotFoundError("linkedin_account_not_found");
34699
+ const selected = matched ?? accounts[0];
34700
+ if (!selected) throw new Error("linkedin_account_not_connected");
34701
+ const profile = await lookupLinkedinProfile("me", selectorToTry, {
34332
34702
  platform: "linkedin",
34333
34703
  username: selected.username,
34334
34704
  selector: accountSelectorFor(selected)