@xpoz/xpoz 0.6.13 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -301,7 +301,7 @@ function coerce(value) {
301
301
  }
302
302
 
303
303
  // src/version.ts
304
- var VERSION = "0.6.13";
304
+ var VERSION = "0.8.0";
305
305
 
306
306
  // src/mcp/transport.ts
307
307
  var USER_AGENT = `xpoz-ts-sdk/${VERSION}`;
@@ -454,6 +454,11 @@ var DEFAULT_TIMEOUT_MS = 3e5;
454
454
  var DEFAULT_API_URL = "https://api.xpoz.ai";
455
455
  var ENV_API_URL = "XPOZ_API_URL";
456
456
  var INSTAGRAM_BASE = "/api/data/instagram";
457
+ var TWITTER_BASE = "/api/data/twitter";
458
+ var INSTAGRAM_ROUTES = {
459
+ user: (identifier) => `${INSTAGRAM_BASE}/users/${encodeURIComponent(identifier)}`,
460
+ postsByIds: `${INSTAGRAM_BASE}/posts/ids`
461
+ };
457
462
  var INSTAGRAM_LIVE_ROUTES = {
458
463
  posts: `${INSTAGRAM_BASE}/posts/live`,
459
464
  userPosts: (identifier) => `${INSTAGRAM_BASE}/posts/users/${encodeURIComponent(identifier)}/live`,
@@ -464,6 +469,20 @@ var INSTAGRAM_LIVE_ROUTES = {
464
469
  user: (identifier) => `${INSTAGRAM_BASE}/users/${encodeURIComponent(identifier)}/live`,
465
470
  userConnections: (identifier) => `${INSTAGRAM_BASE}/users/${encodeURIComponent(identifier)}/connections/live`
466
471
  };
472
+ var TWITTER_ROUTES = {
473
+ posts: `${TWITTER_BASE}/posts`
474
+ };
475
+ var TWITTER_LIVE_ROUTES = {
476
+ posts: `${TWITTER_BASE}/posts/live`,
477
+ userPosts: (username) => `${TWITTER_BASE}/posts/users/${encodeURIComponent(username)}/live`,
478
+ post: (postId) => `${TWITTER_BASE}/posts/${encodeURIComponent(postId)}/live`,
479
+ postComments: (postId) => `${TWITTER_BASE}/posts/${encodeURIComponent(postId)}/comments/live`,
480
+ postQuotes: (postId) => `${TWITTER_BASE}/posts/${encodeURIComponent(postId)}/quotes/live`,
481
+ postInteractingUsers: (postId) => `${TWITTER_BASE}/posts/${encodeURIComponent(postId)}/interacting-users/live`,
482
+ users: `${TWITTER_BASE}/users/live`,
483
+ user: (username) => `${TWITTER_BASE}/users/${encodeURIComponent(username)}/live`,
484
+ userConnections: (username) => `${TWITTER_BASE}/users/${encodeURIComponent(username)}/connections/live`
485
+ };
467
486
  var REST_TIMEOUT_MS = 12e4;
468
487
 
469
488
  // src/rest/transport.ts
@@ -576,8 +595,16 @@ var CursorResult = class {
576
595
  }
577
596
  };
578
597
 
579
- // src/namespaces/instagramLive.ts
580
- var STRING_ID_FIELDS = ["id", "userId", "user_id", "postId", "post_id"];
598
+ // src/namespaces/liveBase.ts
599
+ var STRING_ID_FIELDS = [
600
+ "id",
601
+ "userId",
602
+ "user_id",
603
+ "postId",
604
+ "post_id",
605
+ "authorId",
606
+ "author_id"
607
+ ];
581
608
  function coerceStringIds(item) {
582
609
  const record = item;
583
610
  for (const field of STRING_ID_FIELDS) {
@@ -590,7 +617,7 @@ function coerceStringIds(item) {
590
617
  function csvFields(fields) {
591
618
  return fields && fields.length > 0 ? fields.join(",") : void 0;
592
619
  }
593
- var InstagramLiveNamespace = class {
620
+ var LiveNamespace = class {
594
621
  transport;
595
622
  constructor(transport) {
596
623
  this.transport = transport;
@@ -608,6 +635,10 @@ var InstagramLiveNamespace = class {
608
635
  const page = await this.page(path, params);
609
636
  return page.data[0] ?? null;
610
637
  }
638
+ };
639
+
640
+ // src/namespaces/instagramLive.ts
641
+ var InstagramLiveNamespace = class extends LiveNamespace {
611
642
  async searchPosts(query, options = {}) {
612
643
  return this.page(INSTAGRAM_LIVE_ROUTES.posts, {
613
644
  q: query,
@@ -660,6 +691,73 @@ var InstagramLiveNamespace = class {
660
691
  }
661
692
  };
662
693
 
694
+ // src/namespaces/twitterLive.ts
695
+ var TwitterLiveNamespace = class extends LiveNamespace {
696
+ async searchPosts(query, options = {}) {
697
+ return this.page(TWITTER_LIVE_ROUTES.posts, {
698
+ q: query,
699
+ since: options.since,
700
+ until: options.until,
701
+ lang: options.lang,
702
+ countryCode: options.countryCode,
703
+ sortBy: options.sortBy,
704
+ fields: csvFields(options.fields),
705
+ cursor: options.cursor
706
+ });
707
+ }
708
+ async getPostsByUser(username, options = {}) {
709
+ return this.page(TWITTER_LIVE_ROUTES.userPosts(username), {
710
+ since: options.since,
711
+ until: options.until,
712
+ fields: csvFields(options.fields),
713
+ cursor: options.cursor
714
+ });
715
+ }
716
+ async getPost(postId, options = {}) {
717
+ return this.single(TWITTER_LIVE_ROUTES.post(postId), {
718
+ fields: csvFields(options.fields)
719
+ });
720
+ }
721
+ async getComments(postId, options = {}) {
722
+ return this.page(TWITTER_LIVE_ROUTES.postComments(postId), {
723
+ fields: csvFields(options.fields),
724
+ cursor: options.cursor
725
+ });
726
+ }
727
+ async getQuotes(postId, options = {}) {
728
+ return this.page(TWITTER_LIVE_ROUTES.postQuotes(postId), {
729
+ fields: csvFields(options.fields),
730
+ cursor: options.cursor
731
+ });
732
+ }
733
+ async getPostInteractingUsers(postId, interactionType, options = {}) {
734
+ return this.page(TWITTER_LIVE_ROUTES.postInteractingUsers(postId), {
735
+ interactionType,
736
+ fields: csvFields(options.fields),
737
+ cursor: options.cursor
738
+ });
739
+ }
740
+ async searchUsers(query, options = {}) {
741
+ return this.page(TWITTER_LIVE_ROUTES.users, {
742
+ q: query,
743
+ fields: csvFields(options.fields),
744
+ cursor: options.cursor
745
+ });
746
+ }
747
+ async getUser(username, options = {}) {
748
+ return this.single(TWITTER_LIVE_ROUTES.user(username), {
749
+ fields: csvFields(options.fields)
750
+ });
751
+ }
752
+ async getUserConnections(username, connectionType, options = {}) {
753
+ return this.page(TWITTER_LIVE_ROUTES.userConnections(username), {
754
+ connectionType,
755
+ fields: csvFields(options.fields),
756
+ cursor: options.cursor
757
+ });
758
+ }
759
+ };
760
+
663
761
  // src/mcp/polling.ts
664
762
  async function waitForResult(callTool, operationId, timeoutMs = DEFAULT_TIMEOUT_MS) {
665
763
  const start = Date.now();
@@ -821,28 +919,36 @@ var BaseNamespace = class {
821
919
  }
822
920
  };
823
921
 
922
+ // src/concurrency.ts
923
+ var DEFAULT_CONCURRENCY = 10;
924
+ async function parallelMap(items, fn, concurrency = DEFAULT_CONCURRENCY) {
925
+ const results = new Array(items.length);
926
+ let nextIndex = 0;
927
+ async function worker() {
928
+ while (nextIndex < items.length) {
929
+ const index = nextIndex++;
930
+ results[index] = await fn(items[index]);
931
+ }
932
+ }
933
+ const workers = Array.from(
934
+ { length: Math.min(concurrency, items.length) },
935
+ () => worker()
936
+ );
937
+ await Promise.all(workers);
938
+ return results;
939
+ }
940
+
824
941
  // src/config/tools.ts
825
- var GET_TWITTER_POSTS_BY_IDS = "getTwitterPostsByIds";
826
942
  var GET_TWITTER_POSTS_BY_AUTHOR = "getTwitterPostsByAuthor";
827
943
  var SEARCH_TWITTER_POSTS = "getTwitterPostsByKeywords";
828
944
  var GET_TWITTER_RETWEETS = "getTwitterPostRetweets";
829
- var GET_TWITTER_QUOTES = "getTwitterPostQuotes";
830
- var GET_TWITTER_COMMENTS = "getTwitterPostComments";
831
- var GET_TWITTER_POST_INTERACTING_USERS = "getTwitterPostInteractingUsers";
832
945
  var COUNT_TWEETS = "countTweets";
833
946
  var GET_TWITTER_USER = "getTwitterUser";
834
947
  var GET_TWITTER_USERS = "getTwitterUsers";
835
- var SEARCH_TWITTER_USERS = "searchTwitterUsers";
836
948
  var GET_TWITTER_USER_CONNECTIONS = "getTwitterUserConnections";
837
949
  var GET_TWITTER_USERS_BY_KEYWORDS = "getTwitterUsersByKeywords";
838
- var GET_INSTAGRAM_POSTS_BY_IDS = "getInstagramPostsByIds";
839
950
  var GET_INSTAGRAM_POSTS_BY_USER = "getInstagramPostsByUser";
840
951
  var SEARCH_INSTAGRAM_POSTS = "getInstagramPostsByKeywords";
841
- var GET_INSTAGRAM_COMMENTS = "getInstagramCommentsByPostId";
842
- var GET_INSTAGRAM_USER = "getInstagramUser";
843
- var SEARCH_INSTAGRAM_USERS = "searchInstagramUsers";
844
- var GET_INSTAGRAM_USER_CONNECTIONS = "getInstagramUserConnections";
845
- var GET_INSTAGRAM_POST_INTERACTING_USERS = "getInstagramPostInteractingUsers";
846
952
  var GET_INSTAGRAM_USERS_BY_KEYWORDS = "getInstagramUsersByKeywords";
847
953
  var SEARCH_REDDIT_POSTS = "getRedditPostsByKeywords";
848
954
  var GET_REDDIT_POST_WITH_COMMENTS = "getRedditPostWithCommentsById";
@@ -879,33 +985,79 @@ function parseUser(item) {
879
985
  return item;
880
986
  }
881
987
  var TwitterNamespace = class extends BaseNamespace {
988
+ rest;
989
+ constructor(callTool, timeoutMs, restTransport) {
990
+ super(callTool, timeoutMs);
991
+ this.rest = restTransport;
992
+ }
993
+ cursorToPaginatedResult(response, fetchNext, pageNumber = 1) {
994
+ const items = response.results ?? [];
995
+ const hasMore = Boolean(response.has_more);
996
+ const nextCursor = response.next_page_cursor ?? null;
997
+ const pagination = {
998
+ tableName: null,
999
+ totalRows: 0,
1000
+ totalPages: hasMore ? pageNumber + 1 : pageNumber,
1001
+ pageNumber,
1002
+ pageSize: items.length,
1003
+ resultsCount: items.length
1004
+ };
1005
+ const fetchPage = async () => {
1006
+ if (!nextCursor) {
1007
+ throw new RangeError("No more pages available");
1008
+ }
1009
+ const nextResponse = await fetchNext(nextCursor);
1010
+ return this.cursorToPaginatedResult(nextResponse, fetchNext, pageNumber + 1);
1011
+ };
1012
+ return new PaginatedResult({
1013
+ data: items,
1014
+ pagination,
1015
+ tableName: null,
1016
+ exportOperationId: null,
1017
+ fetchPage: () => fetchPage(),
1018
+ fetchExport: null
1019
+ });
1020
+ }
882
1021
  async getPostsByIds(postIds, options = {}) {
883
- const args = this.buildArgs({ postIds, ...options });
884
- const result = await this.callAndMaybePoll(
885
- GET_TWITTER_POSTS_BY_IDS,
886
- args
887
- );
888
- return (result["results"] ?? []).map(parseTwitterPost);
1022
+ const fieldsCsv = csvFields(options.fields);
1023
+ const results = await parallelMap(postIds, async (postId) => {
1024
+ const response = await this.rest.get(
1025
+ TWITTER_LIVE_ROUTES.post(postId),
1026
+ { fields: fieldsCsv }
1027
+ );
1028
+ return (response.results ?? [])[0] ?? null;
1029
+ });
1030
+ return results.filter((post) => post !== null);
889
1031
  }
890
1032
  async getPostsByAuthor(identifier, options = {}) {
891
- const args = this.buildArgs({
892
- username: identifier,
893
- fields: options.fields,
894
- startDate: options.startDate,
895
- endDate: options.endDate,
896
- forceLatest: options.forceLatest,
897
- responseType: options.responseType,
898
- limit: options.limit
899
- });
900
- const result = await this.callAndMaybePoll(
901
- GET_TWITTER_POSTS_BY_AUTHOR,
902
- args
1033
+ if (options.responseType === "csv" /* Csv */) {
1034
+ const args = this.buildArgs({
1035
+ username: identifier,
1036
+ fields: options.fields,
1037
+ startDate: options.startDate,
1038
+ endDate: options.endDate,
1039
+ forceLatest: options.forceLatest,
1040
+ responseType: options.responseType,
1041
+ limit: options.limit
1042
+ });
1043
+ const result = await this.callAndMaybePoll(GET_TWITTER_POSTS_BY_AUTHOR, args);
1044
+ return this.buildPaginatedResult(result, parseTwitterPost, GET_TWITTER_POSTS_BY_AUTHOR, args);
1045
+ }
1046
+ const params = {
1047
+ since: options.startDate,
1048
+ until: options.endDate,
1049
+ fields: csvFields(options.fields)
1050
+ };
1051
+ const response = await this.rest.get(
1052
+ TWITTER_LIVE_ROUTES.userPosts(identifier),
1053
+ params
903
1054
  );
904
- return this.buildPaginatedResult(
905
- result,
906
- parseTwitterPost,
907
- GET_TWITTER_POSTS_BY_AUTHOR,
908
- args
1055
+ return this.cursorToPaginatedResult(
1056
+ response,
1057
+ (cursor) => this.rest.get(
1058
+ TWITTER_LIVE_ROUTES.userPosts(identifier),
1059
+ { ...params, cursor }
1060
+ )
909
1061
  );
910
1062
  }
911
1063
  async searchPosts(query, options = {}) {
@@ -961,39 +1113,48 @@ var TwitterNamespace = class extends BaseNamespace {
961
1113
  );
962
1114
  }
963
1115
  async getQuotes(postId, options = {}) {
964
- const args = this.buildArgs({ postId, ...options });
965
- const result = await this.callAndMaybePoll(GET_TWITTER_QUOTES, args);
966
- return this.buildPaginatedResult(
967
- result,
968
- parseTwitterPost,
969
- GET_TWITTER_QUOTES,
970
- args
1116
+ const params = { fields: csvFields(options.fields) };
1117
+ const response = await this.rest.get(
1118
+ TWITTER_LIVE_ROUTES.postQuotes(postId),
1119
+ params
1120
+ );
1121
+ return this.cursorToPaginatedResult(
1122
+ response,
1123
+ (cursor) => this.rest.get(
1124
+ TWITTER_LIVE_ROUTES.postQuotes(postId),
1125
+ { ...params, cursor }
1126
+ )
971
1127
  );
972
1128
  }
973
1129
  async getComments(postId, options = {}) {
974
- const args = this.buildArgs({ postId, ...options });
975
- const result = await this.callAndMaybePoll(
976
- GET_TWITTER_COMMENTS,
977
- args
1130
+ const params = { fields: csvFields(options.fields) };
1131
+ const response = await this.rest.get(
1132
+ TWITTER_LIVE_ROUTES.postComments(postId),
1133
+ params
978
1134
  );
979
- return this.buildPaginatedResult(
980
- result,
981
- parseTwitterPost,
982
- GET_TWITTER_COMMENTS,
983
- args
1135
+ return this.cursorToPaginatedResult(
1136
+ response,
1137
+ (cursor) => this.rest.get(
1138
+ TWITTER_LIVE_ROUTES.postComments(postId),
1139
+ { ...params, cursor }
1140
+ )
984
1141
  );
985
1142
  }
986
1143
  async getPostInteractingUsers(postId, interactionType, options = {}) {
987
- const args = this.buildArgs({ postId, interactionType, ...options });
988
- const result = await this.callAndMaybePoll(
989
- GET_TWITTER_POST_INTERACTING_USERS,
990
- args
1144
+ const params = {
1145
+ interactionType,
1146
+ fields: csvFields(options.fields)
1147
+ };
1148
+ const response = await this.rest.get(
1149
+ TWITTER_LIVE_ROUTES.postInteractingUsers(postId),
1150
+ params
991
1151
  );
992
- return this.buildPaginatedResult(
993
- result,
994
- parseUser,
995
- GET_TWITTER_POST_INTERACTING_USERS,
996
- args
1152
+ return this.cursorToPaginatedResult(
1153
+ response,
1154
+ (cursor) => this.rest.get(
1155
+ TWITTER_LIVE_ROUTES.postInteractingUsers(postId),
1156
+ { ...params, cursor }
1157
+ )
997
1158
  );
998
1159
  }
999
1160
  async countPosts(phrase, options = {}) {
@@ -1011,48 +1172,81 @@ var TwitterNamespace = class extends BaseNamespace {
1011
1172
  return Number(count);
1012
1173
  }
1013
1174
  async getUsers(identifiers, options = {}) {
1014
- const args = this.buildArgs({
1015
- identifiers,
1016
- identifierType: options.identifierType ?? "username",
1017
- fields: options.fields,
1018
- forceLatest: options.forceLatest
1175
+ if ((options.identifierType ?? "username") === "id") {
1176
+ const args = this.buildArgs({
1177
+ identifiers,
1178
+ identifierType: "id",
1179
+ fields: options.fields,
1180
+ forceLatest: options.forceLatest
1181
+ });
1182
+ const result = await this.callAndMaybePoll(GET_TWITTER_USERS, args);
1183
+ return (result["results"] ?? []).map(parseUser);
1184
+ }
1185
+ const fieldsCsv = csvFields(options.fields);
1186
+ const results = await parallelMap(identifiers, async (username) => {
1187
+ const response = await this.rest.get(
1188
+ TWITTER_LIVE_ROUTES.user(username),
1189
+ { fields: fieldsCsv }
1190
+ );
1191
+ return (response.results ?? [])[0] ?? null;
1019
1192
  });
1020
- const result = await this.callAndMaybePoll(GET_TWITTER_USERS, args);
1021
- return (result["results"] ?? []).map(parseUser);
1193
+ return results.filter((user) => user !== null);
1022
1194
  }
1023
1195
  async getUser(identifier, options = {}) {
1024
- const args = this.buildArgs({
1025
- identifier,
1026
- identifierType: options.identifierType ?? "username",
1027
- fields: options.fields,
1028
- forceLatest: options.forceLatest
1029
- });
1030
- const result = await this.callAndMaybePoll(GET_TWITTER_USER, args);
1031
- const results = result["results"];
1032
- if (Array.isArray(results) && results.length > 0) {
1033
- return results[0];
1196
+ if ((options.identifierType ?? "username") === "id") {
1197
+ const args = this.buildArgs({
1198
+ identifier,
1199
+ identifierType: "id",
1200
+ fields: options.fields,
1201
+ forceLatest: options.forceLatest
1202
+ });
1203
+ const result = await this.callAndMaybePoll(GET_TWITTER_USER, args);
1204
+ const results = result["results"];
1205
+ if (Array.isArray(results) && results.length > 0) {
1206
+ return results[0];
1207
+ }
1208
+ return result;
1034
1209
  }
1035
- return result;
1210
+ const response = await this.rest.get(
1211
+ TWITTER_LIVE_ROUTES.user(identifier),
1212
+ { fields: csvFields(options.fields) }
1213
+ );
1214
+ if (response.results && response.results.length > 0) {
1215
+ return response.results[0];
1216
+ }
1217
+ throw new Error(`User not found: ${identifier}`);
1036
1218
  }
1037
1219
  async searchUsers(name, options = {}) {
1038
- const args = this.buildArgs({ name, ...options });
1039
- const result = await this.callAndMaybePoll(
1040
- SEARCH_TWITTER_USERS,
1041
- args
1220
+ const response = await this.rest.get(
1221
+ TWITTER_LIVE_ROUTES.users,
1222
+ { q: name, fields: csvFields(options.fields) }
1042
1223
  );
1043
- return (result["results"] ?? []).map(parseUser);
1224
+ const users = response.results ?? [];
1225
+ if (options.limit && options.limit > 0) {
1226
+ return users.slice(0, options.limit);
1227
+ }
1228
+ return users;
1044
1229
  }
1045
1230
  async getUserConnections(username, connectionType, options = {}) {
1046
- const args = this.buildArgs({ username, connectionType, ...options });
1047
- const result = await this.callAndMaybePoll(
1048
- GET_TWITTER_USER_CONNECTIONS,
1049
- args
1231
+ if (options.responseType === "csv" /* Csv */) {
1232
+ const args = this.buildArgs({ username, connectionType, ...options });
1233
+ const result = await this.callAndMaybePoll(GET_TWITTER_USER_CONNECTIONS, args);
1234
+ return this.buildPaginatedResult(result, parseUser, GET_TWITTER_USER_CONNECTIONS, args);
1235
+ }
1236
+ const params = {
1237
+ connectionType,
1238
+ fields: csvFields(options.fields)
1239
+ };
1240
+ const response = await this.rest.get(
1241
+ TWITTER_LIVE_ROUTES.userConnections(username),
1242
+ params
1050
1243
  );
1051
- return this.buildPaginatedResult(
1052
- result,
1053
- parseUser,
1054
- GET_TWITTER_USER_CONNECTIONS,
1055
- args
1244
+ return this.cursorToPaginatedResult(
1245
+ response,
1246
+ (cursor) => this.rest.get(
1247
+ TWITTER_LIVE_ROUTES.userConnections(username),
1248
+ { ...params, cursor }
1249
+ )
1056
1250
  );
1057
1251
  }
1058
1252
  async getUsersByKeywords(query, options = {}) {
@@ -1077,92 +1271,187 @@ function parsePost(item) {
1077
1271
  function parseUser2(item) {
1078
1272
  return item;
1079
1273
  }
1080
- function parseComment(item) {
1081
- return item;
1082
- }
1083
1274
  var InstagramNamespace = class extends BaseNamespace {
1275
+ rest;
1276
+ constructor(callTool, timeoutMs, restTransport) {
1277
+ super(callTool, timeoutMs);
1278
+ this.rest = restTransport;
1279
+ }
1280
+ cursorToPaginatedResult(response, fetchNext, pageNumber = 1) {
1281
+ const items = response.results ?? [];
1282
+ const hasMore = Boolean(response.has_more);
1283
+ const nextCursor = response.next_page_cursor ?? null;
1284
+ const pagination = {
1285
+ tableName: null,
1286
+ totalRows: 0,
1287
+ totalPages: hasMore ? pageNumber + 1 : pageNumber,
1288
+ pageNumber,
1289
+ pageSize: items.length,
1290
+ resultsCount: items.length
1291
+ };
1292
+ const fetchPage = async () => {
1293
+ if (!nextCursor) {
1294
+ throw new RangeError("No more pages available");
1295
+ }
1296
+ const nextResponse = await fetchNext(nextCursor);
1297
+ return this.cursorToPaginatedResult(nextResponse, fetchNext, pageNumber + 1);
1298
+ };
1299
+ return new PaginatedResult({
1300
+ data: items,
1301
+ pagination,
1302
+ tableName: null,
1303
+ exportOperationId: null,
1304
+ fetchPage: () => fetchPage(),
1305
+ fetchExport: null
1306
+ });
1307
+ }
1084
1308
  async getPostsByIds(postIds, options = {}) {
1085
- const args = this.buildArgs({ postIds, ...options });
1086
- const result = await this.callAndMaybePoll(GET_INSTAGRAM_POSTS_BY_IDS, args);
1087
- return (result["results"] ?? []).map(parsePost);
1309
+ const fieldsCsv = csvFields(options.fields);
1310
+ const results = await parallelMap(postIds, async (postId) => {
1311
+ const response = await this.rest.get(
1312
+ INSTAGRAM_LIVE_ROUTES.post(postId),
1313
+ { fields: fieldsCsv }
1314
+ );
1315
+ return (response.results ?? [])[0] ?? null;
1316
+ });
1317
+ return results.filter((post) => post !== null);
1088
1318
  }
1089
1319
  async getPostsByUser(identifier, options = {}) {
1090
- const args = this.buildArgs({
1091
- identifier,
1092
- identifierType: options.identifierType ?? "username",
1093
- fields: options.fields,
1094
- startDate: options.startDate,
1095
- endDate: options.endDate,
1096
- forceLatest: options.forceLatest,
1097
- responseType: options.responseType,
1098
- limit: options.limit
1099
- });
1100
- const result = await this.callAndMaybePoll(GET_INSTAGRAM_POSTS_BY_USER, args);
1101
- return this.buildPaginatedResult(
1102
- result,
1103
- parsePost,
1104
- GET_INSTAGRAM_POSTS_BY_USER,
1105
- args
1320
+ if (options.responseType === "csv" /* Csv */) {
1321
+ const args = this.buildArgs({
1322
+ identifier,
1323
+ identifierType: options.identifierType ?? "username",
1324
+ fields: options.fields,
1325
+ startDate: options.startDate,
1326
+ endDate: options.endDate,
1327
+ forceLatest: options.forceLatest,
1328
+ responseType: options.responseType,
1329
+ limit: options.limit
1330
+ });
1331
+ const result = await this.callAndMaybePoll(GET_INSTAGRAM_POSTS_BY_USER, args);
1332
+ return this.buildPaginatedResult(result, parsePost, GET_INSTAGRAM_POSTS_BY_USER, args);
1333
+ }
1334
+ const params = {
1335
+ fields: csvFields(options.fields)
1336
+ };
1337
+ const response = await this.rest.get(
1338
+ INSTAGRAM_LIVE_ROUTES.userPosts(identifier),
1339
+ params
1340
+ );
1341
+ return this.cursorToPaginatedResult(
1342
+ response,
1343
+ (cursor) => this.rest.get(
1344
+ INSTAGRAM_LIVE_ROUTES.userPosts(identifier),
1345
+ { ...params, cursor }
1346
+ )
1106
1347
  );
1107
1348
  }
1108
1349
  async searchPosts(query, options = {}) {
1109
- const args = this.buildArgs({
1110
- query,
1111
- fields: options.fields,
1112
- startDate: options.startDate,
1113
- endDate: options.endDate,
1114
- forceLatest: options.forceLatest,
1115
- responseType: options.responseType,
1116
- limit: options.limit
1117
- });
1118
- const result = await this.callAndMaybePoll(SEARCH_INSTAGRAM_POSTS, args);
1119
- return this.buildPaginatedResult(result, parsePost, SEARCH_INSTAGRAM_POSTS, args);
1350
+ if (options.responseType === "csv" /* Csv */) {
1351
+ const args = this.buildArgs({
1352
+ query,
1353
+ fields: options.fields,
1354
+ startDate: options.startDate,
1355
+ endDate: options.endDate,
1356
+ forceLatest: options.forceLatest,
1357
+ responseType: options.responseType,
1358
+ limit: options.limit
1359
+ });
1360
+ const result = await this.callAndMaybePoll(SEARCH_INSTAGRAM_POSTS, args);
1361
+ return this.buildPaginatedResult(result, parsePost, SEARCH_INSTAGRAM_POSTS, args);
1362
+ }
1363
+ const params = {
1364
+ q: query,
1365
+ fields: csvFields(options.fields)
1366
+ };
1367
+ const response = await this.rest.get(
1368
+ INSTAGRAM_LIVE_ROUTES.posts,
1369
+ params
1370
+ );
1371
+ return this.cursorToPaginatedResult(
1372
+ response,
1373
+ (cursor) => this.rest.get(
1374
+ INSTAGRAM_LIVE_ROUTES.posts,
1375
+ { ...params, cursor }
1376
+ )
1377
+ );
1120
1378
  }
1121
1379
  async getComments(postId, options = {}) {
1122
- const args = this.buildArgs({ postId, ...options });
1123
- const result = await this.callAndMaybePoll(GET_INSTAGRAM_COMMENTS, args);
1124
- return this.buildPaginatedResult(result, parseComment, GET_INSTAGRAM_COMMENTS, args);
1380
+ const params = {
1381
+ fields: csvFields(options.fields)
1382
+ };
1383
+ const response = await this.rest.get(
1384
+ INSTAGRAM_LIVE_ROUTES.postComments(postId),
1385
+ params
1386
+ );
1387
+ return this.cursorToPaginatedResult(
1388
+ response,
1389
+ (cursor) => this.rest.get(
1390
+ INSTAGRAM_LIVE_ROUTES.postComments(postId),
1391
+ { ...params, cursor }
1392
+ )
1393
+ );
1125
1394
  }
1126
1395
  async getUser(identifier, options = {}) {
1127
- const args = this.buildArgs({
1128
- identifier,
1129
- identifierType: options.identifierType ?? "username",
1130
- fields: options.fields,
1131
- forceLatest: options.forceLatest
1132
- });
1133
- const result = await this.callAndMaybePoll(GET_INSTAGRAM_USER, args);
1134
- const results = result["results"];
1135
- if (Array.isArray(results) && results.length > 0) {
1136
- return results[0];
1396
+ const response = await this.rest.get(
1397
+ INSTAGRAM_ROUTES.user(identifier),
1398
+ {
1399
+ identifierType: options.identifierType ?? "username",
1400
+ fields: csvFields(options.fields),
1401
+ forceLatest: true
1402
+ }
1403
+ );
1404
+ if (response.results.length > 0) {
1405
+ return response.results[0];
1137
1406
  }
1138
- return result;
1407
+ throw new Error(`User not found: ${identifier}`);
1139
1408
  }
1140
1409
  async searchUsers(name, options = {}) {
1141
- const args = this.buildArgs({ name, ...options });
1142
- const result = await this.callAndMaybePoll(SEARCH_INSTAGRAM_USERS, args);
1143
- return (result["results"] ?? []).map(parseUser2);
1410
+ const response = await this.rest.get(
1411
+ INSTAGRAM_LIVE_ROUTES.users,
1412
+ {
1413
+ name,
1414
+ fields: csvFields(options.fields)
1415
+ }
1416
+ );
1417
+ const users = response.results ?? [];
1418
+ if (options.limit && options.limit > 0) {
1419
+ return users.slice(0, options.limit);
1420
+ }
1421
+ return users;
1144
1422
  }
1145
1423
  async getUserConnections(username, connectionType, options = {}) {
1146
- const args = this.buildArgs({ username, connectionType, ...options });
1147
- const result = await this.callAndMaybePoll(GET_INSTAGRAM_USER_CONNECTIONS, args);
1148
- return this.buildPaginatedResult(
1149
- result,
1150
- parseUser2,
1151
- GET_INSTAGRAM_USER_CONNECTIONS,
1152
- args
1424
+ const params = {
1425
+ connectionType,
1426
+ fields: csvFields(options.fields)
1427
+ };
1428
+ const response = await this.rest.get(
1429
+ INSTAGRAM_LIVE_ROUTES.userConnections(username),
1430
+ params
1431
+ );
1432
+ return this.cursorToPaginatedResult(
1433
+ response,
1434
+ (cursor) => this.rest.get(
1435
+ INSTAGRAM_LIVE_ROUTES.userConnections(username),
1436
+ { ...params, cursor }
1437
+ )
1153
1438
  );
1154
1439
  }
1155
1440
  async getPostInteractingUsers(postId, interactionType, options = {}) {
1156
- const args = this.buildArgs({ postId, interactionType, ...options });
1157
- const result = await this.callAndMaybePoll(
1158
- GET_INSTAGRAM_POST_INTERACTING_USERS,
1159
- args
1441
+ const params = {
1442
+ interactionType,
1443
+ fields: csvFields(options.fields)
1444
+ };
1445
+ const response = await this.rest.get(
1446
+ INSTAGRAM_LIVE_ROUTES.postInteractingUsers(postId),
1447
+ params
1160
1448
  );
1161
- return this.buildPaginatedResult(
1162
- result,
1163
- parseUser2,
1164
- GET_INSTAGRAM_POST_INTERACTING_USERS,
1165
- args
1449
+ return this.cursorToPaginatedResult(
1450
+ response,
1451
+ (cursor) => this.rest.get(
1452
+ INSTAGRAM_LIVE_ROUTES.postInteractingUsers(postId),
1453
+ { ...params, cursor }
1454
+ )
1166
1455
  );
1167
1456
  }
1168
1457
  async getUsersByKeywords(query, options = {}) {
@@ -1184,7 +1473,7 @@ function parsePost2(item) {
1184
1473
  function parseUser3(item) {
1185
1474
  return item;
1186
1475
  }
1187
- function parseComment2(item) {
1476
+ function parseComment(item) {
1188
1477
  return item;
1189
1478
  }
1190
1479
  function parseSubreddit(item) {
@@ -1204,7 +1493,7 @@ var RedditNamespace = class extends BaseNamespace {
1204
1493
  async searchComments(query, options = {}) {
1205
1494
  const args = this.buildArgs({ query, ...options });
1206
1495
  const result = await this.callAndMaybePoll(SEARCH_REDDIT_COMMENTS, args);
1207
- return this.buildPaginatedResult(result, parseComment2, SEARCH_REDDIT_COMMENTS, args);
1496
+ return this.buildPaginatedResult(result, parseComment, SEARCH_REDDIT_COMMENTS, args);
1208
1497
  }
1209
1498
  async getCommentById(commentId, options = {}) {
1210
1499
  const args = this.buildArgs({ commentId, ...options });
@@ -1269,7 +1558,7 @@ var RedditNamespace = class extends BaseNamespace {
1269
1558
  const pagination = this.extractPagination(raw);
1270
1559
  return {
1271
1560
  post: postData,
1272
- comments: commentsData.map(parseComment2),
1561
+ comments: commentsData.map(parseComment),
1273
1562
  commentsPagination: pagination.totalPages > 0 ? pagination : null,
1274
1563
  commentsTableName: pagination.tableName ?? null
1275
1564
  };
@@ -1298,7 +1587,7 @@ function parsePost3(item) {
1298
1587
  function parseUser4(item) {
1299
1588
  return item;
1300
1589
  }
1301
- function parseComment3(item) {
1590
+ function parseComment2(item) {
1302
1591
  return item;
1303
1592
  }
1304
1593
  function parseSound(item) {
@@ -1345,7 +1634,7 @@ var TiktokNamespace = class extends BaseNamespace {
1345
1634
  async getComments(postId, options = {}) {
1346
1635
  const args = this.buildArgs({ postId, ...options });
1347
1636
  const result = await this.callAndMaybePoll(GET_TIKTOK_COMMENTS, args);
1348
- return this.buildPaginatedResult(result, parseComment3, GET_TIKTOK_COMMENTS, args);
1637
+ return this.buildPaginatedResult(result, parseComment2, GET_TIKTOK_COMMENTS, args);
1349
1638
  }
1350
1639
  async getUser(identifier, options = {}) {
1351
1640
  const args = this.buildArgs({
@@ -1491,6 +1780,7 @@ var XpozClient = class {
1491
1780
  versionCheck;
1492
1781
  restTransport;
1493
1782
  instagramLiveNamespace;
1783
+ twitterLiveNamespace;
1494
1784
  constructor(options = {}) {
1495
1785
  const apiKey = options.apiKey ?? process.env[ENV_API_KEY];
1496
1786
  if (!apiKey) {
@@ -1505,8 +1795,8 @@ var XpozClient = class {
1505
1795
  const apiUrl = options.apiUrl ?? process.env[ENV_API_URL] ?? DEFAULT_API_URL;
1506
1796
  this.restTransport = new RestTransport(apiUrl, apiKey);
1507
1797
  const callTool = this.transport.callTool.bind(this.transport);
1508
- this.twitter = new TwitterNamespace(callTool, timeoutMs);
1509
- this.instagram = new InstagramNamespace(callTool, timeoutMs);
1798
+ this.twitter = new TwitterNamespace(callTool, timeoutMs, this.restTransport);
1799
+ this.instagram = new InstagramNamespace(callTool, timeoutMs, this.restTransport);
1510
1800
  this.reddit = new RedditNamespace(callTool, timeoutMs);
1511
1801
  this.tiktok = new TiktokNamespace(callTool, timeoutMs);
1512
1802
  this.tracking = new TrackingNamespace(callTool, timeoutMs);
@@ -1518,6 +1808,12 @@ var XpozClient = class {
1518
1808
  }
1519
1809
  return this.instagramLiveNamespace;
1520
1810
  }
1811
+ get twitterLive() {
1812
+ if (!this.twitterLiveNamespace) {
1813
+ this.twitterLiveNamespace = new TwitterLiveNamespace(this.restTransport);
1814
+ }
1815
+ return this.twitterLiveNamespace;
1816
+ }
1521
1817
  async connect() {
1522
1818
  await this.transport.connect();
1523
1819
  if (this.versionCheck) {