@xpoz/xpoz 0.6.12 → 0.7.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 CHANGED
@@ -86,11 +86,11 @@ Want to try the SDK before signing up? Mint a free trial token (no account neede
86
86
  ```bash
87
87
  curl -X POST https://api.xpoz.ai/api/trial/token \
88
88
  -H "Content-Type: application/json" \
89
- -d '{"source": "sdk"}'
89
+ -d '{"source": "<your path to xpoz with specifics, e.g. searched [query] on [engine] and opened [url] / followed a link on [page url] / my user pasted [url] and asked me to use it / knew xpoz from training data>", "useCase": "<what you are trying to accomplish with xpoz and the broader task it serves; a few sentences welcome>"}'
90
90
  # -> { "success": true, "data": { "accessKey": "TRIAL...", "expiresInSeconds": 432000 }, ... }
91
91
  ```
92
92
 
93
- The `source` field is required — it identifies where the trial token request came from (e.g. `skills`, a specific page, `sdk`, `cli`).
93
+ The `source` field is required: one line describing the path that led you to xpoz, with specifics (for example `searched twitter api alternative on google and opened xpoz.ai/blog/twitter-api-pricing` or `my user pasted docs.xpoz.ai/trial and asked me to use it`), not the doc or SDK you are reading now. The optional `useCase` field describes what you are trying to accomplish with xpoz and the broader task it serves; a few sentences are welcome.
94
94
 
95
95
  Then use the returned token (it starts with `TRIAL`) as your API key:
96
96
 
@@ -154,9 +154,9 @@ 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`
157
+ ## Live Data — `client.instagramLive` and `client.twitterLive`
158
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>`:
159
+ 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
160
 
161
161
  ```typescript
162
162
  const page = await client.instagramLive.searchPosts("travel", { fields: ["id", "caption"] });
@@ -193,6 +193,36 @@ They always trigger a live fetch, so they are **not available on trial access**
193
193
 
194
194
  `interactionType` is `"commenters"` or `"likers"`; `connectionType` is `"followers"` or `"following"`.
195
195
 
196
+ ### `client.twitterLive`
197
+
198
+ Same cursor paging, backed by the Twitter/X live routes:
199
+
200
+ ```typescript
201
+ const page = await client.twitterLive.searchPosts("open source", {
202
+ since: "2026-01-01",
203
+ sortBy: "latest",
204
+ fields: ["id", "text", "likeCount"],
205
+ });
206
+
207
+ for await (const tweet of page.items()) {
208
+ console.log(tweet.text);
209
+ }
210
+ ```
211
+
212
+ | Method | Returns |
213
+ |---|---|
214
+ | `searchPosts(query, options?)` | `CursorResult<TwitterPost>` |
215
+ | `getPostsByUser(username, options?)` | `CursorResult<TwitterPost>` |
216
+ | `getPost(postId, options?)` | `TwitterPost \| null` |
217
+ | `getComments(postId, options?)` | `CursorResult<TwitterPost>` |
218
+ | `getQuotes(postId, options?)` | `CursorResult<TwitterPost>` |
219
+ | `getPostInteractingUsers(postId, interactionType, options?)` | `CursorResult<TwitterUser>` |
220
+ | `searchUsers(query, options?)` | `CursorResult<TwitterUser>` |
221
+ | `getUser(username, options?)` | `TwitterUser \| null` |
222
+ | `getUserConnections(username, connectionType, options?)` | `CursorResult<TwitterUser>` |
223
+
224
+ `searchPosts` also accepts `since`, `until` (`YYYY-MM-DD`), `lang`, `countryCode`, and `sortBy` (`"relevance"` or `"latest"`); `getPostsByUser` accepts `since` and `until`. `interactionType` is `"commenters"`, `"quoters"`, or `"retweeters"`; `connectionType` is `"followers"` or `"following"`. Retweets have no live route.
225
+
196
226
  ## Field Selection
197
227
 
198
228
  All methods accept a `fields` option. Use camelCase field names.
@@ -926,6 +956,8 @@ All fields are optional and typed as their respective TypeScript types. Unknown
926
956
  | `likeCount` | `number` | Number of likes |
927
957
  | `commentCount` | `number` | Number of comments |
928
958
  | `reshareCount` | `number` | Number of reshares |
959
+ | `mediaRepostCount` | `number` | Number of media reposts |
960
+ | `saveCount` | `number` | Number of saves |
929
961
  | `videoPlayCount` | `number` | Video play count |
930
962
  | `mediaType` | `string` | Media type |
931
963
  | `imageUrl` | `string` | Image URL |
package/dist/index.cjs CHANGED
@@ -301,7 +301,7 @@ function coerce(value) {
301
301
  }
302
302
 
303
303
  // src/version.ts
304
- var VERSION = "0.6.12";
304
+ var VERSION = "0.7.0";
305
305
 
306
306
  // src/mcp/transport.ts
307
307
  var USER_AGENT = `xpoz-ts-sdk/${VERSION}`;
@@ -454,6 +454,7 @@ 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";
457
458
  var INSTAGRAM_LIVE_ROUTES = {
458
459
  posts: `${INSTAGRAM_BASE}/posts/live`,
459
460
  userPosts: (identifier) => `${INSTAGRAM_BASE}/posts/users/${encodeURIComponent(identifier)}/live`,
@@ -464,6 +465,17 @@ var INSTAGRAM_LIVE_ROUTES = {
464
465
  user: (identifier) => `${INSTAGRAM_BASE}/users/${encodeURIComponent(identifier)}/live`,
465
466
  userConnections: (identifier) => `${INSTAGRAM_BASE}/users/${encodeURIComponent(identifier)}/connections/live`
466
467
  };
468
+ var TWITTER_LIVE_ROUTES = {
469
+ posts: `${TWITTER_BASE}/posts/live`,
470
+ userPosts: (username) => `${TWITTER_BASE}/posts/users/${encodeURIComponent(username)}/live`,
471
+ post: (postId) => `${TWITTER_BASE}/posts/${encodeURIComponent(postId)}/live`,
472
+ postComments: (postId) => `${TWITTER_BASE}/posts/${encodeURIComponent(postId)}/comments/live`,
473
+ postQuotes: (postId) => `${TWITTER_BASE}/posts/${encodeURIComponent(postId)}/quotes/live`,
474
+ postInteractingUsers: (postId) => `${TWITTER_BASE}/posts/${encodeURIComponent(postId)}/interacting-users/live`,
475
+ users: `${TWITTER_BASE}/users/live`,
476
+ user: (username) => `${TWITTER_BASE}/users/${encodeURIComponent(username)}/live`,
477
+ userConnections: (username) => `${TWITTER_BASE}/users/${encodeURIComponent(username)}/connections/live`
478
+ };
467
479
  var REST_TIMEOUT_MS = 12e4;
468
480
 
469
481
  // src/rest/transport.ts
@@ -576,8 +588,16 @@ var CursorResult = class {
576
588
  }
577
589
  };
578
590
 
579
- // src/namespaces/instagramLive.ts
580
- var STRING_ID_FIELDS = ["id", "userId", "user_id", "postId", "post_id"];
591
+ // src/namespaces/liveBase.ts
592
+ var STRING_ID_FIELDS = [
593
+ "id",
594
+ "userId",
595
+ "user_id",
596
+ "postId",
597
+ "post_id",
598
+ "authorId",
599
+ "author_id"
600
+ ];
581
601
  function coerceStringIds(item) {
582
602
  const record = item;
583
603
  for (const field of STRING_ID_FIELDS) {
@@ -590,7 +610,7 @@ function coerceStringIds(item) {
590
610
  function csvFields(fields) {
591
611
  return fields && fields.length > 0 ? fields.join(",") : void 0;
592
612
  }
593
- var InstagramLiveNamespace = class {
613
+ var LiveNamespace = class {
594
614
  transport;
595
615
  constructor(transport) {
596
616
  this.transport = transport;
@@ -608,6 +628,10 @@ var InstagramLiveNamespace = class {
608
628
  const page = await this.page(path, params);
609
629
  return page.data[0] ?? null;
610
630
  }
631
+ };
632
+
633
+ // src/namespaces/instagramLive.ts
634
+ var InstagramLiveNamespace = class extends LiveNamespace {
611
635
  async searchPosts(query, options = {}) {
612
636
  return this.page(INSTAGRAM_LIVE_ROUTES.posts, {
613
637
  q: query,
@@ -660,6 +684,73 @@ var InstagramLiveNamespace = class {
660
684
  }
661
685
  };
662
686
 
687
+ // src/namespaces/twitterLive.ts
688
+ var TwitterLiveNamespace = class extends LiveNamespace {
689
+ async searchPosts(query, options = {}) {
690
+ return this.page(TWITTER_LIVE_ROUTES.posts, {
691
+ q: query,
692
+ since: options.since,
693
+ until: options.until,
694
+ lang: options.lang,
695
+ countryCode: options.countryCode,
696
+ sortBy: options.sortBy,
697
+ fields: csvFields(options.fields),
698
+ cursor: options.cursor
699
+ });
700
+ }
701
+ async getPostsByUser(username, options = {}) {
702
+ return this.page(TWITTER_LIVE_ROUTES.userPosts(username), {
703
+ since: options.since,
704
+ until: options.until,
705
+ fields: csvFields(options.fields),
706
+ cursor: options.cursor
707
+ });
708
+ }
709
+ async getPost(postId, options = {}) {
710
+ return this.single(TWITTER_LIVE_ROUTES.post(postId), {
711
+ fields: csvFields(options.fields)
712
+ });
713
+ }
714
+ async getComments(postId, options = {}) {
715
+ return this.page(TWITTER_LIVE_ROUTES.postComments(postId), {
716
+ fields: csvFields(options.fields),
717
+ cursor: options.cursor
718
+ });
719
+ }
720
+ async getQuotes(postId, options = {}) {
721
+ return this.page(TWITTER_LIVE_ROUTES.postQuotes(postId), {
722
+ fields: csvFields(options.fields),
723
+ cursor: options.cursor
724
+ });
725
+ }
726
+ async getPostInteractingUsers(postId, interactionType, options = {}) {
727
+ return this.page(TWITTER_LIVE_ROUTES.postInteractingUsers(postId), {
728
+ interactionType,
729
+ fields: csvFields(options.fields),
730
+ cursor: options.cursor
731
+ });
732
+ }
733
+ async searchUsers(query, options = {}) {
734
+ return this.page(TWITTER_LIVE_ROUTES.users, {
735
+ q: query,
736
+ fields: csvFields(options.fields),
737
+ cursor: options.cursor
738
+ });
739
+ }
740
+ async getUser(username, options = {}) {
741
+ return this.single(TWITTER_LIVE_ROUTES.user(username), {
742
+ fields: csvFields(options.fields)
743
+ });
744
+ }
745
+ async getUserConnections(username, connectionType, options = {}) {
746
+ return this.page(TWITTER_LIVE_ROUTES.userConnections(username), {
747
+ connectionType,
748
+ fields: csvFields(options.fields),
749
+ cursor: options.cursor
750
+ });
751
+ }
752
+ };
753
+
663
754
  // src/mcp/polling.ts
664
755
  async function waitForResult(callTool, operationId, timeoutMs = DEFAULT_TIMEOUT_MS) {
665
756
  const start = Date.now();
@@ -1491,6 +1582,7 @@ var XpozClient = class {
1491
1582
  versionCheck;
1492
1583
  restTransport;
1493
1584
  instagramLiveNamespace;
1585
+ twitterLiveNamespace;
1494
1586
  constructor(options = {}) {
1495
1587
  const apiKey = options.apiKey ?? process.env[ENV_API_KEY];
1496
1588
  if (!apiKey) {
@@ -1518,6 +1610,12 @@ var XpozClient = class {
1518
1610
  }
1519
1611
  return this.instagramLiveNamespace;
1520
1612
  }
1613
+ get twitterLive() {
1614
+ if (!this.twitterLiveNamespace) {
1615
+ this.twitterLiveNamespace = new TwitterLiveNamespace(this.restTransport);
1616
+ }
1617
+ return this.twitterLiveNamespace;
1618
+ }
1521
1619
  async connect() {
1522
1620
  await this.transport.connect();
1523
1621
  if (this.versionCheck) {
package/dist/index.d.cts CHANGED
@@ -26,6 +26,13 @@ declare class RestTransport {
26
26
  get<T>(path: string, params?: QueryParams): Promise<T>;
27
27
  }
28
28
 
29
+ declare abstract class LiveNamespace {
30
+ protected transport: RestTransport;
31
+ constructor(transport: RestTransport);
32
+ protected page<T>(path: string, params: QueryParams): Promise<CursorResult<T>>;
33
+ protected single<T>(path: string, params: QueryParams): Promise<T | null>;
34
+ }
35
+
29
36
  interface CursorPageResponse<T> {
30
37
  results: T[];
31
38
  count: number;
@@ -35,6 +42,9 @@ interface CursorPageResponse<T> {
35
42
  }
36
43
  type InstagramConnectionType = "followers" | "following";
37
44
  type InstagramInteractionType = "commenters" | "likers";
45
+ type TwitterConnectionType = "followers" | "following";
46
+ type TwitterInteractionType = "commenters" | "quoters" | "retweeters";
47
+ type TwitterLiveSortBy = "relevance" | "latest";
38
48
  interface PaginationInfo {
39
49
  tableName?: string | null;
40
50
  totalRows: number;
@@ -63,6 +73,8 @@ interface InstagramPost {
63
73
  likeCount?: number | null;
64
74
  commentCount?: number | null;
65
75
  reshareCount?: number | null;
76
+ mediaRepostCount?: number | null;
77
+ saveCount?: number | null;
66
78
  videoPlayCount?: number | null;
67
79
  location?: string | null;
68
80
  genAiChatWithAiCtaInfo?: string | null;
@@ -92,6 +104,8 @@ interface InstagramUser {
92
104
  relevantPostsLikesSum?: number | null;
93
105
  relevantPostsCommentsSum?: number | null;
94
106
  relevantPostsResharesSum?: number | null;
107
+ relevantPostsMediaRepostsSum?: number | null;
108
+ relevantPostsSavesSum?: number | null;
95
109
  relevantPostsVideoPlaysSum?: number | null;
96
110
  [key: string]: unknown;
97
111
  }
@@ -117,11 +131,7 @@ interface InstagramComment {
117
131
  [key: string]: unknown;
118
132
  }
119
133
 
120
- declare class InstagramLiveNamespace {
121
- private transport;
122
- constructor(transport: RestTransport);
123
- private page;
124
- private single;
134
+ declare class InstagramLiveNamespace extends LiveNamespace {
125
135
  searchPosts(query: string, options?: {
126
136
  fields?: string[];
127
137
  cursor?: string;
@@ -154,44 +164,6 @@ declare class InstagramLiveNamespace {
154
164
  }): Promise<CursorResult<InstagramUser>>;
155
165
  }
156
166
 
157
- type FetchPage<T> = (pageNumber: number, tableName: string | null | undefined) => Promise<PaginatedResult<T>>;
158
- type FetchExport = (exportOperationId: string) => Promise<string>;
159
- declare class PaginatedResult<T> {
160
- data: T[];
161
- pagination: PaginationInfo;
162
- private _tableName;
163
- private _exportOperationId;
164
- private _fetchPage;
165
- private _fetchExport;
166
- constructor(options: {
167
- data: T[];
168
- pagination: PaginationInfo;
169
- tableName: string | null | undefined;
170
- exportOperationId: string | null | undefined;
171
- fetchPage: FetchPage<T>;
172
- fetchExport: FetchExport | null;
173
- });
174
- hasNextPage(): boolean;
175
- nextPage(): Promise<PaginatedResult<T>>;
176
- getPage(pageNumber: number): Promise<PaginatedResult<T>>;
177
- exportCsv(): Promise<string>;
178
- private _fetchPageResult;
179
- toString(): string;
180
- }
181
-
182
- type CallTool = (name: string, args: Record<string, unknown>) => Promise<Record<string, unknown>>;
183
- type RawDict = Record<string, unknown>;
184
- declare class BaseNamespace {
185
- protected callTool: CallTool;
186
- protected timeoutMs: number;
187
- constructor(callTool: CallTool, timeoutMs?: number);
188
- protected callAndMaybePoll(toolName: string, args: RawDict): Promise<RawDict>;
189
- protected buildPaginatedResult<T>(raw: RawDict, parseItem: (item: RawDict) => T, toolName: string, baseArgs: RawDict): PaginatedResult<T>;
190
- protected buildArgs(args: Record<string, unknown>): RawDict;
191
- protected extractPagination(raw: RawDict): PaginationInfo;
192
- protected extractResults(raw: RawDict): RawDict[];
193
- }
194
-
195
167
  interface TwitterPost {
196
168
  id?: string | null;
197
169
  text?: string | null;
@@ -279,6 +251,88 @@ interface TwitterUser {
279
251
  [key: string]: unknown;
280
252
  }
281
253
 
254
+ declare class TwitterLiveNamespace extends LiveNamespace {
255
+ searchPosts(query: string, options?: {
256
+ since?: string;
257
+ until?: string;
258
+ lang?: string;
259
+ countryCode?: string;
260
+ sortBy?: TwitterLiveSortBy;
261
+ fields?: string[];
262
+ cursor?: string;
263
+ }): Promise<CursorResult<TwitterPost>>;
264
+ getPostsByUser(username: string, options?: {
265
+ since?: string;
266
+ until?: string;
267
+ fields?: string[];
268
+ cursor?: string;
269
+ }): Promise<CursorResult<TwitterPost>>;
270
+ getPost(postId: string, options?: {
271
+ fields?: string[];
272
+ }): Promise<TwitterPost | null>;
273
+ getComments(postId: string, options?: {
274
+ fields?: string[];
275
+ cursor?: string;
276
+ }): Promise<CursorResult<TwitterPost>>;
277
+ getQuotes(postId: string, options?: {
278
+ fields?: string[];
279
+ cursor?: string;
280
+ }): Promise<CursorResult<TwitterPost>>;
281
+ getPostInteractingUsers(postId: string, interactionType: TwitterInteractionType, options?: {
282
+ fields?: string[];
283
+ cursor?: string;
284
+ }): Promise<CursorResult<TwitterUser>>;
285
+ searchUsers(query: string, options?: {
286
+ fields?: string[];
287
+ cursor?: string;
288
+ }): Promise<CursorResult<TwitterUser>>;
289
+ getUser(username: string, options?: {
290
+ fields?: string[];
291
+ }): Promise<TwitterUser | null>;
292
+ getUserConnections(username: string, connectionType: TwitterConnectionType, options?: {
293
+ fields?: string[];
294
+ cursor?: string;
295
+ }): Promise<CursorResult<TwitterUser>>;
296
+ }
297
+
298
+ type FetchPage<T> = (pageNumber: number, tableName: string | null | undefined) => Promise<PaginatedResult<T>>;
299
+ type FetchExport = (exportOperationId: string) => Promise<string>;
300
+ declare class PaginatedResult<T> {
301
+ data: T[];
302
+ pagination: PaginationInfo;
303
+ private _tableName;
304
+ private _exportOperationId;
305
+ private _fetchPage;
306
+ private _fetchExport;
307
+ constructor(options: {
308
+ data: T[];
309
+ pagination: PaginationInfo;
310
+ tableName: string | null | undefined;
311
+ exportOperationId: string | null | undefined;
312
+ fetchPage: FetchPage<T>;
313
+ fetchExport: FetchExport | null;
314
+ });
315
+ hasNextPage(): boolean;
316
+ nextPage(): Promise<PaginatedResult<T>>;
317
+ getPage(pageNumber: number): Promise<PaginatedResult<T>>;
318
+ exportCsv(): Promise<string>;
319
+ private _fetchPageResult;
320
+ toString(): string;
321
+ }
322
+
323
+ type CallTool = (name: string, args: Record<string, unknown>) => Promise<Record<string, unknown>>;
324
+ type RawDict = Record<string, unknown>;
325
+ declare class BaseNamespace {
326
+ protected callTool: CallTool;
327
+ protected timeoutMs: number;
328
+ constructor(callTool: CallTool, timeoutMs?: number);
329
+ protected callAndMaybePoll(toolName: string, args: RawDict): Promise<RawDict>;
330
+ protected buildPaginatedResult<T>(raw: RawDict, parseItem: (item: RawDict) => T, toolName: string, baseArgs: RawDict): PaginatedResult<T>;
331
+ protected buildArgs(args: Record<string, unknown>): RawDict;
332
+ protected extractPagination(raw: RawDict): PaginationInfo;
333
+ protected extractResults(raw: RawDict): RawDict[];
334
+ }
335
+
282
336
  declare enum ResponseType {
283
337
  Fast = "fast",
284
338
  Paging = "paging",
@@ -873,6 +927,7 @@ declare class XpozClient {
873
927
  private versionCheck;
874
928
  private restTransport;
875
929
  private instagramLiveNamespace?;
930
+ private twitterLiveNamespace?;
876
931
  constructor(options?: {
877
932
  apiKey?: string;
878
933
  serverUrl?: string;
@@ -881,6 +936,7 @@ declare class XpozClient {
881
936
  apiUrl?: string;
882
937
  });
883
938
  get instagramLive(): InstagramLiveNamespace;
939
+ get twitterLive(): TwitterLiveNamespace;
884
940
  connect(): Promise<void>;
885
941
  close(): Promise<void>;
886
942
  [Symbol.asyncDispose](): Promise<void>;
@@ -916,8 +972,8 @@ declare class OperationCancelledError extends XpozError {
916
972
  constructor(operationId: string);
917
973
  }
918
974
 
919
- declare const VERSION = "0.6.12";
975
+ declare const VERSION = "0.7.0";
920
976
 
921
977
  declare function checkForUpdates(): Promise<void>;
922
978
 
923
- export { type AccountBilling, type AccountDetails, type AccountUsage, type AddTrackedItemsResult, AuthenticationError, BillingPeriod, CreditResetFrequency, type CreditsUsageHistory, type CursorPageResponse, CursorResult, type InstagramComment, type InstagramConnectionType, type InstagramInteractionType, type InstagramPost, type InstagramUser, NotFoundError, OperationCancelledError, OperationFailedError, OperationTimeoutError, PaginatedResult, type PaginationInfo, type PlanFeatures, type RedditComment, type RedditPost, type RedditPostWithComments, type RedditSubreddit, type RedditUser, type RemoveTrackedItemsResult, ResponseType, type SubredditWithPosts, type TiktokComment, type TiktokPost, type TiktokUser, type TrackedItem, TrackedItemPlatform, TrackedItemType, type TwitterPost, type TwitterUser, type UsageHistoryBucket, VERSION, ValidationError, XpozClient, XpozConnectionError, XpozError, checkForUpdates };
979
+ export { type AccountBilling, type AccountDetails, type AccountUsage, type AddTrackedItemsResult, AuthenticationError, BillingPeriod, CreditResetFrequency, type CreditsUsageHistory, type CursorPageResponse, CursorResult, type InstagramComment, type InstagramConnectionType, type InstagramInteractionType, type InstagramPost, type InstagramUser, NotFoundError, OperationCancelledError, OperationFailedError, OperationTimeoutError, PaginatedResult, type PaginationInfo, type PlanFeatures, type RedditComment, type RedditPost, type RedditPostWithComments, type RedditSubreddit, type RedditUser, type RemoveTrackedItemsResult, ResponseType, type SubredditWithPosts, type TiktokComment, type TiktokPost, type TiktokUser, type TrackedItem, TrackedItemPlatform, TrackedItemType, type TwitterConnectionType, type TwitterInteractionType, type TwitterLiveSortBy, type TwitterPost, type TwitterUser, type UsageHistoryBucket, VERSION, ValidationError, XpozClient, XpozConnectionError, XpozError, checkForUpdates };
package/dist/index.d.ts CHANGED
@@ -26,6 +26,13 @@ declare class RestTransport {
26
26
  get<T>(path: string, params?: QueryParams): Promise<T>;
27
27
  }
28
28
 
29
+ declare abstract class LiveNamespace {
30
+ protected transport: RestTransport;
31
+ constructor(transport: RestTransport);
32
+ protected page<T>(path: string, params: QueryParams): Promise<CursorResult<T>>;
33
+ protected single<T>(path: string, params: QueryParams): Promise<T | null>;
34
+ }
35
+
29
36
  interface CursorPageResponse<T> {
30
37
  results: T[];
31
38
  count: number;
@@ -35,6 +42,9 @@ interface CursorPageResponse<T> {
35
42
  }
36
43
  type InstagramConnectionType = "followers" | "following";
37
44
  type InstagramInteractionType = "commenters" | "likers";
45
+ type TwitterConnectionType = "followers" | "following";
46
+ type TwitterInteractionType = "commenters" | "quoters" | "retweeters";
47
+ type TwitterLiveSortBy = "relevance" | "latest";
38
48
  interface PaginationInfo {
39
49
  tableName?: string | null;
40
50
  totalRows: number;
@@ -63,6 +73,8 @@ interface InstagramPost {
63
73
  likeCount?: number | null;
64
74
  commentCount?: number | null;
65
75
  reshareCount?: number | null;
76
+ mediaRepostCount?: number | null;
77
+ saveCount?: number | null;
66
78
  videoPlayCount?: number | null;
67
79
  location?: string | null;
68
80
  genAiChatWithAiCtaInfo?: string | null;
@@ -92,6 +104,8 @@ interface InstagramUser {
92
104
  relevantPostsLikesSum?: number | null;
93
105
  relevantPostsCommentsSum?: number | null;
94
106
  relevantPostsResharesSum?: number | null;
107
+ relevantPostsMediaRepostsSum?: number | null;
108
+ relevantPostsSavesSum?: number | null;
95
109
  relevantPostsVideoPlaysSum?: number | null;
96
110
  [key: string]: unknown;
97
111
  }
@@ -117,11 +131,7 @@ interface InstagramComment {
117
131
  [key: string]: unknown;
118
132
  }
119
133
 
120
- declare class InstagramLiveNamespace {
121
- private transport;
122
- constructor(transport: RestTransport);
123
- private page;
124
- private single;
134
+ declare class InstagramLiveNamespace extends LiveNamespace {
125
135
  searchPosts(query: string, options?: {
126
136
  fields?: string[];
127
137
  cursor?: string;
@@ -154,44 +164,6 @@ declare class InstagramLiveNamespace {
154
164
  }): Promise<CursorResult<InstagramUser>>;
155
165
  }
156
166
 
157
- type FetchPage<T> = (pageNumber: number, tableName: string | null | undefined) => Promise<PaginatedResult<T>>;
158
- type FetchExport = (exportOperationId: string) => Promise<string>;
159
- declare class PaginatedResult<T> {
160
- data: T[];
161
- pagination: PaginationInfo;
162
- private _tableName;
163
- private _exportOperationId;
164
- private _fetchPage;
165
- private _fetchExport;
166
- constructor(options: {
167
- data: T[];
168
- pagination: PaginationInfo;
169
- tableName: string | null | undefined;
170
- exportOperationId: string | null | undefined;
171
- fetchPage: FetchPage<T>;
172
- fetchExport: FetchExport | null;
173
- });
174
- hasNextPage(): boolean;
175
- nextPage(): Promise<PaginatedResult<T>>;
176
- getPage(pageNumber: number): Promise<PaginatedResult<T>>;
177
- exportCsv(): Promise<string>;
178
- private _fetchPageResult;
179
- toString(): string;
180
- }
181
-
182
- type CallTool = (name: string, args: Record<string, unknown>) => Promise<Record<string, unknown>>;
183
- type RawDict = Record<string, unknown>;
184
- declare class BaseNamespace {
185
- protected callTool: CallTool;
186
- protected timeoutMs: number;
187
- constructor(callTool: CallTool, timeoutMs?: number);
188
- protected callAndMaybePoll(toolName: string, args: RawDict): Promise<RawDict>;
189
- protected buildPaginatedResult<T>(raw: RawDict, parseItem: (item: RawDict) => T, toolName: string, baseArgs: RawDict): PaginatedResult<T>;
190
- protected buildArgs(args: Record<string, unknown>): RawDict;
191
- protected extractPagination(raw: RawDict): PaginationInfo;
192
- protected extractResults(raw: RawDict): RawDict[];
193
- }
194
-
195
167
  interface TwitterPost {
196
168
  id?: string | null;
197
169
  text?: string | null;
@@ -279,6 +251,88 @@ interface TwitterUser {
279
251
  [key: string]: unknown;
280
252
  }
281
253
 
254
+ declare class TwitterLiveNamespace extends LiveNamespace {
255
+ searchPosts(query: string, options?: {
256
+ since?: string;
257
+ until?: string;
258
+ lang?: string;
259
+ countryCode?: string;
260
+ sortBy?: TwitterLiveSortBy;
261
+ fields?: string[];
262
+ cursor?: string;
263
+ }): Promise<CursorResult<TwitterPost>>;
264
+ getPostsByUser(username: string, options?: {
265
+ since?: string;
266
+ until?: string;
267
+ fields?: string[];
268
+ cursor?: string;
269
+ }): Promise<CursorResult<TwitterPost>>;
270
+ getPost(postId: string, options?: {
271
+ fields?: string[];
272
+ }): Promise<TwitterPost | null>;
273
+ getComments(postId: string, options?: {
274
+ fields?: string[];
275
+ cursor?: string;
276
+ }): Promise<CursorResult<TwitterPost>>;
277
+ getQuotes(postId: string, options?: {
278
+ fields?: string[];
279
+ cursor?: string;
280
+ }): Promise<CursorResult<TwitterPost>>;
281
+ getPostInteractingUsers(postId: string, interactionType: TwitterInteractionType, options?: {
282
+ fields?: string[];
283
+ cursor?: string;
284
+ }): Promise<CursorResult<TwitterUser>>;
285
+ searchUsers(query: string, options?: {
286
+ fields?: string[];
287
+ cursor?: string;
288
+ }): Promise<CursorResult<TwitterUser>>;
289
+ getUser(username: string, options?: {
290
+ fields?: string[];
291
+ }): Promise<TwitterUser | null>;
292
+ getUserConnections(username: string, connectionType: TwitterConnectionType, options?: {
293
+ fields?: string[];
294
+ cursor?: string;
295
+ }): Promise<CursorResult<TwitterUser>>;
296
+ }
297
+
298
+ type FetchPage<T> = (pageNumber: number, tableName: string | null | undefined) => Promise<PaginatedResult<T>>;
299
+ type FetchExport = (exportOperationId: string) => Promise<string>;
300
+ declare class PaginatedResult<T> {
301
+ data: T[];
302
+ pagination: PaginationInfo;
303
+ private _tableName;
304
+ private _exportOperationId;
305
+ private _fetchPage;
306
+ private _fetchExport;
307
+ constructor(options: {
308
+ data: T[];
309
+ pagination: PaginationInfo;
310
+ tableName: string | null | undefined;
311
+ exportOperationId: string | null | undefined;
312
+ fetchPage: FetchPage<T>;
313
+ fetchExport: FetchExport | null;
314
+ });
315
+ hasNextPage(): boolean;
316
+ nextPage(): Promise<PaginatedResult<T>>;
317
+ getPage(pageNumber: number): Promise<PaginatedResult<T>>;
318
+ exportCsv(): Promise<string>;
319
+ private _fetchPageResult;
320
+ toString(): string;
321
+ }
322
+
323
+ type CallTool = (name: string, args: Record<string, unknown>) => Promise<Record<string, unknown>>;
324
+ type RawDict = Record<string, unknown>;
325
+ declare class BaseNamespace {
326
+ protected callTool: CallTool;
327
+ protected timeoutMs: number;
328
+ constructor(callTool: CallTool, timeoutMs?: number);
329
+ protected callAndMaybePoll(toolName: string, args: RawDict): Promise<RawDict>;
330
+ protected buildPaginatedResult<T>(raw: RawDict, parseItem: (item: RawDict) => T, toolName: string, baseArgs: RawDict): PaginatedResult<T>;
331
+ protected buildArgs(args: Record<string, unknown>): RawDict;
332
+ protected extractPagination(raw: RawDict): PaginationInfo;
333
+ protected extractResults(raw: RawDict): RawDict[];
334
+ }
335
+
282
336
  declare enum ResponseType {
283
337
  Fast = "fast",
284
338
  Paging = "paging",
@@ -873,6 +927,7 @@ declare class XpozClient {
873
927
  private versionCheck;
874
928
  private restTransport;
875
929
  private instagramLiveNamespace?;
930
+ private twitterLiveNamespace?;
876
931
  constructor(options?: {
877
932
  apiKey?: string;
878
933
  serverUrl?: string;
@@ -881,6 +936,7 @@ declare class XpozClient {
881
936
  apiUrl?: string;
882
937
  });
883
938
  get instagramLive(): InstagramLiveNamespace;
939
+ get twitterLive(): TwitterLiveNamespace;
884
940
  connect(): Promise<void>;
885
941
  close(): Promise<void>;
886
942
  [Symbol.asyncDispose](): Promise<void>;
@@ -916,8 +972,8 @@ declare class OperationCancelledError extends XpozError {
916
972
  constructor(operationId: string);
917
973
  }
918
974
 
919
- declare const VERSION = "0.6.12";
975
+ declare const VERSION = "0.7.0";
920
976
 
921
977
  declare function checkForUpdates(): Promise<void>;
922
978
 
923
- export { type AccountBilling, type AccountDetails, type AccountUsage, type AddTrackedItemsResult, AuthenticationError, BillingPeriod, CreditResetFrequency, type CreditsUsageHistory, type CursorPageResponse, CursorResult, type InstagramComment, type InstagramConnectionType, type InstagramInteractionType, type InstagramPost, type InstagramUser, NotFoundError, OperationCancelledError, OperationFailedError, OperationTimeoutError, PaginatedResult, type PaginationInfo, type PlanFeatures, type RedditComment, type RedditPost, type RedditPostWithComments, type RedditSubreddit, type RedditUser, type RemoveTrackedItemsResult, ResponseType, type SubredditWithPosts, type TiktokComment, type TiktokPost, type TiktokUser, type TrackedItem, TrackedItemPlatform, TrackedItemType, type TwitterPost, type TwitterUser, type UsageHistoryBucket, VERSION, ValidationError, XpozClient, XpozConnectionError, XpozError, checkForUpdates };
979
+ export { type AccountBilling, type AccountDetails, type AccountUsage, type AddTrackedItemsResult, AuthenticationError, BillingPeriod, CreditResetFrequency, type CreditsUsageHistory, type CursorPageResponse, CursorResult, type InstagramComment, type InstagramConnectionType, type InstagramInteractionType, type InstagramPost, type InstagramUser, NotFoundError, OperationCancelledError, OperationFailedError, OperationTimeoutError, PaginatedResult, type PaginationInfo, type PlanFeatures, type RedditComment, type RedditPost, type RedditPostWithComments, type RedditSubreddit, type RedditUser, type RemoveTrackedItemsResult, ResponseType, type SubredditWithPosts, type TiktokComment, type TiktokPost, type TiktokUser, type TrackedItem, TrackedItemPlatform, TrackedItemType, type TwitterConnectionType, type TwitterInteractionType, type TwitterLiveSortBy, type TwitterPost, type TwitterUser, type UsageHistoryBucket, VERSION, ValidationError, XpozClient, XpozConnectionError, XpozError, checkForUpdates };
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.6.12";
251
+ var VERSION = "0.7.0";
252
252
 
253
253
  // src/mcp/transport.ts
254
254
  var USER_AGENT = `xpoz-ts-sdk/${VERSION}`;
@@ -401,6 +401,7 @@ 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";
404
405
  var INSTAGRAM_LIVE_ROUTES = {
405
406
  posts: `${INSTAGRAM_BASE}/posts/live`,
406
407
  userPosts: (identifier) => `${INSTAGRAM_BASE}/posts/users/${encodeURIComponent(identifier)}/live`,
@@ -411,6 +412,17 @@ var INSTAGRAM_LIVE_ROUTES = {
411
412
  user: (identifier) => `${INSTAGRAM_BASE}/users/${encodeURIComponent(identifier)}/live`,
412
413
  userConnections: (identifier) => `${INSTAGRAM_BASE}/users/${encodeURIComponent(identifier)}/connections/live`
413
414
  };
415
+ var TWITTER_LIVE_ROUTES = {
416
+ posts: `${TWITTER_BASE}/posts/live`,
417
+ userPosts: (username) => `${TWITTER_BASE}/posts/users/${encodeURIComponent(username)}/live`,
418
+ post: (postId) => `${TWITTER_BASE}/posts/${encodeURIComponent(postId)}/live`,
419
+ postComments: (postId) => `${TWITTER_BASE}/posts/${encodeURIComponent(postId)}/comments/live`,
420
+ postQuotes: (postId) => `${TWITTER_BASE}/posts/${encodeURIComponent(postId)}/quotes/live`,
421
+ postInteractingUsers: (postId) => `${TWITTER_BASE}/posts/${encodeURIComponent(postId)}/interacting-users/live`,
422
+ users: `${TWITTER_BASE}/users/live`,
423
+ user: (username) => `${TWITTER_BASE}/users/${encodeURIComponent(username)}/live`,
424
+ userConnections: (username) => `${TWITTER_BASE}/users/${encodeURIComponent(username)}/connections/live`
425
+ };
414
426
  var REST_TIMEOUT_MS = 12e4;
415
427
 
416
428
  // src/rest/transport.ts
@@ -523,8 +535,16 @@ var CursorResult = class {
523
535
  }
524
536
  };
525
537
 
526
- // src/namespaces/instagramLive.ts
527
- var STRING_ID_FIELDS = ["id", "userId", "user_id", "postId", "post_id"];
538
+ // src/namespaces/liveBase.ts
539
+ var STRING_ID_FIELDS = [
540
+ "id",
541
+ "userId",
542
+ "user_id",
543
+ "postId",
544
+ "post_id",
545
+ "authorId",
546
+ "author_id"
547
+ ];
528
548
  function coerceStringIds(item) {
529
549
  const record = item;
530
550
  for (const field of STRING_ID_FIELDS) {
@@ -537,7 +557,7 @@ function coerceStringIds(item) {
537
557
  function csvFields(fields) {
538
558
  return fields && fields.length > 0 ? fields.join(",") : void 0;
539
559
  }
540
- var InstagramLiveNamespace = class {
560
+ var LiveNamespace = class {
541
561
  transport;
542
562
  constructor(transport) {
543
563
  this.transport = transport;
@@ -555,6 +575,10 @@ var InstagramLiveNamespace = class {
555
575
  const page = await this.page(path, params);
556
576
  return page.data[0] ?? null;
557
577
  }
578
+ };
579
+
580
+ // src/namespaces/instagramLive.ts
581
+ var InstagramLiveNamespace = class extends LiveNamespace {
558
582
  async searchPosts(query, options = {}) {
559
583
  return this.page(INSTAGRAM_LIVE_ROUTES.posts, {
560
584
  q: query,
@@ -607,6 +631,73 @@ var InstagramLiveNamespace = class {
607
631
  }
608
632
  };
609
633
 
634
+ // src/namespaces/twitterLive.ts
635
+ var TwitterLiveNamespace = class extends LiveNamespace {
636
+ async searchPosts(query, options = {}) {
637
+ return this.page(TWITTER_LIVE_ROUTES.posts, {
638
+ q: query,
639
+ since: options.since,
640
+ until: options.until,
641
+ lang: options.lang,
642
+ countryCode: options.countryCode,
643
+ sortBy: options.sortBy,
644
+ fields: csvFields(options.fields),
645
+ cursor: options.cursor
646
+ });
647
+ }
648
+ async getPostsByUser(username, options = {}) {
649
+ return this.page(TWITTER_LIVE_ROUTES.userPosts(username), {
650
+ since: options.since,
651
+ until: options.until,
652
+ fields: csvFields(options.fields),
653
+ cursor: options.cursor
654
+ });
655
+ }
656
+ async getPost(postId, options = {}) {
657
+ return this.single(TWITTER_LIVE_ROUTES.post(postId), {
658
+ fields: csvFields(options.fields)
659
+ });
660
+ }
661
+ async getComments(postId, options = {}) {
662
+ return this.page(TWITTER_LIVE_ROUTES.postComments(postId), {
663
+ fields: csvFields(options.fields),
664
+ cursor: options.cursor
665
+ });
666
+ }
667
+ async getQuotes(postId, options = {}) {
668
+ return this.page(TWITTER_LIVE_ROUTES.postQuotes(postId), {
669
+ fields: csvFields(options.fields),
670
+ cursor: options.cursor
671
+ });
672
+ }
673
+ async getPostInteractingUsers(postId, interactionType, options = {}) {
674
+ return this.page(TWITTER_LIVE_ROUTES.postInteractingUsers(postId), {
675
+ interactionType,
676
+ fields: csvFields(options.fields),
677
+ cursor: options.cursor
678
+ });
679
+ }
680
+ async searchUsers(query, options = {}) {
681
+ return this.page(TWITTER_LIVE_ROUTES.users, {
682
+ q: query,
683
+ fields: csvFields(options.fields),
684
+ cursor: options.cursor
685
+ });
686
+ }
687
+ async getUser(username, options = {}) {
688
+ return this.single(TWITTER_LIVE_ROUTES.user(username), {
689
+ fields: csvFields(options.fields)
690
+ });
691
+ }
692
+ async getUserConnections(username, connectionType, options = {}) {
693
+ return this.page(TWITTER_LIVE_ROUTES.userConnections(username), {
694
+ connectionType,
695
+ fields: csvFields(options.fields),
696
+ cursor: options.cursor
697
+ });
698
+ }
699
+ };
700
+
610
701
  // src/mcp/polling.ts
611
702
  async function waitForResult(callTool, operationId, timeoutMs = DEFAULT_TIMEOUT_MS) {
612
703
  const start = Date.now();
@@ -1438,6 +1529,7 @@ var XpozClient = class {
1438
1529
  versionCheck;
1439
1530
  restTransport;
1440
1531
  instagramLiveNamespace;
1532
+ twitterLiveNamespace;
1441
1533
  constructor(options = {}) {
1442
1534
  const apiKey = options.apiKey ?? process.env[ENV_API_KEY];
1443
1535
  if (!apiKey) {
@@ -1465,6 +1557,12 @@ var XpozClient = class {
1465
1557
  }
1466
1558
  return this.instagramLiveNamespace;
1467
1559
  }
1560
+ get twitterLive() {
1561
+ if (!this.twitterLiveNamespace) {
1562
+ this.twitterLiveNamespace = new TwitterLiveNamespace(this.restTransport);
1563
+ }
1564
+ return this.twitterLiveNamespace;
1565
+ }
1468
1566
  async connect() {
1469
1567
  await this.transport.connect();
1470
1568
  if (this.versionCheck) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xpoz/xpoz",
3
- "version": "0.6.12",
3
+ "version": "0.7.0",
4
4
  "description": "TypeScript SDK for the Xpoz social media intelligence platform",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",