@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.js
CHANGED
|
@@ -248,7 +248,7 @@ function coerce(value) {
|
|
|
248
248
|
}
|
|
249
249
|
|
|
250
250
|
// src/version.ts
|
|
251
|
-
var VERSION = "0.
|
|
251
|
+
var VERSION = "0.8.0";
|
|
252
252
|
|
|
253
253
|
// src/mcp/transport.ts
|
|
254
254
|
var USER_AGENT = `xpoz-ts-sdk/${VERSION}`;
|
|
@@ -401,6 +401,11 @@ var DEFAULT_TIMEOUT_MS = 3e5;
|
|
|
401
401
|
var DEFAULT_API_URL = "https://api.xpoz.ai";
|
|
402
402
|
var ENV_API_URL = "XPOZ_API_URL";
|
|
403
403
|
var INSTAGRAM_BASE = "/api/data/instagram";
|
|
404
|
+
var TWITTER_BASE = "/api/data/twitter";
|
|
405
|
+
var INSTAGRAM_ROUTES = {
|
|
406
|
+
user: (identifier) => `${INSTAGRAM_BASE}/users/${encodeURIComponent(identifier)}`,
|
|
407
|
+
postsByIds: `${INSTAGRAM_BASE}/posts/ids`
|
|
408
|
+
};
|
|
404
409
|
var INSTAGRAM_LIVE_ROUTES = {
|
|
405
410
|
posts: `${INSTAGRAM_BASE}/posts/live`,
|
|
406
411
|
userPosts: (identifier) => `${INSTAGRAM_BASE}/posts/users/${encodeURIComponent(identifier)}/live`,
|
|
@@ -411,6 +416,20 @@ var INSTAGRAM_LIVE_ROUTES = {
|
|
|
411
416
|
user: (identifier) => `${INSTAGRAM_BASE}/users/${encodeURIComponent(identifier)}/live`,
|
|
412
417
|
userConnections: (identifier) => `${INSTAGRAM_BASE}/users/${encodeURIComponent(identifier)}/connections/live`
|
|
413
418
|
};
|
|
419
|
+
var TWITTER_ROUTES = {
|
|
420
|
+
posts: `${TWITTER_BASE}/posts`
|
|
421
|
+
};
|
|
422
|
+
var TWITTER_LIVE_ROUTES = {
|
|
423
|
+
posts: `${TWITTER_BASE}/posts/live`,
|
|
424
|
+
userPosts: (username) => `${TWITTER_BASE}/posts/users/${encodeURIComponent(username)}/live`,
|
|
425
|
+
post: (postId) => `${TWITTER_BASE}/posts/${encodeURIComponent(postId)}/live`,
|
|
426
|
+
postComments: (postId) => `${TWITTER_BASE}/posts/${encodeURIComponent(postId)}/comments/live`,
|
|
427
|
+
postQuotes: (postId) => `${TWITTER_BASE}/posts/${encodeURIComponent(postId)}/quotes/live`,
|
|
428
|
+
postInteractingUsers: (postId) => `${TWITTER_BASE}/posts/${encodeURIComponent(postId)}/interacting-users/live`,
|
|
429
|
+
users: `${TWITTER_BASE}/users/live`,
|
|
430
|
+
user: (username) => `${TWITTER_BASE}/users/${encodeURIComponent(username)}/live`,
|
|
431
|
+
userConnections: (username) => `${TWITTER_BASE}/users/${encodeURIComponent(username)}/connections/live`
|
|
432
|
+
};
|
|
414
433
|
var REST_TIMEOUT_MS = 12e4;
|
|
415
434
|
|
|
416
435
|
// src/rest/transport.ts
|
|
@@ -523,8 +542,16 @@ var CursorResult = class {
|
|
|
523
542
|
}
|
|
524
543
|
};
|
|
525
544
|
|
|
526
|
-
// src/namespaces/
|
|
527
|
-
var STRING_ID_FIELDS = [
|
|
545
|
+
// src/namespaces/liveBase.ts
|
|
546
|
+
var STRING_ID_FIELDS = [
|
|
547
|
+
"id",
|
|
548
|
+
"userId",
|
|
549
|
+
"user_id",
|
|
550
|
+
"postId",
|
|
551
|
+
"post_id",
|
|
552
|
+
"authorId",
|
|
553
|
+
"author_id"
|
|
554
|
+
];
|
|
528
555
|
function coerceStringIds(item) {
|
|
529
556
|
const record = item;
|
|
530
557
|
for (const field of STRING_ID_FIELDS) {
|
|
@@ -537,7 +564,7 @@ function coerceStringIds(item) {
|
|
|
537
564
|
function csvFields(fields) {
|
|
538
565
|
return fields && fields.length > 0 ? fields.join(",") : void 0;
|
|
539
566
|
}
|
|
540
|
-
var
|
|
567
|
+
var LiveNamespace = class {
|
|
541
568
|
transport;
|
|
542
569
|
constructor(transport) {
|
|
543
570
|
this.transport = transport;
|
|
@@ -555,6 +582,10 @@ var InstagramLiveNamespace = class {
|
|
|
555
582
|
const page = await this.page(path, params);
|
|
556
583
|
return page.data[0] ?? null;
|
|
557
584
|
}
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
// src/namespaces/instagramLive.ts
|
|
588
|
+
var InstagramLiveNamespace = class extends LiveNamespace {
|
|
558
589
|
async searchPosts(query, options = {}) {
|
|
559
590
|
return this.page(INSTAGRAM_LIVE_ROUTES.posts, {
|
|
560
591
|
q: query,
|
|
@@ -607,6 +638,73 @@ var InstagramLiveNamespace = class {
|
|
|
607
638
|
}
|
|
608
639
|
};
|
|
609
640
|
|
|
641
|
+
// src/namespaces/twitterLive.ts
|
|
642
|
+
var TwitterLiveNamespace = class extends LiveNamespace {
|
|
643
|
+
async searchPosts(query, options = {}) {
|
|
644
|
+
return this.page(TWITTER_LIVE_ROUTES.posts, {
|
|
645
|
+
q: query,
|
|
646
|
+
since: options.since,
|
|
647
|
+
until: options.until,
|
|
648
|
+
lang: options.lang,
|
|
649
|
+
countryCode: options.countryCode,
|
|
650
|
+
sortBy: options.sortBy,
|
|
651
|
+
fields: csvFields(options.fields),
|
|
652
|
+
cursor: options.cursor
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
async getPostsByUser(username, options = {}) {
|
|
656
|
+
return this.page(TWITTER_LIVE_ROUTES.userPosts(username), {
|
|
657
|
+
since: options.since,
|
|
658
|
+
until: options.until,
|
|
659
|
+
fields: csvFields(options.fields),
|
|
660
|
+
cursor: options.cursor
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
async getPost(postId, options = {}) {
|
|
664
|
+
return this.single(TWITTER_LIVE_ROUTES.post(postId), {
|
|
665
|
+
fields: csvFields(options.fields)
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
async getComments(postId, options = {}) {
|
|
669
|
+
return this.page(TWITTER_LIVE_ROUTES.postComments(postId), {
|
|
670
|
+
fields: csvFields(options.fields),
|
|
671
|
+
cursor: options.cursor
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
async getQuotes(postId, options = {}) {
|
|
675
|
+
return this.page(TWITTER_LIVE_ROUTES.postQuotes(postId), {
|
|
676
|
+
fields: csvFields(options.fields),
|
|
677
|
+
cursor: options.cursor
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
async getPostInteractingUsers(postId, interactionType, options = {}) {
|
|
681
|
+
return this.page(TWITTER_LIVE_ROUTES.postInteractingUsers(postId), {
|
|
682
|
+
interactionType,
|
|
683
|
+
fields: csvFields(options.fields),
|
|
684
|
+
cursor: options.cursor
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
async searchUsers(query, options = {}) {
|
|
688
|
+
return this.page(TWITTER_LIVE_ROUTES.users, {
|
|
689
|
+
q: query,
|
|
690
|
+
fields: csvFields(options.fields),
|
|
691
|
+
cursor: options.cursor
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
async getUser(username, options = {}) {
|
|
695
|
+
return this.single(TWITTER_LIVE_ROUTES.user(username), {
|
|
696
|
+
fields: csvFields(options.fields)
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
async getUserConnections(username, connectionType, options = {}) {
|
|
700
|
+
return this.page(TWITTER_LIVE_ROUTES.userConnections(username), {
|
|
701
|
+
connectionType,
|
|
702
|
+
fields: csvFields(options.fields),
|
|
703
|
+
cursor: options.cursor
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
};
|
|
707
|
+
|
|
610
708
|
// src/mcp/polling.ts
|
|
611
709
|
async function waitForResult(callTool, operationId, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
612
710
|
const start = Date.now();
|
|
@@ -768,28 +866,36 @@ var BaseNamespace = class {
|
|
|
768
866
|
}
|
|
769
867
|
};
|
|
770
868
|
|
|
869
|
+
// src/concurrency.ts
|
|
870
|
+
var DEFAULT_CONCURRENCY = 10;
|
|
871
|
+
async function parallelMap(items, fn, concurrency = DEFAULT_CONCURRENCY) {
|
|
872
|
+
const results = new Array(items.length);
|
|
873
|
+
let nextIndex = 0;
|
|
874
|
+
async function worker() {
|
|
875
|
+
while (nextIndex < items.length) {
|
|
876
|
+
const index = nextIndex++;
|
|
877
|
+
results[index] = await fn(items[index]);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
const workers = Array.from(
|
|
881
|
+
{ length: Math.min(concurrency, items.length) },
|
|
882
|
+
() => worker()
|
|
883
|
+
);
|
|
884
|
+
await Promise.all(workers);
|
|
885
|
+
return results;
|
|
886
|
+
}
|
|
887
|
+
|
|
771
888
|
// src/config/tools.ts
|
|
772
|
-
var GET_TWITTER_POSTS_BY_IDS = "getTwitterPostsByIds";
|
|
773
889
|
var GET_TWITTER_POSTS_BY_AUTHOR = "getTwitterPostsByAuthor";
|
|
774
890
|
var SEARCH_TWITTER_POSTS = "getTwitterPostsByKeywords";
|
|
775
891
|
var GET_TWITTER_RETWEETS = "getTwitterPostRetweets";
|
|
776
|
-
var GET_TWITTER_QUOTES = "getTwitterPostQuotes";
|
|
777
|
-
var GET_TWITTER_COMMENTS = "getTwitterPostComments";
|
|
778
|
-
var GET_TWITTER_POST_INTERACTING_USERS = "getTwitterPostInteractingUsers";
|
|
779
892
|
var COUNT_TWEETS = "countTweets";
|
|
780
893
|
var GET_TWITTER_USER = "getTwitterUser";
|
|
781
894
|
var GET_TWITTER_USERS = "getTwitterUsers";
|
|
782
|
-
var SEARCH_TWITTER_USERS = "searchTwitterUsers";
|
|
783
895
|
var GET_TWITTER_USER_CONNECTIONS = "getTwitterUserConnections";
|
|
784
896
|
var GET_TWITTER_USERS_BY_KEYWORDS = "getTwitterUsersByKeywords";
|
|
785
|
-
var GET_INSTAGRAM_POSTS_BY_IDS = "getInstagramPostsByIds";
|
|
786
897
|
var GET_INSTAGRAM_POSTS_BY_USER = "getInstagramPostsByUser";
|
|
787
898
|
var SEARCH_INSTAGRAM_POSTS = "getInstagramPostsByKeywords";
|
|
788
|
-
var GET_INSTAGRAM_COMMENTS = "getInstagramCommentsByPostId";
|
|
789
|
-
var GET_INSTAGRAM_USER = "getInstagramUser";
|
|
790
|
-
var SEARCH_INSTAGRAM_USERS = "searchInstagramUsers";
|
|
791
|
-
var GET_INSTAGRAM_USER_CONNECTIONS = "getInstagramUserConnections";
|
|
792
|
-
var GET_INSTAGRAM_POST_INTERACTING_USERS = "getInstagramPostInteractingUsers";
|
|
793
899
|
var GET_INSTAGRAM_USERS_BY_KEYWORDS = "getInstagramUsersByKeywords";
|
|
794
900
|
var SEARCH_REDDIT_POSTS = "getRedditPostsByKeywords";
|
|
795
901
|
var GET_REDDIT_POST_WITH_COMMENTS = "getRedditPostWithCommentsById";
|
|
@@ -826,33 +932,79 @@ function parseUser(item) {
|
|
|
826
932
|
return item;
|
|
827
933
|
}
|
|
828
934
|
var TwitterNamespace = class extends BaseNamespace {
|
|
935
|
+
rest;
|
|
936
|
+
constructor(callTool, timeoutMs, restTransport) {
|
|
937
|
+
super(callTool, timeoutMs);
|
|
938
|
+
this.rest = restTransport;
|
|
939
|
+
}
|
|
940
|
+
cursorToPaginatedResult(response, fetchNext, pageNumber = 1) {
|
|
941
|
+
const items = response.results ?? [];
|
|
942
|
+
const hasMore = Boolean(response.has_more);
|
|
943
|
+
const nextCursor = response.next_page_cursor ?? null;
|
|
944
|
+
const pagination = {
|
|
945
|
+
tableName: null,
|
|
946
|
+
totalRows: 0,
|
|
947
|
+
totalPages: hasMore ? pageNumber + 1 : pageNumber,
|
|
948
|
+
pageNumber,
|
|
949
|
+
pageSize: items.length,
|
|
950
|
+
resultsCount: items.length
|
|
951
|
+
};
|
|
952
|
+
const fetchPage = async () => {
|
|
953
|
+
if (!nextCursor) {
|
|
954
|
+
throw new RangeError("No more pages available");
|
|
955
|
+
}
|
|
956
|
+
const nextResponse = await fetchNext(nextCursor);
|
|
957
|
+
return this.cursorToPaginatedResult(nextResponse, fetchNext, pageNumber + 1);
|
|
958
|
+
};
|
|
959
|
+
return new PaginatedResult({
|
|
960
|
+
data: items,
|
|
961
|
+
pagination,
|
|
962
|
+
tableName: null,
|
|
963
|
+
exportOperationId: null,
|
|
964
|
+
fetchPage: () => fetchPage(),
|
|
965
|
+
fetchExport: null
|
|
966
|
+
});
|
|
967
|
+
}
|
|
829
968
|
async getPostsByIds(postIds, options = {}) {
|
|
830
|
-
const
|
|
831
|
-
const
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
969
|
+
const fieldsCsv = csvFields(options.fields);
|
|
970
|
+
const results = await parallelMap(postIds, async (postId) => {
|
|
971
|
+
const response = await this.rest.get(
|
|
972
|
+
TWITTER_LIVE_ROUTES.post(postId),
|
|
973
|
+
{ fields: fieldsCsv }
|
|
974
|
+
);
|
|
975
|
+
return (response.results ?? [])[0] ?? null;
|
|
976
|
+
});
|
|
977
|
+
return results.filter((post) => post !== null);
|
|
836
978
|
}
|
|
837
979
|
async getPostsByAuthor(identifier, options = {}) {
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
GET_TWITTER_POSTS_BY_AUTHOR,
|
|
849
|
-
args
|
|
980
|
+
if (options.responseType === "csv" /* Csv */) {
|
|
981
|
+
const args = this.buildArgs({
|
|
982
|
+
username: identifier,
|
|
983
|
+
fields: options.fields,
|
|
984
|
+
startDate: options.startDate,
|
|
985
|
+
endDate: options.endDate,
|
|
986
|
+
forceLatest: options.forceLatest,
|
|
987
|
+
responseType: options.responseType,
|
|
988
|
+
limit: options.limit
|
|
989
|
+
});
|
|
990
|
+
const result = await this.callAndMaybePoll(GET_TWITTER_POSTS_BY_AUTHOR, args);
|
|
991
|
+
return this.buildPaginatedResult(result, parseTwitterPost, GET_TWITTER_POSTS_BY_AUTHOR, args);
|
|
992
|
+
}
|
|
993
|
+
const params = {
|
|
994
|
+
since: options.startDate,
|
|
995
|
+
until: options.endDate,
|
|
996
|
+
fields: csvFields(options.fields)
|
|
997
|
+
};
|
|
998
|
+
const response = await this.rest.get(
|
|
999
|
+
TWITTER_LIVE_ROUTES.userPosts(identifier),
|
|
1000
|
+
params
|
|
850
1001
|
);
|
|
851
|
-
return this.
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
1002
|
+
return this.cursorToPaginatedResult(
|
|
1003
|
+
response,
|
|
1004
|
+
(cursor) => this.rest.get(
|
|
1005
|
+
TWITTER_LIVE_ROUTES.userPosts(identifier),
|
|
1006
|
+
{ ...params, cursor }
|
|
1007
|
+
)
|
|
856
1008
|
);
|
|
857
1009
|
}
|
|
858
1010
|
async searchPosts(query, options = {}) {
|
|
@@ -908,39 +1060,48 @@ var TwitterNamespace = class extends BaseNamespace {
|
|
|
908
1060
|
);
|
|
909
1061
|
}
|
|
910
1062
|
async getQuotes(postId, options = {}) {
|
|
911
|
-
const
|
|
912
|
-
const
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
1063
|
+
const params = { fields: csvFields(options.fields) };
|
|
1064
|
+
const response = await this.rest.get(
|
|
1065
|
+
TWITTER_LIVE_ROUTES.postQuotes(postId),
|
|
1066
|
+
params
|
|
1067
|
+
);
|
|
1068
|
+
return this.cursorToPaginatedResult(
|
|
1069
|
+
response,
|
|
1070
|
+
(cursor) => this.rest.get(
|
|
1071
|
+
TWITTER_LIVE_ROUTES.postQuotes(postId),
|
|
1072
|
+
{ ...params, cursor }
|
|
1073
|
+
)
|
|
918
1074
|
);
|
|
919
1075
|
}
|
|
920
1076
|
async getComments(postId, options = {}) {
|
|
921
|
-
const
|
|
922
|
-
const
|
|
923
|
-
|
|
924
|
-
|
|
1077
|
+
const params = { fields: csvFields(options.fields) };
|
|
1078
|
+
const response = await this.rest.get(
|
|
1079
|
+
TWITTER_LIVE_ROUTES.postComments(postId),
|
|
1080
|
+
params
|
|
925
1081
|
);
|
|
926
|
-
return this.
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
1082
|
+
return this.cursorToPaginatedResult(
|
|
1083
|
+
response,
|
|
1084
|
+
(cursor) => this.rest.get(
|
|
1085
|
+
TWITTER_LIVE_ROUTES.postComments(postId),
|
|
1086
|
+
{ ...params, cursor }
|
|
1087
|
+
)
|
|
931
1088
|
);
|
|
932
1089
|
}
|
|
933
1090
|
async getPostInteractingUsers(postId, interactionType, options = {}) {
|
|
934
|
-
const
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
1091
|
+
const params = {
|
|
1092
|
+
interactionType,
|
|
1093
|
+
fields: csvFields(options.fields)
|
|
1094
|
+
};
|
|
1095
|
+
const response = await this.rest.get(
|
|
1096
|
+
TWITTER_LIVE_ROUTES.postInteractingUsers(postId),
|
|
1097
|
+
params
|
|
938
1098
|
);
|
|
939
|
-
return this.
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
1099
|
+
return this.cursorToPaginatedResult(
|
|
1100
|
+
response,
|
|
1101
|
+
(cursor) => this.rest.get(
|
|
1102
|
+
TWITTER_LIVE_ROUTES.postInteractingUsers(postId),
|
|
1103
|
+
{ ...params, cursor }
|
|
1104
|
+
)
|
|
944
1105
|
);
|
|
945
1106
|
}
|
|
946
1107
|
async countPosts(phrase, options = {}) {
|
|
@@ -958,48 +1119,81 @@ var TwitterNamespace = class extends BaseNamespace {
|
|
|
958
1119
|
return Number(count);
|
|
959
1120
|
}
|
|
960
1121
|
async getUsers(identifiers, options = {}) {
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1122
|
+
if ((options.identifierType ?? "username") === "id") {
|
|
1123
|
+
const args = this.buildArgs({
|
|
1124
|
+
identifiers,
|
|
1125
|
+
identifierType: "id",
|
|
1126
|
+
fields: options.fields,
|
|
1127
|
+
forceLatest: options.forceLatest
|
|
1128
|
+
});
|
|
1129
|
+
const result = await this.callAndMaybePoll(GET_TWITTER_USERS, args);
|
|
1130
|
+
return (result["results"] ?? []).map(parseUser);
|
|
1131
|
+
}
|
|
1132
|
+
const fieldsCsv = csvFields(options.fields);
|
|
1133
|
+
const results = await parallelMap(identifiers, async (username) => {
|
|
1134
|
+
const response = await this.rest.get(
|
|
1135
|
+
TWITTER_LIVE_ROUTES.user(username),
|
|
1136
|
+
{ fields: fieldsCsv }
|
|
1137
|
+
);
|
|
1138
|
+
return (response.results ?? [])[0] ?? null;
|
|
966
1139
|
});
|
|
967
|
-
|
|
968
|
-
return (result["results"] ?? []).map(parseUser);
|
|
1140
|
+
return results.filter((user) => user !== null);
|
|
969
1141
|
}
|
|
970
1142
|
async getUser(identifier, options = {}) {
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1143
|
+
if ((options.identifierType ?? "username") === "id") {
|
|
1144
|
+
const args = this.buildArgs({
|
|
1145
|
+
identifier,
|
|
1146
|
+
identifierType: "id",
|
|
1147
|
+
fields: options.fields,
|
|
1148
|
+
forceLatest: options.forceLatest
|
|
1149
|
+
});
|
|
1150
|
+
const result = await this.callAndMaybePoll(GET_TWITTER_USER, args);
|
|
1151
|
+
const results = result["results"];
|
|
1152
|
+
if (Array.isArray(results) && results.length > 0) {
|
|
1153
|
+
return results[0];
|
|
1154
|
+
}
|
|
1155
|
+
return result;
|
|
981
1156
|
}
|
|
982
|
-
|
|
1157
|
+
const response = await this.rest.get(
|
|
1158
|
+
TWITTER_LIVE_ROUTES.user(identifier),
|
|
1159
|
+
{ fields: csvFields(options.fields) }
|
|
1160
|
+
);
|
|
1161
|
+
if (response.results && response.results.length > 0) {
|
|
1162
|
+
return response.results[0];
|
|
1163
|
+
}
|
|
1164
|
+
throw new Error(`User not found: ${identifier}`);
|
|
983
1165
|
}
|
|
984
1166
|
async searchUsers(name, options = {}) {
|
|
985
|
-
const
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
args
|
|
1167
|
+
const response = await this.rest.get(
|
|
1168
|
+
TWITTER_LIVE_ROUTES.users,
|
|
1169
|
+
{ q: name, fields: csvFields(options.fields) }
|
|
989
1170
|
);
|
|
990
|
-
|
|
1171
|
+
const users = response.results ?? [];
|
|
1172
|
+
if (options.limit && options.limit > 0) {
|
|
1173
|
+
return users.slice(0, options.limit);
|
|
1174
|
+
}
|
|
1175
|
+
return users;
|
|
991
1176
|
}
|
|
992
1177
|
async getUserConnections(username, connectionType, options = {}) {
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
GET_TWITTER_USER_CONNECTIONS,
|
|
996
|
-
args
|
|
1178
|
+
if (options.responseType === "csv" /* Csv */) {
|
|
1179
|
+
const args = this.buildArgs({ username, connectionType, ...options });
|
|
1180
|
+
const result = await this.callAndMaybePoll(GET_TWITTER_USER_CONNECTIONS, args);
|
|
1181
|
+
return this.buildPaginatedResult(result, parseUser, GET_TWITTER_USER_CONNECTIONS, args);
|
|
1182
|
+
}
|
|
1183
|
+
const params = {
|
|
1184
|
+
connectionType,
|
|
1185
|
+
fields: csvFields(options.fields)
|
|
1186
|
+
};
|
|
1187
|
+
const response = await this.rest.get(
|
|
1188
|
+
TWITTER_LIVE_ROUTES.userConnections(username),
|
|
1189
|
+
params
|
|
997
1190
|
);
|
|
998
|
-
return this.
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1191
|
+
return this.cursorToPaginatedResult(
|
|
1192
|
+
response,
|
|
1193
|
+
(cursor) => this.rest.get(
|
|
1194
|
+
TWITTER_LIVE_ROUTES.userConnections(username),
|
|
1195
|
+
{ ...params, cursor }
|
|
1196
|
+
)
|
|
1003
1197
|
);
|
|
1004
1198
|
}
|
|
1005
1199
|
async getUsersByKeywords(query, options = {}) {
|
|
@@ -1024,92 +1218,187 @@ function parsePost(item) {
|
|
|
1024
1218
|
function parseUser2(item) {
|
|
1025
1219
|
return item;
|
|
1026
1220
|
}
|
|
1027
|
-
function parseComment(item) {
|
|
1028
|
-
return item;
|
|
1029
|
-
}
|
|
1030
1221
|
var InstagramNamespace = class extends BaseNamespace {
|
|
1222
|
+
rest;
|
|
1223
|
+
constructor(callTool, timeoutMs, restTransport) {
|
|
1224
|
+
super(callTool, timeoutMs);
|
|
1225
|
+
this.rest = restTransport;
|
|
1226
|
+
}
|
|
1227
|
+
cursorToPaginatedResult(response, fetchNext, pageNumber = 1) {
|
|
1228
|
+
const items = response.results ?? [];
|
|
1229
|
+
const hasMore = Boolean(response.has_more);
|
|
1230
|
+
const nextCursor = response.next_page_cursor ?? null;
|
|
1231
|
+
const pagination = {
|
|
1232
|
+
tableName: null,
|
|
1233
|
+
totalRows: 0,
|
|
1234
|
+
totalPages: hasMore ? pageNumber + 1 : pageNumber,
|
|
1235
|
+
pageNumber,
|
|
1236
|
+
pageSize: items.length,
|
|
1237
|
+
resultsCount: items.length
|
|
1238
|
+
};
|
|
1239
|
+
const fetchPage = async () => {
|
|
1240
|
+
if (!nextCursor) {
|
|
1241
|
+
throw new RangeError("No more pages available");
|
|
1242
|
+
}
|
|
1243
|
+
const nextResponse = await fetchNext(nextCursor);
|
|
1244
|
+
return this.cursorToPaginatedResult(nextResponse, fetchNext, pageNumber + 1);
|
|
1245
|
+
};
|
|
1246
|
+
return new PaginatedResult({
|
|
1247
|
+
data: items,
|
|
1248
|
+
pagination,
|
|
1249
|
+
tableName: null,
|
|
1250
|
+
exportOperationId: null,
|
|
1251
|
+
fetchPage: () => fetchPage(),
|
|
1252
|
+
fetchExport: null
|
|
1253
|
+
});
|
|
1254
|
+
}
|
|
1031
1255
|
async getPostsByIds(postIds, options = {}) {
|
|
1032
|
-
const
|
|
1033
|
-
const
|
|
1034
|
-
|
|
1256
|
+
const fieldsCsv = csvFields(options.fields);
|
|
1257
|
+
const results = await parallelMap(postIds, async (postId) => {
|
|
1258
|
+
const response = await this.rest.get(
|
|
1259
|
+
INSTAGRAM_LIVE_ROUTES.post(postId),
|
|
1260
|
+
{ fields: fieldsCsv }
|
|
1261
|
+
);
|
|
1262
|
+
return (response.results ?? [])[0] ?? null;
|
|
1263
|
+
});
|
|
1264
|
+
return results.filter((post) => post !== null);
|
|
1035
1265
|
}
|
|
1036
1266
|
async getPostsByUser(identifier, options = {}) {
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
result,
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1267
|
+
if (options.responseType === "csv" /* Csv */) {
|
|
1268
|
+
const args = this.buildArgs({
|
|
1269
|
+
identifier,
|
|
1270
|
+
identifierType: options.identifierType ?? "username",
|
|
1271
|
+
fields: options.fields,
|
|
1272
|
+
startDate: options.startDate,
|
|
1273
|
+
endDate: options.endDate,
|
|
1274
|
+
forceLatest: options.forceLatest,
|
|
1275
|
+
responseType: options.responseType,
|
|
1276
|
+
limit: options.limit
|
|
1277
|
+
});
|
|
1278
|
+
const result = await this.callAndMaybePoll(GET_INSTAGRAM_POSTS_BY_USER, args);
|
|
1279
|
+
return this.buildPaginatedResult(result, parsePost, GET_INSTAGRAM_POSTS_BY_USER, args);
|
|
1280
|
+
}
|
|
1281
|
+
const params = {
|
|
1282
|
+
fields: csvFields(options.fields)
|
|
1283
|
+
};
|
|
1284
|
+
const response = await this.rest.get(
|
|
1285
|
+
INSTAGRAM_LIVE_ROUTES.userPosts(identifier),
|
|
1286
|
+
params
|
|
1287
|
+
);
|
|
1288
|
+
return this.cursorToPaginatedResult(
|
|
1289
|
+
response,
|
|
1290
|
+
(cursor) => this.rest.get(
|
|
1291
|
+
INSTAGRAM_LIVE_ROUTES.userPosts(identifier),
|
|
1292
|
+
{ ...params, cursor }
|
|
1293
|
+
)
|
|
1053
1294
|
);
|
|
1054
1295
|
}
|
|
1055
1296
|
async searchPosts(query, options = {}) {
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1297
|
+
if (options.responseType === "csv" /* Csv */) {
|
|
1298
|
+
const args = this.buildArgs({
|
|
1299
|
+
query,
|
|
1300
|
+
fields: options.fields,
|
|
1301
|
+
startDate: options.startDate,
|
|
1302
|
+
endDate: options.endDate,
|
|
1303
|
+
forceLatest: options.forceLatest,
|
|
1304
|
+
responseType: options.responseType,
|
|
1305
|
+
limit: options.limit
|
|
1306
|
+
});
|
|
1307
|
+
const result = await this.callAndMaybePoll(SEARCH_INSTAGRAM_POSTS, args);
|
|
1308
|
+
return this.buildPaginatedResult(result, parsePost, SEARCH_INSTAGRAM_POSTS, args);
|
|
1309
|
+
}
|
|
1310
|
+
const params = {
|
|
1311
|
+
q: query,
|
|
1312
|
+
fields: csvFields(options.fields)
|
|
1313
|
+
};
|
|
1314
|
+
const response = await this.rest.get(
|
|
1315
|
+
INSTAGRAM_LIVE_ROUTES.posts,
|
|
1316
|
+
params
|
|
1317
|
+
);
|
|
1318
|
+
return this.cursorToPaginatedResult(
|
|
1319
|
+
response,
|
|
1320
|
+
(cursor) => this.rest.get(
|
|
1321
|
+
INSTAGRAM_LIVE_ROUTES.posts,
|
|
1322
|
+
{ ...params, cursor }
|
|
1323
|
+
)
|
|
1324
|
+
);
|
|
1067
1325
|
}
|
|
1068
1326
|
async getComments(postId, options = {}) {
|
|
1069
|
-
const
|
|
1070
|
-
|
|
1071
|
-
|
|
1327
|
+
const params = {
|
|
1328
|
+
fields: csvFields(options.fields)
|
|
1329
|
+
};
|
|
1330
|
+
const response = await this.rest.get(
|
|
1331
|
+
INSTAGRAM_LIVE_ROUTES.postComments(postId),
|
|
1332
|
+
params
|
|
1333
|
+
);
|
|
1334
|
+
return this.cursorToPaginatedResult(
|
|
1335
|
+
response,
|
|
1336
|
+
(cursor) => this.rest.get(
|
|
1337
|
+
INSTAGRAM_LIVE_ROUTES.postComments(postId),
|
|
1338
|
+
{ ...params, cursor }
|
|
1339
|
+
)
|
|
1340
|
+
);
|
|
1072
1341
|
}
|
|
1073
1342
|
async getUser(identifier, options = {}) {
|
|
1074
|
-
const
|
|
1075
|
-
identifier,
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
if (
|
|
1083
|
-
return results[0];
|
|
1343
|
+
const response = await this.rest.get(
|
|
1344
|
+
INSTAGRAM_ROUTES.user(identifier),
|
|
1345
|
+
{
|
|
1346
|
+
identifierType: options.identifierType ?? "username",
|
|
1347
|
+
fields: csvFields(options.fields),
|
|
1348
|
+
forceLatest: true
|
|
1349
|
+
}
|
|
1350
|
+
);
|
|
1351
|
+
if (response.results.length > 0) {
|
|
1352
|
+
return response.results[0];
|
|
1084
1353
|
}
|
|
1085
|
-
|
|
1354
|
+
throw new Error(`User not found: ${identifier}`);
|
|
1086
1355
|
}
|
|
1087
1356
|
async searchUsers(name, options = {}) {
|
|
1088
|
-
const
|
|
1089
|
-
|
|
1090
|
-
|
|
1357
|
+
const response = await this.rest.get(
|
|
1358
|
+
INSTAGRAM_LIVE_ROUTES.users,
|
|
1359
|
+
{
|
|
1360
|
+
name,
|
|
1361
|
+
fields: csvFields(options.fields)
|
|
1362
|
+
}
|
|
1363
|
+
);
|
|
1364
|
+
const users = response.results ?? [];
|
|
1365
|
+
if (options.limit && options.limit > 0) {
|
|
1366
|
+
return users.slice(0, options.limit);
|
|
1367
|
+
}
|
|
1368
|
+
return users;
|
|
1091
1369
|
}
|
|
1092
1370
|
async getUserConnections(username, connectionType, options = {}) {
|
|
1093
|
-
const
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1371
|
+
const params = {
|
|
1372
|
+
connectionType,
|
|
1373
|
+
fields: csvFields(options.fields)
|
|
1374
|
+
};
|
|
1375
|
+
const response = await this.rest.get(
|
|
1376
|
+
INSTAGRAM_LIVE_ROUTES.userConnections(username),
|
|
1377
|
+
params
|
|
1378
|
+
);
|
|
1379
|
+
return this.cursorToPaginatedResult(
|
|
1380
|
+
response,
|
|
1381
|
+
(cursor) => this.rest.get(
|
|
1382
|
+
INSTAGRAM_LIVE_ROUTES.userConnections(username),
|
|
1383
|
+
{ ...params, cursor }
|
|
1384
|
+
)
|
|
1100
1385
|
);
|
|
1101
1386
|
}
|
|
1102
1387
|
async getPostInteractingUsers(postId, interactionType, options = {}) {
|
|
1103
|
-
const
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1388
|
+
const params = {
|
|
1389
|
+
interactionType,
|
|
1390
|
+
fields: csvFields(options.fields)
|
|
1391
|
+
};
|
|
1392
|
+
const response = await this.rest.get(
|
|
1393
|
+
INSTAGRAM_LIVE_ROUTES.postInteractingUsers(postId),
|
|
1394
|
+
params
|
|
1107
1395
|
);
|
|
1108
|
-
return this.
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1396
|
+
return this.cursorToPaginatedResult(
|
|
1397
|
+
response,
|
|
1398
|
+
(cursor) => this.rest.get(
|
|
1399
|
+
INSTAGRAM_LIVE_ROUTES.postInteractingUsers(postId),
|
|
1400
|
+
{ ...params, cursor }
|
|
1401
|
+
)
|
|
1113
1402
|
);
|
|
1114
1403
|
}
|
|
1115
1404
|
async getUsersByKeywords(query, options = {}) {
|
|
@@ -1131,7 +1420,7 @@ function parsePost2(item) {
|
|
|
1131
1420
|
function parseUser3(item) {
|
|
1132
1421
|
return item;
|
|
1133
1422
|
}
|
|
1134
|
-
function
|
|
1423
|
+
function parseComment(item) {
|
|
1135
1424
|
return item;
|
|
1136
1425
|
}
|
|
1137
1426
|
function parseSubreddit(item) {
|
|
@@ -1151,7 +1440,7 @@ var RedditNamespace = class extends BaseNamespace {
|
|
|
1151
1440
|
async searchComments(query, options = {}) {
|
|
1152
1441
|
const args = this.buildArgs({ query, ...options });
|
|
1153
1442
|
const result = await this.callAndMaybePoll(SEARCH_REDDIT_COMMENTS, args);
|
|
1154
|
-
return this.buildPaginatedResult(result,
|
|
1443
|
+
return this.buildPaginatedResult(result, parseComment, SEARCH_REDDIT_COMMENTS, args);
|
|
1155
1444
|
}
|
|
1156
1445
|
async getCommentById(commentId, options = {}) {
|
|
1157
1446
|
const args = this.buildArgs({ commentId, ...options });
|
|
@@ -1216,7 +1505,7 @@ var RedditNamespace = class extends BaseNamespace {
|
|
|
1216
1505
|
const pagination = this.extractPagination(raw);
|
|
1217
1506
|
return {
|
|
1218
1507
|
post: postData,
|
|
1219
|
-
comments: commentsData.map(
|
|
1508
|
+
comments: commentsData.map(parseComment),
|
|
1220
1509
|
commentsPagination: pagination.totalPages > 0 ? pagination : null,
|
|
1221
1510
|
commentsTableName: pagination.tableName ?? null
|
|
1222
1511
|
};
|
|
@@ -1245,7 +1534,7 @@ function parsePost3(item) {
|
|
|
1245
1534
|
function parseUser4(item) {
|
|
1246
1535
|
return item;
|
|
1247
1536
|
}
|
|
1248
|
-
function
|
|
1537
|
+
function parseComment2(item) {
|
|
1249
1538
|
return item;
|
|
1250
1539
|
}
|
|
1251
1540
|
function parseSound(item) {
|
|
@@ -1292,7 +1581,7 @@ var TiktokNamespace = class extends BaseNamespace {
|
|
|
1292
1581
|
async getComments(postId, options = {}) {
|
|
1293
1582
|
const args = this.buildArgs({ postId, ...options });
|
|
1294
1583
|
const result = await this.callAndMaybePoll(GET_TIKTOK_COMMENTS, args);
|
|
1295
|
-
return this.buildPaginatedResult(result,
|
|
1584
|
+
return this.buildPaginatedResult(result, parseComment2, GET_TIKTOK_COMMENTS, args);
|
|
1296
1585
|
}
|
|
1297
1586
|
async getUser(identifier, options = {}) {
|
|
1298
1587
|
const args = this.buildArgs({
|
|
@@ -1438,6 +1727,7 @@ var XpozClient = class {
|
|
|
1438
1727
|
versionCheck;
|
|
1439
1728
|
restTransport;
|
|
1440
1729
|
instagramLiveNamespace;
|
|
1730
|
+
twitterLiveNamespace;
|
|
1441
1731
|
constructor(options = {}) {
|
|
1442
1732
|
const apiKey = options.apiKey ?? process.env[ENV_API_KEY];
|
|
1443
1733
|
if (!apiKey) {
|
|
@@ -1452,8 +1742,8 @@ var XpozClient = class {
|
|
|
1452
1742
|
const apiUrl = options.apiUrl ?? process.env[ENV_API_URL] ?? DEFAULT_API_URL;
|
|
1453
1743
|
this.restTransport = new RestTransport(apiUrl, apiKey);
|
|
1454
1744
|
const callTool = this.transport.callTool.bind(this.transport);
|
|
1455
|
-
this.twitter = new TwitterNamespace(callTool, timeoutMs);
|
|
1456
|
-
this.instagram = new InstagramNamespace(callTool, timeoutMs);
|
|
1745
|
+
this.twitter = new TwitterNamespace(callTool, timeoutMs, this.restTransport);
|
|
1746
|
+
this.instagram = new InstagramNamespace(callTool, timeoutMs, this.restTransport);
|
|
1457
1747
|
this.reddit = new RedditNamespace(callTool, timeoutMs);
|
|
1458
1748
|
this.tiktok = new TiktokNamespace(callTool, timeoutMs);
|
|
1459
1749
|
this.tracking = new TrackingNamespace(callTool, timeoutMs);
|
|
@@ -1465,6 +1755,12 @@ var XpozClient = class {
|
|
|
1465
1755
|
}
|
|
1466
1756
|
return this.instagramLiveNamespace;
|
|
1467
1757
|
}
|
|
1758
|
+
get twitterLive() {
|
|
1759
|
+
if (!this.twitterLiveNamespace) {
|
|
1760
|
+
this.twitterLiveNamespace = new TwitterLiveNamespace(this.restTransport);
|
|
1761
|
+
}
|
|
1762
|
+
return this.twitterLiveNamespace;
|
|
1763
|
+
}
|
|
1468
1764
|
async connect() {
|
|
1469
1765
|
await this.transport.connect();
|
|
1470
1766
|
if (this.versionCheck) {
|