@xpoz/xpoz 0.7.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -34
- package/dist/index.cjs +393 -186
- package/dist/index.d.cts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +393 -186
- 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.1";
|
|
305
305
|
|
|
306
306
|
// src/mcp/transport.ts
|
|
307
307
|
var USER_AGENT = `xpoz-ts-sdk/${VERSION}`;
|
|
@@ -455,6 +455,10 @@ 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
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
|
+
};
|
|
458
462
|
var INSTAGRAM_LIVE_ROUTES = {
|
|
459
463
|
posts: `${INSTAGRAM_BASE}/posts/live`,
|
|
460
464
|
userPosts: (identifier) => `${INSTAGRAM_BASE}/posts/users/${encodeURIComponent(identifier)}/live`,
|
|
@@ -465,6 +469,9 @@ var INSTAGRAM_LIVE_ROUTES = {
|
|
|
465
469
|
user: (identifier) => `${INSTAGRAM_BASE}/users/${encodeURIComponent(identifier)}/live`,
|
|
466
470
|
userConnections: (identifier) => `${INSTAGRAM_BASE}/users/${encodeURIComponent(identifier)}/connections/live`
|
|
467
471
|
};
|
|
472
|
+
var TWITTER_ROUTES = {
|
|
473
|
+
posts: `${TWITTER_BASE}/posts`
|
|
474
|
+
};
|
|
468
475
|
var TWITTER_LIVE_ROUTES = {
|
|
469
476
|
posts: `${TWITTER_BASE}/posts/live`,
|
|
470
477
|
userPosts: (username) => `${TWITTER_BASE}/posts/users/${encodeURIComponent(username)}/live`,
|
|
@@ -912,28 +919,36 @@ var BaseNamespace = class {
|
|
|
912
919
|
}
|
|
913
920
|
};
|
|
914
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
|
+
|
|
915
941
|
// src/config/tools.ts
|
|
916
|
-
var GET_TWITTER_POSTS_BY_IDS = "getTwitterPostsByIds";
|
|
917
942
|
var GET_TWITTER_POSTS_BY_AUTHOR = "getTwitterPostsByAuthor";
|
|
918
943
|
var SEARCH_TWITTER_POSTS = "getTwitterPostsByKeywords";
|
|
919
944
|
var GET_TWITTER_RETWEETS = "getTwitterPostRetweets";
|
|
920
|
-
var GET_TWITTER_QUOTES = "getTwitterPostQuotes";
|
|
921
|
-
var GET_TWITTER_COMMENTS = "getTwitterPostComments";
|
|
922
|
-
var GET_TWITTER_POST_INTERACTING_USERS = "getTwitterPostInteractingUsers";
|
|
923
945
|
var COUNT_TWEETS = "countTweets";
|
|
924
946
|
var GET_TWITTER_USER = "getTwitterUser";
|
|
925
947
|
var GET_TWITTER_USERS = "getTwitterUsers";
|
|
926
|
-
var SEARCH_TWITTER_USERS = "searchTwitterUsers";
|
|
927
948
|
var GET_TWITTER_USER_CONNECTIONS = "getTwitterUserConnections";
|
|
928
949
|
var GET_TWITTER_USERS_BY_KEYWORDS = "getTwitterUsersByKeywords";
|
|
929
|
-
var GET_INSTAGRAM_POSTS_BY_IDS = "getInstagramPostsByIds";
|
|
930
950
|
var GET_INSTAGRAM_POSTS_BY_USER = "getInstagramPostsByUser";
|
|
931
951
|
var SEARCH_INSTAGRAM_POSTS = "getInstagramPostsByKeywords";
|
|
932
|
-
var GET_INSTAGRAM_COMMENTS = "getInstagramCommentsByPostId";
|
|
933
|
-
var GET_INSTAGRAM_USER = "getInstagramUser";
|
|
934
|
-
var SEARCH_INSTAGRAM_USERS = "searchInstagramUsers";
|
|
935
|
-
var GET_INSTAGRAM_USER_CONNECTIONS = "getInstagramUserConnections";
|
|
936
|
-
var GET_INSTAGRAM_POST_INTERACTING_USERS = "getInstagramPostInteractingUsers";
|
|
937
952
|
var GET_INSTAGRAM_USERS_BY_KEYWORDS = "getInstagramUsersByKeywords";
|
|
938
953
|
var SEARCH_REDDIT_POSTS = "getRedditPostsByKeywords";
|
|
939
954
|
var GET_REDDIT_POST_WITH_COMMENTS = "getRedditPostWithCommentsById";
|
|
@@ -970,50 +985,96 @@ function parseUser(item) {
|
|
|
970
985
|
return item;
|
|
971
986
|
}
|
|
972
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
|
+
}
|
|
973
1021
|
async getPostsByIds(postIds, options = {}) {
|
|
974
|
-
const
|
|
975
|
-
const
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
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);
|
|
980
1031
|
}
|
|
981
1032
|
async getPostsByAuthor(identifier, options = {}) {
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
GET_TWITTER_POSTS_BY_AUTHOR,
|
|
993
|
-
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
|
|
994
1054
|
);
|
|
995
|
-
return this.
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1055
|
+
return this.cursorToPaginatedResult(
|
|
1056
|
+
response,
|
|
1057
|
+
(cursor) => this.rest.get(
|
|
1058
|
+
TWITTER_LIVE_ROUTES.userPosts(identifier),
|
|
1059
|
+
{ ...params, cursor }
|
|
1060
|
+
)
|
|
1000
1061
|
);
|
|
1001
1062
|
}
|
|
1002
1063
|
async searchPosts(query, options = {}) {
|
|
1003
|
-
const args = this.buildArgs({
|
|
1004
|
-
query,
|
|
1005
|
-
fields: options.fields,
|
|
1006
|
-
startDate: options.startDate,
|
|
1007
|
-
endDate: options.endDate,
|
|
1008
|
-
authorUsername: options.authorUsername,
|
|
1009
|
-
authorId: options.authorId,
|
|
1010
|
-
language: options.language,
|
|
1011
|
-
filterOutRetweets: options.filterOutRetweets,
|
|
1012
|
-
forceLatest: options.forceLatest,
|
|
1013
|
-
responseType: options.responseType,
|
|
1014
|
-
limit: options.limit
|
|
1015
|
-
});
|
|
1016
1064
|
if (options.responseType === "csv" /* Csv */) {
|
|
1065
|
+
const args = this.buildArgs({
|
|
1066
|
+
query,
|
|
1067
|
+
fields: options.fields,
|
|
1068
|
+
startDate: options.startDate,
|
|
1069
|
+
endDate: options.endDate,
|
|
1070
|
+
authorUsername: options.authorUsername,
|
|
1071
|
+
authorId: options.authorId,
|
|
1072
|
+
language: options.language,
|
|
1073
|
+
filterOutRetweets: options.filterOutRetweets,
|
|
1074
|
+
forceLatest: options.forceLatest,
|
|
1075
|
+
responseType: options.responseType,
|
|
1076
|
+
limit: options.limit
|
|
1077
|
+
});
|
|
1017
1078
|
const raw = await this.callTool(SEARCH_TWITTER_POSTS, args);
|
|
1018
1079
|
const exportOpId = raw["operationId"] ?? raw["dataDumpExportOperationId"] ?? null;
|
|
1019
1080
|
const csvRaw = {
|
|
@@ -1027,15 +1088,24 @@ var TwitterNamespace = class extends BaseNamespace {
|
|
|
1027
1088
|
args
|
|
1028
1089
|
);
|
|
1029
1090
|
}
|
|
1030
|
-
const
|
|
1031
|
-
|
|
1032
|
-
|
|
1091
|
+
const params = {
|
|
1092
|
+
q: query,
|
|
1093
|
+
since: options.startDate,
|
|
1094
|
+
until: options.endDate,
|
|
1095
|
+
username: options.authorUsername,
|
|
1096
|
+
lang: options.language,
|
|
1097
|
+
fields: csvFields(options.fields)
|
|
1098
|
+
};
|
|
1099
|
+
const response = await this.rest.get(
|
|
1100
|
+
TWITTER_LIVE_ROUTES.posts,
|
|
1101
|
+
params
|
|
1033
1102
|
);
|
|
1034
|
-
return this.
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1103
|
+
return this.cursorToPaginatedResult(
|
|
1104
|
+
response,
|
|
1105
|
+
(cursor) => this.rest.get(
|
|
1106
|
+
TWITTER_LIVE_ROUTES.posts,
|
|
1107
|
+
{ ...params, cursor }
|
|
1108
|
+
)
|
|
1039
1109
|
);
|
|
1040
1110
|
}
|
|
1041
1111
|
async getRetweets(postId, options = {}) {
|
|
@@ -1052,39 +1122,48 @@ var TwitterNamespace = class extends BaseNamespace {
|
|
|
1052
1122
|
);
|
|
1053
1123
|
}
|
|
1054
1124
|
async getQuotes(postId, options = {}) {
|
|
1055
|
-
const
|
|
1056
|
-
const
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1125
|
+
const params = { fields: csvFields(options.fields) };
|
|
1126
|
+
const response = await this.rest.get(
|
|
1127
|
+
TWITTER_LIVE_ROUTES.postQuotes(postId),
|
|
1128
|
+
params
|
|
1129
|
+
);
|
|
1130
|
+
return this.cursorToPaginatedResult(
|
|
1131
|
+
response,
|
|
1132
|
+
(cursor) => this.rest.get(
|
|
1133
|
+
TWITTER_LIVE_ROUTES.postQuotes(postId),
|
|
1134
|
+
{ ...params, cursor }
|
|
1135
|
+
)
|
|
1062
1136
|
);
|
|
1063
1137
|
}
|
|
1064
1138
|
async getComments(postId, options = {}) {
|
|
1065
|
-
const
|
|
1066
|
-
const
|
|
1067
|
-
|
|
1068
|
-
|
|
1139
|
+
const params = { fields: csvFields(options.fields) };
|
|
1140
|
+
const response = await this.rest.get(
|
|
1141
|
+
TWITTER_LIVE_ROUTES.postComments(postId),
|
|
1142
|
+
params
|
|
1069
1143
|
);
|
|
1070
|
-
return this.
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1144
|
+
return this.cursorToPaginatedResult(
|
|
1145
|
+
response,
|
|
1146
|
+
(cursor) => this.rest.get(
|
|
1147
|
+
TWITTER_LIVE_ROUTES.postComments(postId),
|
|
1148
|
+
{ ...params, cursor }
|
|
1149
|
+
)
|
|
1075
1150
|
);
|
|
1076
1151
|
}
|
|
1077
1152
|
async getPostInteractingUsers(postId, interactionType, options = {}) {
|
|
1078
|
-
const
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1153
|
+
const params = {
|
|
1154
|
+
interactionType,
|
|
1155
|
+
fields: csvFields(options.fields)
|
|
1156
|
+
};
|
|
1157
|
+
const response = await this.rest.get(
|
|
1158
|
+
TWITTER_LIVE_ROUTES.postInteractingUsers(postId),
|
|
1159
|
+
params
|
|
1082
1160
|
);
|
|
1083
|
-
return this.
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1161
|
+
return this.cursorToPaginatedResult(
|
|
1162
|
+
response,
|
|
1163
|
+
(cursor) => this.rest.get(
|
|
1164
|
+
TWITTER_LIVE_ROUTES.postInteractingUsers(postId),
|
|
1165
|
+
{ ...params, cursor }
|
|
1166
|
+
)
|
|
1088
1167
|
);
|
|
1089
1168
|
}
|
|
1090
1169
|
async countPosts(phrase, options = {}) {
|
|
@@ -1102,48 +1181,81 @@ var TwitterNamespace = class extends BaseNamespace {
|
|
|
1102
1181
|
return Number(count);
|
|
1103
1182
|
}
|
|
1104
1183
|
async getUsers(identifiers, options = {}) {
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1184
|
+
if ((options.identifierType ?? "username") === "id") {
|
|
1185
|
+
const args = this.buildArgs({
|
|
1186
|
+
identifiers,
|
|
1187
|
+
identifierType: "id",
|
|
1188
|
+
fields: options.fields,
|
|
1189
|
+
forceLatest: options.forceLatest
|
|
1190
|
+
});
|
|
1191
|
+
const result = await this.callAndMaybePoll(GET_TWITTER_USERS, args);
|
|
1192
|
+
return (result["results"] ?? []).map(parseUser);
|
|
1193
|
+
}
|
|
1194
|
+
const fieldsCsv = csvFields(options.fields);
|
|
1195
|
+
const results = await parallelMap(identifiers, async (username) => {
|
|
1196
|
+
const response = await this.rest.get(
|
|
1197
|
+
TWITTER_LIVE_ROUTES.user(username),
|
|
1198
|
+
{ fields: fieldsCsv }
|
|
1199
|
+
);
|
|
1200
|
+
return (response.results ?? [])[0] ?? null;
|
|
1110
1201
|
});
|
|
1111
|
-
|
|
1112
|
-
return (result["results"] ?? []).map(parseUser);
|
|
1202
|
+
return results.filter((user) => user !== null);
|
|
1113
1203
|
}
|
|
1114
1204
|
async getUser(identifier, options = {}) {
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1205
|
+
if ((options.identifierType ?? "username") === "id") {
|
|
1206
|
+
const args = this.buildArgs({
|
|
1207
|
+
identifier,
|
|
1208
|
+
identifierType: "id",
|
|
1209
|
+
fields: options.fields,
|
|
1210
|
+
forceLatest: options.forceLatest
|
|
1211
|
+
});
|
|
1212
|
+
const result = await this.callAndMaybePoll(GET_TWITTER_USER, args);
|
|
1213
|
+
const results = result["results"];
|
|
1214
|
+
if (Array.isArray(results) && results.length > 0) {
|
|
1215
|
+
return results[0];
|
|
1216
|
+
}
|
|
1217
|
+
return result;
|
|
1125
1218
|
}
|
|
1126
|
-
|
|
1219
|
+
const response = await this.rest.get(
|
|
1220
|
+
TWITTER_LIVE_ROUTES.user(identifier),
|
|
1221
|
+
{ fields: csvFields(options.fields) }
|
|
1222
|
+
);
|
|
1223
|
+
if (response.results && response.results.length > 0) {
|
|
1224
|
+
return response.results[0];
|
|
1225
|
+
}
|
|
1226
|
+
throw new Error(`User not found: ${identifier}`);
|
|
1127
1227
|
}
|
|
1128
1228
|
async searchUsers(name, options = {}) {
|
|
1129
|
-
const
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
args
|
|
1229
|
+
const response = await this.rest.get(
|
|
1230
|
+
TWITTER_LIVE_ROUTES.users,
|
|
1231
|
+
{ q: name, fields: csvFields(options.fields) }
|
|
1133
1232
|
);
|
|
1134
|
-
|
|
1233
|
+
const users = response.results ?? [];
|
|
1234
|
+
if (options.limit && options.limit > 0) {
|
|
1235
|
+
return users.slice(0, options.limit);
|
|
1236
|
+
}
|
|
1237
|
+
return users;
|
|
1135
1238
|
}
|
|
1136
1239
|
async getUserConnections(username, connectionType, options = {}) {
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
GET_TWITTER_USER_CONNECTIONS,
|
|
1140
|
-
args
|
|
1240
|
+
if (options.responseType === "csv" /* Csv */) {
|
|
1241
|
+
const args = this.buildArgs({ username, connectionType, ...options });
|
|
1242
|
+
const result = await this.callAndMaybePoll(GET_TWITTER_USER_CONNECTIONS, args);
|
|
1243
|
+
return this.buildPaginatedResult(result, parseUser, GET_TWITTER_USER_CONNECTIONS, args);
|
|
1244
|
+
}
|
|
1245
|
+
const params = {
|
|
1246
|
+
connectionType,
|
|
1247
|
+
fields: csvFields(options.fields)
|
|
1248
|
+
};
|
|
1249
|
+
const response = await this.rest.get(
|
|
1250
|
+
TWITTER_LIVE_ROUTES.userConnections(username),
|
|
1251
|
+
params
|
|
1141
1252
|
);
|
|
1142
|
-
return this.
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1253
|
+
return this.cursorToPaginatedResult(
|
|
1254
|
+
response,
|
|
1255
|
+
(cursor) => this.rest.get(
|
|
1256
|
+
TWITTER_LIVE_ROUTES.userConnections(username),
|
|
1257
|
+
{ ...params, cursor }
|
|
1258
|
+
)
|
|
1147
1259
|
);
|
|
1148
1260
|
}
|
|
1149
1261
|
async getUsersByKeywords(query, options = {}) {
|
|
@@ -1168,92 +1280,187 @@ function parsePost(item) {
|
|
|
1168
1280
|
function parseUser2(item) {
|
|
1169
1281
|
return item;
|
|
1170
1282
|
}
|
|
1171
|
-
function parseComment(item) {
|
|
1172
|
-
return item;
|
|
1173
|
-
}
|
|
1174
1283
|
var InstagramNamespace = class extends BaseNamespace {
|
|
1284
|
+
rest;
|
|
1285
|
+
constructor(callTool, timeoutMs, restTransport) {
|
|
1286
|
+
super(callTool, timeoutMs);
|
|
1287
|
+
this.rest = restTransport;
|
|
1288
|
+
}
|
|
1289
|
+
cursorToPaginatedResult(response, fetchNext, pageNumber = 1) {
|
|
1290
|
+
const items = response.results ?? [];
|
|
1291
|
+
const hasMore = Boolean(response.has_more);
|
|
1292
|
+
const nextCursor = response.next_page_cursor ?? null;
|
|
1293
|
+
const pagination = {
|
|
1294
|
+
tableName: null,
|
|
1295
|
+
totalRows: 0,
|
|
1296
|
+
totalPages: hasMore ? pageNumber + 1 : pageNumber,
|
|
1297
|
+
pageNumber,
|
|
1298
|
+
pageSize: items.length,
|
|
1299
|
+
resultsCount: items.length
|
|
1300
|
+
};
|
|
1301
|
+
const fetchPage = async () => {
|
|
1302
|
+
if (!nextCursor) {
|
|
1303
|
+
throw new RangeError("No more pages available");
|
|
1304
|
+
}
|
|
1305
|
+
const nextResponse = await fetchNext(nextCursor);
|
|
1306
|
+
return this.cursorToPaginatedResult(nextResponse, fetchNext, pageNumber + 1);
|
|
1307
|
+
};
|
|
1308
|
+
return new PaginatedResult({
|
|
1309
|
+
data: items,
|
|
1310
|
+
pagination,
|
|
1311
|
+
tableName: null,
|
|
1312
|
+
exportOperationId: null,
|
|
1313
|
+
fetchPage: () => fetchPage(),
|
|
1314
|
+
fetchExport: null
|
|
1315
|
+
});
|
|
1316
|
+
}
|
|
1175
1317
|
async getPostsByIds(postIds, options = {}) {
|
|
1176
|
-
const
|
|
1177
|
-
const
|
|
1178
|
-
|
|
1318
|
+
const fieldsCsv = csvFields(options.fields);
|
|
1319
|
+
const results = await parallelMap(postIds, async (postId) => {
|
|
1320
|
+
const response = await this.rest.get(
|
|
1321
|
+
INSTAGRAM_LIVE_ROUTES.post(postId),
|
|
1322
|
+
{ fields: fieldsCsv }
|
|
1323
|
+
);
|
|
1324
|
+
return (response.results ?? [])[0] ?? null;
|
|
1325
|
+
});
|
|
1326
|
+
return results.filter((post) => post !== null);
|
|
1179
1327
|
}
|
|
1180
1328
|
async getPostsByUser(identifier, options = {}) {
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
result,
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1329
|
+
if (options.responseType === "csv" /* Csv */) {
|
|
1330
|
+
const args = this.buildArgs({
|
|
1331
|
+
identifier,
|
|
1332
|
+
identifierType: options.identifierType ?? "username",
|
|
1333
|
+
fields: options.fields,
|
|
1334
|
+
startDate: options.startDate,
|
|
1335
|
+
endDate: options.endDate,
|
|
1336
|
+
forceLatest: options.forceLatest,
|
|
1337
|
+
responseType: options.responseType,
|
|
1338
|
+
limit: options.limit
|
|
1339
|
+
});
|
|
1340
|
+
const result = await this.callAndMaybePoll(GET_INSTAGRAM_POSTS_BY_USER, args);
|
|
1341
|
+
return this.buildPaginatedResult(result, parsePost, GET_INSTAGRAM_POSTS_BY_USER, args);
|
|
1342
|
+
}
|
|
1343
|
+
const params = {
|
|
1344
|
+
fields: csvFields(options.fields)
|
|
1345
|
+
};
|
|
1346
|
+
const response = await this.rest.get(
|
|
1347
|
+
INSTAGRAM_LIVE_ROUTES.userPosts(identifier),
|
|
1348
|
+
params
|
|
1349
|
+
);
|
|
1350
|
+
return this.cursorToPaginatedResult(
|
|
1351
|
+
response,
|
|
1352
|
+
(cursor) => this.rest.get(
|
|
1353
|
+
INSTAGRAM_LIVE_ROUTES.userPosts(identifier),
|
|
1354
|
+
{ ...params, cursor }
|
|
1355
|
+
)
|
|
1197
1356
|
);
|
|
1198
1357
|
}
|
|
1199
1358
|
async searchPosts(query, options = {}) {
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1359
|
+
if (options.responseType === "csv" /* Csv */) {
|
|
1360
|
+
const args = this.buildArgs({
|
|
1361
|
+
query,
|
|
1362
|
+
fields: options.fields,
|
|
1363
|
+
startDate: options.startDate,
|
|
1364
|
+
endDate: options.endDate,
|
|
1365
|
+
forceLatest: options.forceLatest,
|
|
1366
|
+
responseType: options.responseType,
|
|
1367
|
+
limit: options.limit
|
|
1368
|
+
});
|
|
1369
|
+
const result = await this.callAndMaybePoll(SEARCH_INSTAGRAM_POSTS, args);
|
|
1370
|
+
return this.buildPaginatedResult(result, parsePost, SEARCH_INSTAGRAM_POSTS, args);
|
|
1371
|
+
}
|
|
1372
|
+
const params = {
|
|
1373
|
+
q: query,
|
|
1374
|
+
fields: csvFields(options.fields)
|
|
1375
|
+
};
|
|
1376
|
+
const response = await this.rest.get(
|
|
1377
|
+
INSTAGRAM_LIVE_ROUTES.posts,
|
|
1378
|
+
params
|
|
1379
|
+
);
|
|
1380
|
+
return this.cursorToPaginatedResult(
|
|
1381
|
+
response,
|
|
1382
|
+
(cursor) => this.rest.get(
|
|
1383
|
+
INSTAGRAM_LIVE_ROUTES.posts,
|
|
1384
|
+
{ ...params, cursor }
|
|
1385
|
+
)
|
|
1386
|
+
);
|
|
1211
1387
|
}
|
|
1212
1388
|
async getComments(postId, options = {}) {
|
|
1213
|
-
const
|
|
1214
|
-
|
|
1215
|
-
|
|
1389
|
+
const params = {
|
|
1390
|
+
fields: csvFields(options.fields)
|
|
1391
|
+
};
|
|
1392
|
+
const response = await this.rest.get(
|
|
1393
|
+
INSTAGRAM_LIVE_ROUTES.postComments(postId),
|
|
1394
|
+
params
|
|
1395
|
+
);
|
|
1396
|
+
return this.cursorToPaginatedResult(
|
|
1397
|
+
response,
|
|
1398
|
+
(cursor) => this.rest.get(
|
|
1399
|
+
INSTAGRAM_LIVE_ROUTES.postComments(postId),
|
|
1400
|
+
{ ...params, cursor }
|
|
1401
|
+
)
|
|
1402
|
+
);
|
|
1216
1403
|
}
|
|
1217
1404
|
async getUser(identifier, options = {}) {
|
|
1218
|
-
const
|
|
1219
|
-
identifier,
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
if (
|
|
1227
|
-
return results[0];
|
|
1405
|
+
const response = await this.rest.get(
|
|
1406
|
+
INSTAGRAM_ROUTES.user(identifier),
|
|
1407
|
+
{
|
|
1408
|
+
identifierType: options.identifierType ?? "username",
|
|
1409
|
+
fields: csvFields(options.fields),
|
|
1410
|
+
forceLatest: true
|
|
1411
|
+
}
|
|
1412
|
+
);
|
|
1413
|
+
if (response.results.length > 0) {
|
|
1414
|
+
return response.results[0];
|
|
1228
1415
|
}
|
|
1229
|
-
|
|
1416
|
+
throw new Error(`User not found: ${identifier}`);
|
|
1230
1417
|
}
|
|
1231
1418
|
async searchUsers(name, options = {}) {
|
|
1232
|
-
const
|
|
1233
|
-
|
|
1234
|
-
|
|
1419
|
+
const response = await this.rest.get(
|
|
1420
|
+
INSTAGRAM_LIVE_ROUTES.users,
|
|
1421
|
+
{
|
|
1422
|
+
name,
|
|
1423
|
+
fields: csvFields(options.fields)
|
|
1424
|
+
}
|
|
1425
|
+
);
|
|
1426
|
+
const users = response.results ?? [];
|
|
1427
|
+
if (options.limit && options.limit > 0) {
|
|
1428
|
+
return users.slice(0, options.limit);
|
|
1429
|
+
}
|
|
1430
|
+
return users;
|
|
1235
1431
|
}
|
|
1236
1432
|
async getUserConnections(username, connectionType, options = {}) {
|
|
1237
|
-
const
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1433
|
+
const params = {
|
|
1434
|
+
connectionType,
|
|
1435
|
+
fields: csvFields(options.fields)
|
|
1436
|
+
};
|
|
1437
|
+
const response = await this.rest.get(
|
|
1438
|
+
INSTAGRAM_LIVE_ROUTES.userConnections(username),
|
|
1439
|
+
params
|
|
1440
|
+
);
|
|
1441
|
+
return this.cursorToPaginatedResult(
|
|
1442
|
+
response,
|
|
1443
|
+
(cursor) => this.rest.get(
|
|
1444
|
+
INSTAGRAM_LIVE_ROUTES.userConnections(username),
|
|
1445
|
+
{ ...params, cursor }
|
|
1446
|
+
)
|
|
1244
1447
|
);
|
|
1245
1448
|
}
|
|
1246
1449
|
async getPostInteractingUsers(postId, interactionType, options = {}) {
|
|
1247
|
-
const
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1450
|
+
const params = {
|
|
1451
|
+
interactionType,
|
|
1452
|
+
fields: csvFields(options.fields)
|
|
1453
|
+
};
|
|
1454
|
+
const response = await this.rest.get(
|
|
1455
|
+
INSTAGRAM_LIVE_ROUTES.postInteractingUsers(postId),
|
|
1456
|
+
params
|
|
1251
1457
|
);
|
|
1252
|
-
return this.
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1458
|
+
return this.cursorToPaginatedResult(
|
|
1459
|
+
response,
|
|
1460
|
+
(cursor) => this.rest.get(
|
|
1461
|
+
INSTAGRAM_LIVE_ROUTES.postInteractingUsers(postId),
|
|
1462
|
+
{ ...params, cursor }
|
|
1463
|
+
)
|
|
1257
1464
|
);
|
|
1258
1465
|
}
|
|
1259
1466
|
async getUsersByKeywords(query, options = {}) {
|
|
@@ -1275,7 +1482,7 @@ function parsePost2(item) {
|
|
|
1275
1482
|
function parseUser3(item) {
|
|
1276
1483
|
return item;
|
|
1277
1484
|
}
|
|
1278
|
-
function
|
|
1485
|
+
function parseComment(item) {
|
|
1279
1486
|
return item;
|
|
1280
1487
|
}
|
|
1281
1488
|
function parseSubreddit(item) {
|
|
@@ -1295,7 +1502,7 @@ var RedditNamespace = class extends BaseNamespace {
|
|
|
1295
1502
|
async searchComments(query, options = {}) {
|
|
1296
1503
|
const args = this.buildArgs({ query, ...options });
|
|
1297
1504
|
const result = await this.callAndMaybePoll(SEARCH_REDDIT_COMMENTS, args);
|
|
1298
|
-
return this.buildPaginatedResult(result,
|
|
1505
|
+
return this.buildPaginatedResult(result, parseComment, SEARCH_REDDIT_COMMENTS, args);
|
|
1299
1506
|
}
|
|
1300
1507
|
async getCommentById(commentId, options = {}) {
|
|
1301
1508
|
const args = this.buildArgs({ commentId, ...options });
|
|
@@ -1360,7 +1567,7 @@ var RedditNamespace = class extends BaseNamespace {
|
|
|
1360
1567
|
const pagination = this.extractPagination(raw);
|
|
1361
1568
|
return {
|
|
1362
1569
|
post: postData,
|
|
1363
|
-
comments: commentsData.map(
|
|
1570
|
+
comments: commentsData.map(parseComment),
|
|
1364
1571
|
commentsPagination: pagination.totalPages > 0 ? pagination : null,
|
|
1365
1572
|
commentsTableName: pagination.tableName ?? null
|
|
1366
1573
|
};
|
|
@@ -1389,7 +1596,7 @@ function parsePost3(item) {
|
|
|
1389
1596
|
function parseUser4(item) {
|
|
1390
1597
|
return item;
|
|
1391
1598
|
}
|
|
1392
|
-
function
|
|
1599
|
+
function parseComment2(item) {
|
|
1393
1600
|
return item;
|
|
1394
1601
|
}
|
|
1395
1602
|
function parseSound(item) {
|
|
@@ -1436,7 +1643,7 @@ var TiktokNamespace = class extends BaseNamespace {
|
|
|
1436
1643
|
async getComments(postId, options = {}) {
|
|
1437
1644
|
const args = this.buildArgs({ postId, ...options });
|
|
1438
1645
|
const result = await this.callAndMaybePoll(GET_TIKTOK_COMMENTS, args);
|
|
1439
|
-
return this.buildPaginatedResult(result,
|
|
1646
|
+
return this.buildPaginatedResult(result, parseComment2, GET_TIKTOK_COMMENTS, args);
|
|
1440
1647
|
}
|
|
1441
1648
|
async getUser(identifier, options = {}) {
|
|
1442
1649
|
const args = this.buildArgs({
|
|
@@ -1597,8 +1804,8 @@ var XpozClient = class {
|
|
|
1597
1804
|
const apiUrl = options.apiUrl ?? process.env[ENV_API_URL] ?? DEFAULT_API_URL;
|
|
1598
1805
|
this.restTransport = new RestTransport(apiUrl, apiKey);
|
|
1599
1806
|
const callTool = this.transport.callTool.bind(this.transport);
|
|
1600
|
-
this.twitter = new TwitterNamespace(callTool, timeoutMs);
|
|
1601
|
-
this.instagram = new InstagramNamespace(callTool, timeoutMs);
|
|
1807
|
+
this.twitter = new TwitterNamespace(callTool, timeoutMs, this.restTransport);
|
|
1808
|
+
this.instagram = new InstagramNamespace(callTool, timeoutMs, this.restTransport);
|
|
1602
1809
|
this.reddit = new RedditNamespace(callTool, timeoutMs);
|
|
1603
1810
|
this.tiktok = new TiktokNamespace(callTool, timeoutMs);
|
|
1604
1811
|
this.tracking = new TrackingNamespace(callTool, timeoutMs);
|