@xpoz/xpoz 0.6.10 → 0.6.12
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 +80 -9
- package/dist/index.cjs +249 -1
- package/dist/index.d.cts +199 -100
- package/dist/index.d.ts +199 -100
- package/dist/index.js +246 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@xpoz/xpoz)
|
|
4
4
|
|
|
5
|
-
TypeScript SDK for the [Xpoz](https://xpoz.ai) social media intelligence platform. Query Twitter/X, Instagram, and
|
|
5
|
+
TypeScript SDK for the [Xpoz](https://xpoz.ai) social media intelligence platform. Query Twitter/X, Instagram, Reddit, and TikTok data through a simple, typed interface.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -24,7 +24,7 @@ export XPOZ_API_KEY=your-token-here
|
|
|
24
24
|
|
|
25
25
|
## What is Xpoz?
|
|
26
26
|
|
|
27
|
-
Xpoz provides unified access to social media data across Twitter/X, Instagram, and
|
|
27
|
+
Xpoz provides unified access to social media data across Twitter/X, Instagram, Reddit, and TikTok. The platform indexes billions of posts, user profiles, and engagement metrics — making it possible to search, analyze, and export social media data at scale.
|
|
28
28
|
|
|
29
29
|
The SDK wraps Xpoz's [MCP](https://modelcontextprotocol.io) server, abstracting away transport, authentication, operation polling, and pagination into a clean developer-friendly API.
|
|
30
30
|
|
|
@@ -154,6 +154,45 @@ const page5 = await results.getPage(5); // jump to specific page
|
|
|
154
154
|
const csvUrl = await results.exportCsv(); // returns download URL
|
|
155
155
|
```
|
|
156
156
|
|
|
157
|
+
## Live Data — `client.instagramLive`
|
|
158
|
+
|
|
159
|
+
Instagram live methods bypass the database and fetch straight from the crawler API, so results are always current. They page with an opaque **cursor** rather than page numbers, and return a `CursorResult<T>`:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
const page = await client.instagramLive.searchPosts("travel", { fields: ["id", "caption"] });
|
|
163
|
+
|
|
164
|
+
page.data; // InstagramPost[] — this page
|
|
165
|
+
page.hasMore; // another page is available upstream
|
|
166
|
+
page.nextPageCursor; // opaque token for the next call
|
|
167
|
+
page.hasNextPage(); // boolean
|
|
168
|
+
|
|
169
|
+
const next = await page.nextPage();
|
|
170
|
+
|
|
171
|
+
// Walk every page
|
|
172
|
+
for await (const post of page.items()) {
|
|
173
|
+
console.log(post.id);
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Cursor paging is forward-only: there is no `getPage(n)`, `totalPages`, or `totalRows`, because the upstream API does not report them. Drive iteration off `hasMore` and the cursor — never off the item count, since a page can be short or empty while `hasMore` is still true.
|
|
178
|
+
|
|
179
|
+
These routes talk to the Xpoz REST API rather than the MCP server, so **`connect()` is not required** to use them. Override the base URL with `new XpozClient({ apiUrl })` or the `XPOZ_API_URL` environment variable.
|
|
180
|
+
|
|
181
|
+
They always trigger a live fetch, so they are **not available on trial access** and throw `AuthenticationError` (HTTP 403).
|
|
182
|
+
|
|
183
|
+
| Method | Returns |
|
|
184
|
+
|---|---|
|
|
185
|
+
| `searchPosts(query, options?)` | `CursorResult<InstagramPost>` |
|
|
186
|
+
| `getPostsByUser(identifier, options?)` | `CursorResult<InstagramPost>` |
|
|
187
|
+
| `getPost(postId, options?)` | `InstagramPost \| null` |
|
|
188
|
+
| `getComments(postId, options?)` | `CursorResult<InstagramComment>` |
|
|
189
|
+
| `getPostInteractingUsers(postId, interactionType, options?)` | `CursorResult<InstagramUser>` |
|
|
190
|
+
| `searchUsers(name, options?)` | `CursorResult<InstagramUser>` |
|
|
191
|
+
| `getUser(identifier, options?)` | `InstagramUser \| null` |
|
|
192
|
+
| `getUserConnections(identifier, connectionType, options?)` | `CursorResult<InstagramUser>` |
|
|
193
|
+
|
|
194
|
+
`interactionType` is `"commenters"` or `"likers"`; `connectionType` is `"followers"` or `"following"`.
|
|
195
|
+
|
|
157
196
|
## Field Selection
|
|
158
197
|
|
|
159
198
|
All methods accept a `fields` option. Use camelCase field names.
|
|
@@ -582,6 +621,16 @@ const comments = await client.reddit.searchComments("helpful tip", {
|
|
|
582
621
|
});
|
|
583
622
|
```
|
|
584
623
|
|
|
624
|
+
#### `getCommentById(commentId, options?) -> Promise<RedditComment>`
|
|
625
|
+
|
|
626
|
+
Fetch a single Reddit comment by its id (bare base36 or `t1_`-prefixed). Database-first with live API fallback when the comment is missing or stale.
|
|
627
|
+
|
|
628
|
+
```typescript
|
|
629
|
+
const comment = await client.reddit.getCommentById("laz1ytq", {
|
|
630
|
+
fields: ["id", "body", "rank", "removal"],
|
|
631
|
+
});
|
|
632
|
+
```
|
|
633
|
+
|
|
585
634
|
#### `searchSubreddits(query, options?) -> Promise<RedditSubreddit[]>`
|
|
586
635
|
|
|
587
636
|
Search subreddits by name. Use `limit` to adjust the number of results.
|
|
@@ -797,6 +846,19 @@ for (const bucket of history.credits) {
|
|
|
797
846
|
|
|
798
847
|
All fields are optional and typed as their respective TypeScript types. Unknown fields are preserved on the object.
|
|
799
848
|
|
|
849
|
+
> **Date fields.** Post models expose up to three creation-time fields whose
|
|
850
|
+
> runtime formats differ from what their names suggest:
|
|
851
|
+
>
|
|
852
|
+
> - `createdAt` — full ISO 8601 datetime on Twitter; epoch **seconds** on
|
|
853
|
+
> Reddit/Instagram/TikTok.
|
|
854
|
+
> - `createdAtTimestamp` — full ISO 8601 datetime (Reddit/Instagram/TikTok;
|
|
855
|
+
> not returned for Twitter).
|
|
856
|
+
> - `createdAtDate` — the creation **date only**, rendered as ISO midnight
|
|
857
|
+
> (`2026-07-20T00:00:00.000Z`); it carries no real time-of-day.
|
|
858
|
+
>
|
|
859
|
+
> Depending on response quoting, values can arrive as strings or numbers —
|
|
860
|
+
> treat all three as `string | number`.
|
|
861
|
+
|
|
800
862
|
### TwitterPost
|
|
801
863
|
|
|
802
864
|
| Field | Type | Description |
|
|
@@ -816,9 +878,13 @@ All fields are optional and typed as their respective TypeScript types. Unknown
|
|
|
816
878
|
| `mentions` | `string[]` | Mentioned usernames |
|
|
817
879
|
| `mediaUrls` | `string[]` | Media attachment URLs |
|
|
818
880
|
| `urls` | `string[]` | URLs in tweet text |
|
|
819
|
-
| `
|
|
820
|
-
| `
|
|
821
|
-
| `
|
|
881
|
+
| `placeName` | `string` | Tagged place name |
|
|
882
|
+
| `placeCountry` | `string` | Tagged place country |
|
|
883
|
+
| `placeCountryCode` | `string` | Tagged place country code (ISO 3166-1 alpha-2) |
|
|
884
|
+
| `placeBoundingBoxCoordinates` | `unknown` | Tagged place bounding box |
|
|
885
|
+
| `placeCentroid` | `unknown` | Tagged place centroid |
|
|
886
|
+
| `createdAt` | `string \| number` | Creation datetime (ISO 8601) |
|
|
887
|
+
| `createdAtDate` | `string \| number` | Creation date (ISO midnight, no time-of-day) |
|
|
822
888
|
| `conversationId` | `string` | Thread conversation ID |
|
|
823
889
|
| `quotedTweetId` | `string` | ID of quoted tweet |
|
|
824
890
|
| `replyToTweetId` | `string` | ID of parent tweet |
|
|
@@ -864,7 +930,9 @@ All fields are optional and typed as their respective TypeScript types. Unknown
|
|
|
864
930
|
| `mediaType` | `string` | Media type |
|
|
865
931
|
| `imageUrl` | `string` | Image URL |
|
|
866
932
|
| `videoUrl` | `string` | Video URL |
|
|
867
|
-
| `
|
|
933
|
+
| `createdAt` | `string \| number` | Creation time (epoch seconds) |
|
|
934
|
+
| `createdAtTimestamp` | `string \| number` | Creation datetime (ISO 8601) |
|
|
935
|
+
| `createdAtDate` | `string \| number` | Creation date (ISO midnight, no time-of-day) |
|
|
868
936
|
| `genAiChatWithAiCtaInfo` | `string` | Gen AI chat CTA info |
|
|
869
937
|
| `hasHighRiskGenAiInformTreatment` | `boolean` | High risk Gen AI treatment flag |
|
|
870
938
|
|
|
@@ -911,7 +979,9 @@ All fields are optional and typed as their respective TypeScript types. Unknown
|
|
|
911
979
|
| `permalink` | `string` | Reddit permalink |
|
|
912
980
|
| `isSelf` | `boolean` | Self post (text only) |
|
|
913
981
|
| `over18` | `boolean` | NSFW flag |
|
|
914
|
-
| `
|
|
982
|
+
| `createdAt` | `string \| number` | Creation time (epoch seconds) |
|
|
983
|
+
| `createdAtTimestamp` | `string \| number` | Creation datetime (ISO 8601) |
|
|
984
|
+
| `createdAtDate` | `string \| number` | Creation date (ISO midnight, no time-of-day) |
|
|
915
985
|
|
|
916
986
|
### RedditUser
|
|
917
987
|
|
|
@@ -976,8 +1046,9 @@ All fields are optional and typed as their respective TypeScript types. Unknown
|
|
|
976
1046
|
| `hashtags` | `string[]` | Hashtags in the post |
|
|
977
1047
|
| `postType` | `number` | Post type code |
|
|
978
1048
|
| `isPrivate` | `boolean` | Private post flag |
|
|
979
|
-
| `createdAt` | `string`
|
|
980
|
-
| `
|
|
1049
|
+
| `createdAt` | `string \| number` | Creation time (epoch seconds) |
|
|
1050
|
+
| `createdAtTimestamp` | `string \| number` | Creation datetime (ISO 8601) |
|
|
1051
|
+
| `createdAtDate` | `string \| number` | Creation date (ISO midnight, no time-of-day) |
|
|
981
1052
|
|
|
982
1053
|
### TiktokUser
|
|
983
1054
|
|
package/dist/index.cjs
CHANGED
|
@@ -33,6 +33,8 @@ __export(index_exports, {
|
|
|
33
33
|
AuthenticationError: () => AuthenticationError,
|
|
34
34
|
BillingPeriod: () => BillingPeriod,
|
|
35
35
|
CreditResetFrequency: () => CreditResetFrequency,
|
|
36
|
+
CursorResult: () => CursorResult,
|
|
37
|
+
NotFoundError: () => NotFoundError,
|
|
36
38
|
OperationCancelledError: () => OperationCancelledError,
|
|
37
39
|
OperationFailedError: () => OperationFailedError,
|
|
38
40
|
OperationTimeoutError: () => OperationTimeoutError,
|
|
@@ -41,6 +43,7 @@ __export(index_exports, {
|
|
|
41
43
|
TrackedItemPlatform: () => TrackedItemPlatform,
|
|
42
44
|
TrackedItemType: () => TrackedItemType,
|
|
43
45
|
VERSION: () => VERSION,
|
|
46
|
+
ValidationError: () => ValidationError,
|
|
44
47
|
XpozClient: () => XpozClient,
|
|
45
48
|
XpozConnectionError: () => XpozConnectionError,
|
|
46
49
|
XpozError: () => XpozError,
|
|
@@ -298,7 +301,7 @@ function coerce(value) {
|
|
|
298
301
|
}
|
|
299
302
|
|
|
300
303
|
// src/version.ts
|
|
301
|
-
var VERSION = "0.6.
|
|
304
|
+
var VERSION = "0.6.12";
|
|
302
305
|
|
|
303
306
|
// src/mcp/transport.ts
|
|
304
307
|
var USER_AGENT = `xpoz-ts-sdk/${VERSION}`;
|
|
@@ -393,6 +396,18 @@ var XpozConnectionError = class extends XpozError {
|
|
|
393
396
|
this.name = "XpozConnectionError";
|
|
394
397
|
}
|
|
395
398
|
};
|
|
399
|
+
var NotFoundError = class extends XpozError {
|
|
400
|
+
constructor(message) {
|
|
401
|
+
super(message);
|
|
402
|
+
this.name = "NotFoundError";
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
var ValidationError = class extends XpozError {
|
|
406
|
+
constructor(message) {
|
|
407
|
+
super(message);
|
|
408
|
+
this.name = "ValidationError";
|
|
409
|
+
}
|
|
410
|
+
};
|
|
396
411
|
var OperationTimeoutError = class extends XpozError {
|
|
397
412
|
operationId;
|
|
398
413
|
elapsedMs;
|
|
@@ -435,6 +450,216 @@ var ResponseType = /* @__PURE__ */ ((ResponseType2) => {
|
|
|
435
450
|
var POLL_INTERVAL_MS = 5e3;
|
|
436
451
|
var DEFAULT_TIMEOUT_MS = 3e5;
|
|
437
452
|
|
|
453
|
+
// src/config/routes.ts
|
|
454
|
+
var DEFAULT_API_URL = "https://api.xpoz.ai";
|
|
455
|
+
var ENV_API_URL = "XPOZ_API_URL";
|
|
456
|
+
var INSTAGRAM_BASE = "/api/data/instagram";
|
|
457
|
+
var INSTAGRAM_LIVE_ROUTES = {
|
|
458
|
+
posts: `${INSTAGRAM_BASE}/posts/live`,
|
|
459
|
+
userPosts: (identifier) => `${INSTAGRAM_BASE}/posts/users/${encodeURIComponent(identifier)}/live`,
|
|
460
|
+
post: (postId) => `${INSTAGRAM_BASE}/posts/${encodeURIComponent(postId)}/live`,
|
|
461
|
+
postComments: (postId) => `${INSTAGRAM_BASE}/posts/${encodeURIComponent(postId)}/comments/live`,
|
|
462
|
+
postInteractingUsers: (postId) => `${INSTAGRAM_BASE}/posts/${encodeURIComponent(postId)}/interacting-users/live`,
|
|
463
|
+
users: `${INSTAGRAM_BASE}/users/live`,
|
|
464
|
+
user: (identifier) => `${INSTAGRAM_BASE}/users/${encodeURIComponent(identifier)}/live`,
|
|
465
|
+
userConnections: (identifier) => `${INSTAGRAM_BASE}/users/${encodeURIComponent(identifier)}/connections/live`
|
|
466
|
+
};
|
|
467
|
+
var REST_TIMEOUT_MS = 12e4;
|
|
468
|
+
|
|
469
|
+
// src/rest/transport.ts
|
|
470
|
+
var USER_AGENT2 = `xpoz-ts-sdk/${VERSION}`;
|
|
471
|
+
function buildQuery(params) {
|
|
472
|
+
const search = new URLSearchParams();
|
|
473
|
+
for (const [key, value] of Object.entries(params)) {
|
|
474
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
475
|
+
search.append(key, String(value));
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
const query = search.toString();
|
|
479
|
+
return query ? `?${query}` : "";
|
|
480
|
+
}
|
|
481
|
+
async function extractErrorMessage(response) {
|
|
482
|
+
try {
|
|
483
|
+
const body = await response.json();
|
|
484
|
+
const message = body.error ?? body.message;
|
|
485
|
+
return typeof message === "string" ? message : response.statusText;
|
|
486
|
+
} catch {
|
|
487
|
+
return response.statusText;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
async function raiseForStatus(response) {
|
|
491
|
+
if (response.ok) {
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
const message = await extractErrorMessage(response);
|
|
495
|
+
if (response.status === 401 || response.status === 403) {
|
|
496
|
+
throw new AuthenticationError(message);
|
|
497
|
+
}
|
|
498
|
+
if (response.status === 404) {
|
|
499
|
+
throw new NotFoundError(message);
|
|
500
|
+
}
|
|
501
|
+
if (response.status === 400) {
|
|
502
|
+
throw new ValidationError(message);
|
|
503
|
+
}
|
|
504
|
+
throw new XpozError(`HTTP ${response.status}: ${message}`);
|
|
505
|
+
}
|
|
506
|
+
var RestTransport = class {
|
|
507
|
+
baseUrl;
|
|
508
|
+
apiKey;
|
|
509
|
+
timeoutMs;
|
|
510
|
+
constructor(baseUrl, apiKey, timeoutMs = REST_TIMEOUT_MS) {
|
|
511
|
+
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
512
|
+
this.apiKey = apiKey;
|
|
513
|
+
this.timeoutMs = timeoutMs;
|
|
514
|
+
}
|
|
515
|
+
async get(path, params = {}) {
|
|
516
|
+
const url = `${this.baseUrl}${path}${buildQuery(params)}`;
|
|
517
|
+
const controller = new AbortController();
|
|
518
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
519
|
+
let response;
|
|
520
|
+
try {
|
|
521
|
+
response = await fetch(url, {
|
|
522
|
+
headers: {
|
|
523
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
524
|
+
"User-Agent": USER_AGENT2,
|
|
525
|
+
Accept: "application/json"
|
|
526
|
+
},
|
|
527
|
+
signal: controller.signal
|
|
528
|
+
});
|
|
529
|
+
} catch (error) {
|
|
530
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
531
|
+
throw new XpozConnectionError(reason);
|
|
532
|
+
} finally {
|
|
533
|
+
clearTimeout(timer);
|
|
534
|
+
}
|
|
535
|
+
await raiseForStatus(response);
|
|
536
|
+
return await response.json();
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
// src/cursor.ts
|
|
541
|
+
var CursorResult = class {
|
|
542
|
+
data;
|
|
543
|
+
hasMore;
|
|
544
|
+
nextPageCursor;
|
|
545
|
+
_fetchPage;
|
|
546
|
+
constructor(options) {
|
|
547
|
+
this.data = options.data;
|
|
548
|
+
this.hasMore = options.hasMore;
|
|
549
|
+
this.nextPageCursor = options.nextPageCursor;
|
|
550
|
+
this._fetchPage = options.fetchPage;
|
|
551
|
+
}
|
|
552
|
+
hasNextPage() {
|
|
553
|
+
return this.hasMore && this.nextPageCursor !== null;
|
|
554
|
+
}
|
|
555
|
+
async nextPage() {
|
|
556
|
+
if (!this.hasNextPage()) {
|
|
557
|
+
throw new RangeError("No more pages available");
|
|
558
|
+
}
|
|
559
|
+
return this._fetchPage(this.nextPageCursor);
|
|
560
|
+
}
|
|
561
|
+
async *pages() {
|
|
562
|
+
let page = this;
|
|
563
|
+
yield page;
|
|
564
|
+
while (page.hasNextPage()) {
|
|
565
|
+
page = await page.nextPage();
|
|
566
|
+
yield page;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
async *items() {
|
|
570
|
+
for await (const page of this.pages()) {
|
|
571
|
+
yield* page.data;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
[Symbol.iterator]() {
|
|
575
|
+
return this.data[Symbol.iterator]();
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
// src/namespaces/instagramLive.ts
|
|
580
|
+
var STRING_ID_FIELDS = ["id", "userId", "user_id", "postId", "post_id"];
|
|
581
|
+
function coerceStringIds(item) {
|
|
582
|
+
const record = item;
|
|
583
|
+
for (const field of STRING_ID_FIELDS) {
|
|
584
|
+
if (typeof record[field] === "number") {
|
|
585
|
+
record[field] = String(record[field]);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return item;
|
|
589
|
+
}
|
|
590
|
+
function csvFields(fields) {
|
|
591
|
+
return fields && fields.length > 0 ? fields.join(",") : void 0;
|
|
592
|
+
}
|
|
593
|
+
var InstagramLiveNamespace = class {
|
|
594
|
+
transport;
|
|
595
|
+
constructor(transport) {
|
|
596
|
+
this.transport = transport;
|
|
597
|
+
}
|
|
598
|
+
async page(path, params) {
|
|
599
|
+
const payload = await this.transport.get(path, params);
|
|
600
|
+
return new CursorResult({
|
|
601
|
+
data: (payload.results ?? []).map(coerceStringIds),
|
|
602
|
+
hasMore: Boolean(payload.has_more),
|
|
603
|
+
nextPageCursor: payload.next_page_cursor ?? null,
|
|
604
|
+
fetchPage: (cursor) => this.page(path, { ...params, cursor })
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
async single(path, params) {
|
|
608
|
+
const page = await this.page(path, params);
|
|
609
|
+
return page.data[0] ?? null;
|
|
610
|
+
}
|
|
611
|
+
async searchPosts(query, options = {}) {
|
|
612
|
+
return this.page(INSTAGRAM_LIVE_ROUTES.posts, {
|
|
613
|
+
q: query,
|
|
614
|
+
fields: csvFields(options.fields),
|
|
615
|
+
cursor: options.cursor
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
async getPostsByUser(identifier, options = {}) {
|
|
619
|
+
return this.page(INSTAGRAM_LIVE_ROUTES.userPosts(identifier), {
|
|
620
|
+
fields: csvFields(options.fields),
|
|
621
|
+
cursor: options.cursor
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
async getPost(postId, options = {}) {
|
|
625
|
+
return this.single(INSTAGRAM_LIVE_ROUTES.post(postId), {
|
|
626
|
+
fields: csvFields(options.fields)
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
async getComments(postId, options = {}) {
|
|
630
|
+
return this.page(INSTAGRAM_LIVE_ROUTES.postComments(postId), {
|
|
631
|
+
fields: csvFields(options.fields),
|
|
632
|
+
cursor: options.cursor
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
async getPostInteractingUsers(postId, interactionType, options = {}) {
|
|
636
|
+
return this.page(INSTAGRAM_LIVE_ROUTES.postInteractingUsers(postId), {
|
|
637
|
+
interactionType,
|
|
638
|
+
fields: csvFields(options.fields),
|
|
639
|
+
cursor: options.cursor
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
async searchUsers(name, options = {}) {
|
|
643
|
+
return this.page(INSTAGRAM_LIVE_ROUTES.users, {
|
|
644
|
+
name,
|
|
645
|
+
fields: csvFields(options.fields),
|
|
646
|
+
cursor: options.cursor
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
async getUser(identifier, options = {}) {
|
|
650
|
+
return this.single(INSTAGRAM_LIVE_ROUTES.user(identifier), {
|
|
651
|
+
fields: csvFields(options.fields)
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
async getUserConnections(identifier, connectionType, options = {}) {
|
|
655
|
+
return this.page(INSTAGRAM_LIVE_ROUTES.userConnections(identifier), {
|
|
656
|
+
connectionType,
|
|
657
|
+
fields: csvFields(options.fields),
|
|
658
|
+
cursor: options.cursor
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
};
|
|
662
|
+
|
|
438
663
|
// src/mcp/polling.ts
|
|
439
664
|
async function waitForResult(callTool, operationId, timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
440
665
|
const start = Date.now();
|
|
@@ -622,6 +847,7 @@ var GET_INSTAGRAM_USERS_BY_KEYWORDS = "getInstagramUsersByKeywords";
|
|
|
622
847
|
var SEARCH_REDDIT_POSTS = "getRedditPostsByKeywords";
|
|
623
848
|
var GET_REDDIT_POST_WITH_COMMENTS = "getRedditPostWithCommentsById";
|
|
624
849
|
var SEARCH_REDDIT_COMMENTS = "getRedditCommentsByKeywords";
|
|
850
|
+
var GET_REDDIT_COMMENT_BY_ID = "getRedditCommentById";
|
|
625
851
|
var GET_REDDIT_USER = "getRedditUser";
|
|
626
852
|
var SEARCH_REDDIT_USERS = "searchRedditUsers";
|
|
627
853
|
var GET_REDDIT_USERS_BY_KEYWORDS = "getRedditUsersByKeywords";
|
|
@@ -980,6 +1206,15 @@ var RedditNamespace = class extends BaseNamespace {
|
|
|
980
1206
|
const result = await this.callAndMaybePoll(SEARCH_REDDIT_COMMENTS, args);
|
|
981
1207
|
return this.buildPaginatedResult(result, parseComment2, SEARCH_REDDIT_COMMENTS, args);
|
|
982
1208
|
}
|
|
1209
|
+
async getCommentById(commentId, options = {}) {
|
|
1210
|
+
const args = this.buildArgs({ commentId, ...options });
|
|
1211
|
+
const result = await this.callAndMaybePoll(GET_REDDIT_COMMENT_BY_ID, args);
|
|
1212
|
+
const results = result["results"];
|
|
1213
|
+
if (Array.isArray(results) && results.length > 0) {
|
|
1214
|
+
return results[0];
|
|
1215
|
+
}
|
|
1216
|
+
return result;
|
|
1217
|
+
}
|
|
983
1218
|
async getUser(username, options = {}) {
|
|
984
1219
|
const args = this.buildArgs({ username, ...options });
|
|
985
1220
|
const result = await this.callAndMaybePoll(GET_REDDIT_USER, args);
|
|
@@ -1254,6 +1489,8 @@ var XpozClient = class {
|
|
|
1254
1489
|
account;
|
|
1255
1490
|
transport;
|
|
1256
1491
|
versionCheck;
|
|
1492
|
+
restTransport;
|
|
1493
|
+
instagramLiveNamespace;
|
|
1257
1494
|
constructor(options = {}) {
|
|
1258
1495
|
const apiKey = options.apiKey ?? process.env[ENV_API_KEY];
|
|
1259
1496
|
if (!apiKey) {
|
|
@@ -1265,6 +1502,8 @@ var XpozClient = class {
|
|
|
1265
1502
|
const serverUrl = options.serverUrl ?? process.env[ENV_SERVER_URL] ?? DEFAULT_SERVER_URL;
|
|
1266
1503
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
1267
1504
|
this.transport = new McpTransport(serverUrl, apiKey);
|
|
1505
|
+
const apiUrl = options.apiUrl ?? process.env[ENV_API_URL] ?? DEFAULT_API_URL;
|
|
1506
|
+
this.restTransport = new RestTransport(apiUrl, apiKey);
|
|
1268
1507
|
const callTool = this.transport.callTool.bind(this.transport);
|
|
1269
1508
|
this.twitter = new TwitterNamespace(callTool, timeoutMs);
|
|
1270
1509
|
this.instagram = new InstagramNamespace(callTool, timeoutMs);
|
|
@@ -1273,6 +1512,12 @@ var XpozClient = class {
|
|
|
1273
1512
|
this.tracking = new TrackingNamespace(callTool, timeoutMs);
|
|
1274
1513
|
this.account = new AccountNamespace(callTool, timeoutMs);
|
|
1275
1514
|
}
|
|
1515
|
+
get instagramLive() {
|
|
1516
|
+
if (!this.instagramLiveNamespace) {
|
|
1517
|
+
this.instagramLiveNamespace = new InstagramLiveNamespace(this.restTransport);
|
|
1518
|
+
}
|
|
1519
|
+
return this.instagramLiveNamespace;
|
|
1520
|
+
}
|
|
1276
1521
|
async connect() {
|
|
1277
1522
|
await this.transport.connect();
|
|
1278
1523
|
if (this.versionCheck) {
|
|
@@ -1319,6 +1564,8 @@ var CreditResetFrequency = /* @__PURE__ */ ((CreditResetFrequency2) => {
|
|
|
1319
1564
|
AuthenticationError,
|
|
1320
1565
|
BillingPeriod,
|
|
1321
1566
|
CreditResetFrequency,
|
|
1567
|
+
CursorResult,
|
|
1568
|
+
NotFoundError,
|
|
1322
1569
|
OperationCancelledError,
|
|
1323
1570
|
OperationFailedError,
|
|
1324
1571
|
OperationTimeoutError,
|
|
@@ -1327,6 +1574,7 @@ var CreditResetFrequency = /* @__PURE__ */ ((CreditResetFrequency2) => {
|
|
|
1327
1574
|
TrackedItemPlatform,
|
|
1328
1575
|
TrackedItemType,
|
|
1329
1576
|
VERSION,
|
|
1577
|
+
ValidationError,
|
|
1330
1578
|
XpozClient,
|
|
1331
1579
|
XpozConnectionError,
|
|
1332
1580
|
XpozError,
|