@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/README.md +35 -36
- package/dist/index.cjs +464 -168
- package/dist/index.d.cts +107 -45
- package/dist/index.d.ts +107 -45
- package/dist/index.js +464 -168
- package/package.json +1 -1
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.
|
|
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/
|
|
580
|
-
var STRING_ID_FIELDS = [
|
|
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
|
|
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
|
|
884
|
-
const
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
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
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
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.
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
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
|
|
965
|
-
const
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
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
|
|
975
|
-
const
|
|
976
|
-
|
|
977
|
-
|
|
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.
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
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
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
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.
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
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
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
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
|
-
|
|
1021
|
-
return (result["results"] ?? []).map(parseUser);
|
|
1193
|
+
return results.filter((user) => user !== null);
|
|
1022
1194
|
}
|
|
1023
1195
|
async getUser(identifier, options = {}) {
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
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
|
-
|
|
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
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
args
|
|
1220
|
+
const response = await this.rest.get(
|
|
1221
|
+
TWITTER_LIVE_ROUTES.users,
|
|
1222
|
+
{ q: name, fields: csvFields(options.fields) }
|
|
1042
1223
|
);
|
|
1043
|
-
|
|
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
|
-
|
|
1047
|
-
|
|
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.
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
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
|
|
1086
|
-
const
|
|
1087
|
-
|
|
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
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
result,
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
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
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
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
|
|
1123
|
-
|
|
1124
|
-
|
|
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
|
|
1128
|
-
identifier,
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
if (
|
|
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
|
-
|
|
1407
|
+
throw new Error(`User not found: ${identifier}`);
|
|
1139
1408
|
}
|
|
1140
1409
|
async searchUsers(name, options = {}) {
|
|
1141
|
-
const
|
|
1142
|
-
|
|
1143
|
-
|
|
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
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
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
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
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.
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
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
|
|
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,
|
|
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(
|
|
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
|
|
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,
|
|
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) {
|