@xpoz/xpoz 0.1.0 → 0.2.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 +117 -11
- package/dist/index.cjs +85 -11
- package/dist/index.d.cts +26 -4
- package/dist/index.d.ts +26 -4
- package/dist/index.js +82 -10
- package/package.json +11 -2
package/README.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# Xpoz TypeScript SDK
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@xpoz/xpoz)
|
|
4
|
+
|
|
3
5
|
TypeScript SDK for the [Xpoz](https://xpoz.ai) social media intelligence platform. Query Twitter/X, Instagram, and Reddit data through a simple, typed interface.
|
|
4
6
|
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
7
9
|
```bash
|
|
8
|
-
npm install xpoz
|
|
10
|
+
npm install @xpoz/xpoz
|
|
9
11
|
```
|
|
10
12
|
|
|
11
13
|
Requires Node.js 18+.
|
|
@@ -31,6 +33,7 @@ The SDK wraps Xpoz's [MCP](https://modelcontextprotocol.io) server, abstracting
|
|
|
31
33
|
- **30 data methods** across Twitter, Instagram, and Reddit
|
|
32
34
|
- **Fully async** — all methods return `Promise<T>`
|
|
33
35
|
- **Automatic operation polling** — long-running queries are abstracted away
|
|
36
|
+
- **Response types** — choose between fast (immediate), paging (full pagination), or CSV export
|
|
34
37
|
- **Server-side pagination** — `PaginatedResult<T>` with `nextPage()`, `getPage(n)`
|
|
35
38
|
- **CSV export** — `exportCsv()` on any paginated result
|
|
36
39
|
- **Field selection** — request only the fields you need
|
|
@@ -40,7 +43,7 @@ The SDK wraps Xpoz's [MCP](https://modelcontextprotocol.io) server, abstracting
|
|
|
40
43
|
## Quick Start
|
|
41
44
|
|
|
42
45
|
```typescript
|
|
43
|
-
import { XpozClient } from "xpoz";
|
|
46
|
+
import { XpozClient, ResponseType } from "@xpoz/xpoz";
|
|
44
47
|
|
|
45
48
|
const client = new XpozClient({ apiKey: "your-api-key" });
|
|
46
49
|
await client.connect();
|
|
@@ -135,6 +138,73 @@ const user = await client.twitter.getUser("elonmusk", {
|
|
|
135
138
|
|
|
136
139
|
Requesting fewer fields significantly improves response time.
|
|
137
140
|
|
|
141
|
+
## Response Types
|
|
142
|
+
|
|
143
|
+
Search and query methods support a `responseType` option that controls how results are returned. Import the `ResponseType` enum:
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
import { XpozClient, ResponseType } from "@xpoz/xpoz";
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
| Mode | Enum Value | Behavior | Best For |
|
|
150
|
+
| --- | --- | --- | --- |
|
|
151
|
+
| **Fast** | `ResponseType.Fast` | Returns up to 300 results immediately, no async polling (default) | Quick queries, UI previews |
|
|
152
|
+
| **Paging** | `ResponseType.Paging` | Async paginated query with full dataset access | Full analysis, large datasets |
|
|
153
|
+
| **CSV** | `ResponseType.Csv` | Async bulk export, use `exportCsv()` to get download URL | Data exports |
|
|
154
|
+
|
|
155
|
+
### Fast mode (default)
|
|
156
|
+
|
|
157
|
+
The default behavior. Returns results immediately without polling. Use `limit` to constrain the number of results (max 300):
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
const results = await client.twitter.searchPosts("bitcoin", {
|
|
161
|
+
startDate: "2025-01-01",
|
|
162
|
+
responseType: ResponseType.Fast,
|
|
163
|
+
limit: 50,
|
|
164
|
+
});
|
|
165
|
+
console.log(results.data.length); // up to 50 results, returned immediately
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Paging mode
|
|
169
|
+
|
|
170
|
+
Returns paginated results with full `totalRows`, `totalPages`, and `tableName` for cursor-based navigation:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
const results = await client.twitter.searchPosts("bitcoin", {
|
|
174
|
+
startDate: "2025-01-01",
|
|
175
|
+
responseType: ResponseType.Paging, // optional — this is the default
|
|
176
|
+
});
|
|
177
|
+
console.log(results.pagination.totalRows); // total matching rows
|
|
178
|
+
if (results.hasNextPage()) {
|
|
179
|
+
const page2 = await results.nextPage();
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### CSV mode
|
|
184
|
+
|
|
185
|
+
Initiates an async export. Call `exportCsv()` on the result to poll the export operation and get a download URL:
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
const results = await client.twitter.searchPosts("bitcoin", {
|
|
189
|
+
startDate: "2025-01-01",
|
|
190
|
+
responseType: ResponseType.Csv,
|
|
191
|
+
});
|
|
192
|
+
const downloadUrl = await results.exportCsv();
|
|
193
|
+
console.log(downloadUrl); // URL to download the CSV file
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Methods supporting `responseType` and `limit`
|
|
197
|
+
|
|
198
|
+
The following methods accept both `responseType` and `limit`:
|
|
199
|
+
|
|
200
|
+
- `twitter.getPostsByAuthor()`, `twitter.searchPosts()`, `twitter.getUsersByKeywords()`
|
|
201
|
+
- `instagram.getPostsByUser()`, `instagram.searchPosts()`, `instagram.getUsersByKeywords()`
|
|
202
|
+
- `reddit.searchPosts()`
|
|
203
|
+
|
|
204
|
+
These methods accept `limit` only:
|
|
205
|
+
|
|
206
|
+
- `twitter.searchUsers()`, `instagram.searchUsers()`, `reddit.searchUsers()`, `reddit.searchSubreddits()`
|
|
207
|
+
|
|
138
208
|
## Query Syntax
|
|
139
209
|
|
|
140
210
|
The `query` parameter on all `search*` and `get*ByKeywords` methods supports a Lucene-style full-text syntax across Twitter, Instagram, and Reddit.
|
|
@@ -189,7 +259,8 @@ import {
|
|
|
189
259
|
OperationTimeoutError,
|
|
190
260
|
OperationFailedError,
|
|
191
261
|
OperationCancelledError,
|
|
192
|
-
|
|
262
|
+
ResponseType,
|
|
263
|
+
} from "@xpoz/xpoz";
|
|
193
264
|
|
|
194
265
|
try {
|
|
195
266
|
const user = await client.twitter.getUser("nonexistent_user_12345");
|
|
@@ -226,10 +297,11 @@ const user = await client.twitter.getUser("44196397", { identifierType: "id" });
|
|
|
226
297
|
|
|
227
298
|
#### `searchUsers(name, options?) -> Promise<TwitterUser[]>`
|
|
228
299
|
|
|
229
|
-
Search users by name or username. Returns up to 10 results.
|
|
300
|
+
Search users by name or username. Returns up to 10 results by default. Use `limit` to adjust.
|
|
230
301
|
|
|
231
302
|
```typescript
|
|
232
303
|
const users = await client.twitter.searchUsers("elon");
|
|
304
|
+
const topFive = await client.twitter.searchUsers("elon", { limit: 5 });
|
|
233
305
|
```
|
|
234
306
|
|
|
235
307
|
#### `getUserConnections(username, connectionType, options?) -> Promise<PaginatedResult<TwitterUser>>`
|
|
@@ -243,11 +315,13 @@ const following = await client.twitter.getUserConnections("elonmusk", "following
|
|
|
243
315
|
|
|
244
316
|
#### `getUsersByKeywords(query, options?) -> Promise<PaginatedResult<TwitterUser>>`
|
|
245
317
|
|
|
246
|
-
Find users who authored posts matching a keyword query.
|
|
318
|
+
Find users who authored posts matching a keyword query. Supports `responseType` and `limit`.
|
|
247
319
|
|
|
248
320
|
```typescript
|
|
249
321
|
const users = await client.twitter.getUsersByKeywords('"machine learning"', {
|
|
250
322
|
fields: ["username", "name", "followersCount"],
|
|
323
|
+
responseType: ResponseType.Fast,
|
|
324
|
+
limit: 20,
|
|
251
325
|
});
|
|
252
326
|
```
|
|
253
327
|
|
|
@@ -261,17 +335,19 @@ const tweets = await client.twitter.getPostsByIds(["1234567890", "0987654321"]);
|
|
|
261
335
|
|
|
262
336
|
#### `getPostsByAuthor(identifier, options?) -> Promise<PaginatedResult<TwitterPost>>`
|
|
263
337
|
|
|
264
|
-
Get all posts by an author with optional date filtering.
|
|
338
|
+
Get all posts by an author with optional date filtering. Supports `responseType` and `limit`.
|
|
265
339
|
|
|
266
340
|
```typescript
|
|
267
341
|
const results = await client.twitter.getPostsByAuthor("elonmusk", {
|
|
268
342
|
startDate: "2025-01-01",
|
|
343
|
+
responseType: ResponseType.Fast,
|
|
344
|
+
limit: 100,
|
|
269
345
|
});
|
|
270
346
|
```
|
|
271
347
|
|
|
272
348
|
#### `searchPosts(query, options?) -> Promise<PaginatedResult<TwitterPost>>`
|
|
273
349
|
|
|
274
|
-
Full-text search with filters. Supports exact phrases (`"machine learning"`), boolean operators (`AI AND python`), and parentheses.
|
|
350
|
+
Full-text search with filters. Supports exact phrases (`"machine learning"`), boolean operators (`AI AND python`), and parentheses. Supports `responseType` and `limit`.
|
|
275
351
|
|
|
276
352
|
```typescript
|
|
277
353
|
const results = await client.twitter.searchPosts('"artificial intelligence" AND ethics', {
|
|
@@ -279,6 +355,8 @@ const results = await client.twitter.searchPosts('"artificial intelligence" AND
|
|
|
279
355
|
endDate: "2025-06-01",
|
|
280
356
|
language: "en",
|
|
281
357
|
fields: ["id", "text", "likeCount", "authorUsername", "createdAtDate"],
|
|
358
|
+
responseType: ResponseType.Fast,
|
|
359
|
+
limit: 50,
|
|
282
360
|
});
|
|
283
361
|
```
|
|
284
362
|
|
|
@@ -336,8 +414,11 @@ console.log(`${user.fullName} — ${user.followerCount?.toLocaleString()} follow
|
|
|
336
414
|
|
|
337
415
|
#### `searchUsers(name, options?) -> Promise<InstagramUser[]>`
|
|
338
416
|
|
|
417
|
+
Search users by name. Use `limit` to adjust the number of results.
|
|
418
|
+
|
|
339
419
|
```typescript
|
|
340
420
|
const users = await client.instagram.searchUsers("nasa");
|
|
421
|
+
const topThree = await client.instagram.searchUsers("nasa", { limit: 3 });
|
|
341
422
|
```
|
|
342
423
|
|
|
343
424
|
#### `getUserConnections(username, connectionType, options?) -> Promise<PaginatedResult<InstagramUser>>`
|
|
@@ -348,8 +429,13 @@ const followers = await client.instagram.getUserConnections("instagram", "follow
|
|
|
348
429
|
|
|
349
430
|
#### `getUsersByKeywords(query, options?) -> Promise<PaginatedResult<InstagramUser>>`
|
|
350
431
|
|
|
432
|
+
Find users who authored posts matching a keyword query. Supports `responseType` and `limit`.
|
|
433
|
+
|
|
351
434
|
```typescript
|
|
352
|
-
const users = await client.instagram.getUsersByKeywords('"sustainable fashion"'
|
|
435
|
+
const users = await client.instagram.getUsersByKeywords('"sustainable fashion"', {
|
|
436
|
+
responseType: ResponseType.Fast,
|
|
437
|
+
limit: 20,
|
|
438
|
+
});
|
|
353
439
|
```
|
|
354
440
|
|
|
355
441
|
#### `getPostsByIds(postIds, options?) -> Promise<InstagramPost[]>`
|
|
@@ -362,14 +448,24 @@ const posts = await client.instagram.getPostsByIds(["3606450040306139062_4836333
|
|
|
362
448
|
|
|
363
449
|
#### `getPostsByUser(identifier, options?) -> Promise<PaginatedResult<InstagramPost>>`
|
|
364
450
|
|
|
451
|
+
Get all posts by a user. Supports `responseType` and `limit`.
|
|
452
|
+
|
|
365
453
|
```typescript
|
|
366
|
-
const results = await client.instagram.getPostsByUser("nasa"
|
|
454
|
+
const results = await client.instagram.getPostsByUser("nasa", {
|
|
455
|
+
responseType: ResponseType.Fast,
|
|
456
|
+
limit: 50,
|
|
457
|
+
});
|
|
367
458
|
```
|
|
368
459
|
|
|
369
460
|
#### `searchPosts(query, options?) -> Promise<PaginatedResult<InstagramPost>>`
|
|
370
461
|
|
|
462
|
+
Full-text search with filters. Supports `responseType` and `limit`.
|
|
463
|
+
|
|
371
464
|
```typescript
|
|
372
|
-
const results = await client.instagram.searchPosts("travel photography"
|
|
465
|
+
const results = await client.instagram.searchPosts("travel photography", {
|
|
466
|
+
responseType: ResponseType.Fast,
|
|
467
|
+
limit: 30,
|
|
468
|
+
});
|
|
373
469
|
```
|
|
374
470
|
|
|
375
471
|
#### `getComments(postId, options?) -> Promise<PaginatedResult<InstagramComment>>`
|
|
@@ -402,8 +498,11 @@ console.log(`${user.username} — ${user.totalKarma?.toLocaleString()} karma`);
|
|
|
402
498
|
|
|
403
499
|
#### `searchUsers(name, options?) -> Promise<RedditUser[]>`
|
|
404
500
|
|
|
501
|
+
Search users by name. Use `limit` to adjust the number of results.
|
|
502
|
+
|
|
405
503
|
```typescript
|
|
406
504
|
const users = await client.reddit.searchUsers("spez");
|
|
505
|
+
const topThree = await client.reddit.searchUsers("spez", { limit: 3 });
|
|
407
506
|
```
|
|
408
507
|
|
|
409
508
|
#### `getUsersByKeywords(query, options?) -> Promise<PaginatedResult<RedditUser>>`
|
|
@@ -416,13 +515,15 @@ const users = await client.reddit.getUsersByKeywords('"machine learning"', {
|
|
|
416
515
|
|
|
417
516
|
#### `searchPosts(query, options?) -> Promise<PaginatedResult<RedditPost>>`
|
|
418
517
|
|
|
419
|
-
`sort`: `"relevance"`, `"hot"`, `"top"`, `"new"`, `"comments"`. `time`: `"hour"`, `"day"`, `"week"`, `"month"`, `"year"`, `"all"`.
|
|
518
|
+
`sort`: `"relevance"`, `"hot"`, `"top"`, `"new"`, `"comments"`. `time`: `"hour"`, `"day"`, `"week"`, `"month"`, `"year"`, `"all"`. Supports `responseType` and `limit`.
|
|
420
519
|
|
|
421
520
|
```typescript
|
|
422
521
|
const results = await client.reddit.searchPosts("python tutorial", {
|
|
423
522
|
subreddit: "learnpython",
|
|
424
523
|
sort: "top",
|
|
425
524
|
time: "month",
|
|
525
|
+
responseType: ResponseType.Fast,
|
|
526
|
+
limit: 25,
|
|
426
527
|
});
|
|
427
528
|
```
|
|
428
529
|
|
|
@@ -448,8 +549,11 @@ const comments = await client.reddit.searchComments("helpful tip", {
|
|
|
448
549
|
|
|
449
550
|
#### `searchSubreddits(query, options?) -> Promise<RedditSubreddit[]>`
|
|
450
551
|
|
|
552
|
+
Search subreddits by name. Use `limit` to adjust the number of results.
|
|
553
|
+
|
|
451
554
|
```typescript
|
|
452
555
|
const subs = await client.reddit.searchSubreddits("machine learning");
|
|
556
|
+
const topFive = await client.reddit.searchSubreddits("machine learning", { limit: 5 });
|
|
453
557
|
```
|
|
454
558
|
|
|
455
559
|
#### `getSubredditWithPosts(subredditName, options?) -> Promise<SubredditWithPosts>`
|
|
@@ -634,12 +738,14 @@ All fields are optional and typed as their respective TypeScript types. Unknown
|
|
|
634
738
|
- `post: RedditPost`
|
|
635
739
|
- `comments: RedditComment[]`
|
|
636
740
|
- `commentsPagination: PaginationInfo | null`
|
|
741
|
+
- `commentsTableName: string | null`
|
|
637
742
|
|
|
638
743
|
**`SubredditWithPosts`** — returned by `getSubredditWithPosts()`:
|
|
639
744
|
|
|
640
745
|
- `subreddit: RedditSubreddit`
|
|
641
746
|
- `posts: RedditPost[]`
|
|
642
747
|
- `postsPagination: PaginationInfo | null`
|
|
748
|
+
- `postsTableName: string | null`
|
|
643
749
|
|
|
644
750
|
---
|
|
645
751
|
|
package/dist/index.cjs
CHANGED
|
@@ -25,10 +25,12 @@ __export(index_exports, {
|
|
|
25
25
|
OperationFailedError: () => OperationFailedError,
|
|
26
26
|
OperationTimeoutError: () => OperationTimeoutError,
|
|
27
27
|
PaginatedResult: () => PaginatedResult,
|
|
28
|
+
ResponseType: () => ResponseType,
|
|
28
29
|
VERSION: () => VERSION,
|
|
29
30
|
XpozClient: () => XpozClient,
|
|
30
31
|
XpozConnectionError: () => XpozConnectionError,
|
|
31
|
-
XpozError: () => XpozError
|
|
32
|
+
XpozError: () => XpozError,
|
|
33
|
+
checkForUpdates: () => checkForUpdates
|
|
32
34
|
});
|
|
33
35
|
module.exports = __toCommonJS(index_exports);
|
|
34
36
|
|
|
@@ -282,7 +284,7 @@ function coerce(value) {
|
|
|
282
284
|
}
|
|
283
285
|
|
|
284
286
|
// src/version.ts
|
|
285
|
-
var VERSION = "0.1
|
|
287
|
+
var VERSION = "0.2.1";
|
|
286
288
|
|
|
287
289
|
// src/mcp/transport.ts
|
|
288
290
|
var USER_AGENT = `xpoz-ts-sdk/${VERSION}`;
|
|
@@ -395,6 +397,12 @@ var OperationCancelledError = class extends XpozError {
|
|
|
395
397
|
var DEFAULT_SERVER_URL = "https://mcp.xpoz.ai/mcp";
|
|
396
398
|
var ENV_API_KEY = "XPOZ_API_KEY";
|
|
397
399
|
var ENV_SERVER_URL = "XPOZ_SERVER_URL";
|
|
400
|
+
var ResponseType = /* @__PURE__ */ ((ResponseType2) => {
|
|
401
|
+
ResponseType2["Fast"] = "fast";
|
|
402
|
+
ResponseType2["Paging"] = "paging";
|
|
403
|
+
ResponseType2["Csv"] = "csv";
|
|
404
|
+
return ResponseType2;
|
|
405
|
+
})(ResponseType || {});
|
|
398
406
|
var POLL_INTERVAL_MS = 5e3;
|
|
399
407
|
var DEFAULT_TIMEOUT_MS = 3e5;
|
|
400
408
|
|
|
@@ -499,6 +507,9 @@ var BaseNamespace = class {
|
|
|
499
507
|
}
|
|
500
508
|
async callAndMaybePoll(toolName, args) {
|
|
501
509
|
const result = await this.callTool(toolName, args);
|
|
510
|
+
if ("results" in result) {
|
|
511
|
+
return result;
|
|
512
|
+
}
|
|
502
513
|
const operationId = result["operationId"];
|
|
503
514
|
if (operationId) {
|
|
504
515
|
return waitForResult(this.callTool, operationId, this.timeoutMs);
|
|
@@ -517,7 +528,11 @@ var BaseNamespace = class {
|
|
|
517
528
|
return this.buildPaginatedResult(pageRaw, parseItem, toolName, baseArgs);
|
|
518
529
|
};
|
|
519
530
|
const fetchExport = async (opId) => {
|
|
520
|
-
const pollResult = await waitForResult(
|
|
531
|
+
const pollResult = await waitForResult(
|
|
532
|
+
this.callTool,
|
|
533
|
+
opId,
|
|
534
|
+
this.timeoutMs
|
|
535
|
+
);
|
|
521
536
|
return pollResult["downloadUrl"] ?? "";
|
|
522
537
|
};
|
|
523
538
|
return new PaginatedResult({
|
|
@@ -593,12 +608,13 @@ var TwitterNamespace = class extends BaseNamespace {
|
|
|
593
608
|
}
|
|
594
609
|
async getPostsByAuthor(identifier, options = {}) {
|
|
595
610
|
const args = this.buildArgs({
|
|
596
|
-
identifier,
|
|
597
|
-
identifierType: options.identifierType ?? "username",
|
|
611
|
+
username: identifier,
|
|
598
612
|
fields: options.fields,
|
|
599
613
|
startDate: options.startDate,
|
|
600
614
|
endDate: options.endDate,
|
|
601
|
-
forceLatest: options.forceLatest
|
|
615
|
+
forceLatest: options.forceLatest,
|
|
616
|
+
responseType: options.responseType,
|
|
617
|
+
limit: options.limit
|
|
602
618
|
});
|
|
603
619
|
const result = await this.callAndMaybePoll(GET_TWITTER_POSTS_BY_AUTHOR, args);
|
|
604
620
|
return this.buildPaginatedResult(result, parseTwitterPost, GET_TWITTER_POSTS_BY_AUTHOR, args);
|
|
@@ -613,9 +629,10 @@ var TwitterNamespace = class extends BaseNamespace {
|
|
|
613
629
|
authorId: options.authorId,
|
|
614
630
|
language: options.language,
|
|
615
631
|
forceLatest: options.forceLatest,
|
|
616
|
-
responseType: options.responseType
|
|
632
|
+
responseType: options.responseType,
|
|
633
|
+
limit: options.limit
|
|
617
634
|
});
|
|
618
|
-
if (options.responseType === "csv") {
|
|
635
|
+
if (options.responseType === "csv" /* Csv */) {
|
|
619
636
|
const raw = await this.callTool(SEARCH_TWITTER_POSTS, args);
|
|
620
637
|
const exportOpId = raw["operationId"] ?? raw["dataDumpExportOperationId"] ?? null;
|
|
621
638
|
const csvRaw = { results: [], dataDumpExportOperationId: exportOpId };
|
|
@@ -726,7 +743,9 @@ var InstagramNamespace = class extends BaseNamespace {
|
|
|
726
743
|
fields: options.fields,
|
|
727
744
|
startDate: options.startDate,
|
|
728
745
|
endDate: options.endDate,
|
|
729
|
-
forceLatest: options.forceLatest
|
|
746
|
+
forceLatest: options.forceLatest,
|
|
747
|
+
responseType: options.responseType,
|
|
748
|
+
limit: options.limit
|
|
730
749
|
});
|
|
731
750
|
const result = await this.callAndMaybePoll(GET_INSTAGRAM_POSTS_BY_USER, args);
|
|
732
751
|
return this.buildPaginatedResult(
|
|
@@ -737,7 +756,15 @@ var InstagramNamespace = class extends BaseNamespace {
|
|
|
737
756
|
);
|
|
738
757
|
}
|
|
739
758
|
async searchPosts(query, options = {}) {
|
|
740
|
-
const args = this.buildArgs({
|
|
759
|
+
const args = this.buildArgs({
|
|
760
|
+
query,
|
|
761
|
+
fields: options.fields,
|
|
762
|
+
startDate: options.startDate,
|
|
763
|
+
endDate: options.endDate,
|
|
764
|
+
forceLatest: options.forceLatest,
|
|
765
|
+
responseType: options.responseType,
|
|
766
|
+
limit: options.limit
|
|
767
|
+
});
|
|
741
768
|
const result = await this.callAndMaybePoll(SEARCH_INSTAGRAM_POSTS, args);
|
|
742
769
|
return this.buildPaginatedResult(result, parsePost, SEARCH_INSTAGRAM_POSTS, args);
|
|
743
770
|
}
|
|
@@ -904,12 +931,53 @@ var RedditNamespace = class extends BaseNamespace {
|
|
|
904
931
|
}
|
|
905
932
|
};
|
|
906
933
|
|
|
934
|
+
// src/versionCheck.ts
|
|
935
|
+
var NPM_REGISTRY_URL = "https://registry.npmjs.org/@xpoz/xpoz/latest";
|
|
936
|
+
var CHECK_TIMEOUT_MS = 3e3;
|
|
937
|
+
var PACKAGE_NAME = "@xpoz/xpoz";
|
|
938
|
+
var hasWarned = false;
|
|
939
|
+
async function checkForUpdates() {
|
|
940
|
+
if (hasWarned) return;
|
|
941
|
+
try {
|
|
942
|
+
const controller = new AbortController();
|
|
943
|
+
const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS);
|
|
944
|
+
const response = await fetch(NPM_REGISTRY_URL, {
|
|
945
|
+
signal: controller.signal,
|
|
946
|
+
headers: { Accept: "application/json" }
|
|
947
|
+
});
|
|
948
|
+
clearTimeout(timeout);
|
|
949
|
+
if (!response.ok) return;
|
|
950
|
+
const data = await response.json();
|
|
951
|
+
const latest = data.version;
|
|
952
|
+
if (!latest || latest === VERSION) return;
|
|
953
|
+
if (isNewerVersion(latest, VERSION)) {
|
|
954
|
+
hasWarned = true;
|
|
955
|
+
console.warn(
|
|
956
|
+
`[xpoz] A newer version of ${PACKAGE_NAME} is available: ${latest} (current: ${VERSION}). Run \`npm install ${PACKAGE_NAME}@latest\` to update.`
|
|
957
|
+
);
|
|
958
|
+
}
|
|
959
|
+
} catch {
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
function isNewerVersion(latestVersion, currentVersion) {
|
|
963
|
+
const latestVersionParts = latestVersion.split(".").map(Number);
|
|
964
|
+
const currentVersionParts = currentVersion.split(".").map(Number);
|
|
965
|
+
for (let i = 0; i < 3; i++) {
|
|
966
|
+
const latestVersionPart = latestVersionParts[i] ?? 0;
|
|
967
|
+
const currentVersionPart = currentVersionParts[i] ?? 0;
|
|
968
|
+
if (latestVersionPart > currentVersionPart) return true;
|
|
969
|
+
if (latestVersionPart < currentVersionPart) return false;
|
|
970
|
+
}
|
|
971
|
+
return false;
|
|
972
|
+
}
|
|
973
|
+
|
|
907
974
|
// src/client.ts
|
|
908
975
|
var XpozClient = class {
|
|
909
976
|
twitter;
|
|
910
977
|
instagram;
|
|
911
978
|
reddit;
|
|
912
979
|
transport;
|
|
980
|
+
versionCheck;
|
|
913
981
|
constructor(options = {}) {
|
|
914
982
|
const apiKey = options.apiKey ?? process.env[ENV_API_KEY];
|
|
915
983
|
if (!apiKey) {
|
|
@@ -917,6 +985,7 @@ var XpozClient = class {
|
|
|
917
985
|
`API key required. Get your token at http://xpoz.ai/get-token?utm_source=ts_sdk&utm_medium=sdk (login \u2192 copy token), then pass it as apiKey or set the ${ENV_API_KEY} environment variable.`
|
|
918
986
|
);
|
|
919
987
|
}
|
|
988
|
+
this.versionCheck = options.versionCheck ?? true;
|
|
920
989
|
const serverUrl = options.serverUrl ?? process.env[ENV_SERVER_URL] ?? DEFAULT_SERVER_URL;
|
|
921
990
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
922
991
|
this.transport = new McpTransport(serverUrl, apiKey);
|
|
@@ -927,6 +996,9 @@ var XpozClient = class {
|
|
|
927
996
|
}
|
|
928
997
|
async connect() {
|
|
929
998
|
await this.transport.connect();
|
|
999
|
+
if (this.versionCheck) {
|
|
1000
|
+
checkForUpdates();
|
|
1001
|
+
}
|
|
930
1002
|
}
|
|
931
1003
|
async close() {
|
|
932
1004
|
await this.transport.close();
|
|
@@ -942,8 +1014,10 @@ var XpozClient = class {
|
|
|
942
1014
|
OperationFailedError,
|
|
943
1015
|
OperationTimeoutError,
|
|
944
1016
|
PaginatedResult,
|
|
1017
|
+
ResponseType,
|
|
945
1018
|
VERSION,
|
|
946
1019
|
XpozClient,
|
|
947
1020
|
XpozConnectionError,
|
|
948
|
-
XpozError
|
|
1021
|
+
XpozError,
|
|
1022
|
+
checkForUpdates
|
|
949
1023
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -144,17 +144,24 @@ interface TwitterUser {
|
|
|
144
144
|
[key: string]: unknown;
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
declare enum ResponseType {
|
|
148
|
+
Fast = "fast",
|
|
149
|
+
Paging = "paging",
|
|
150
|
+
Csv = "csv"
|
|
151
|
+
}
|
|
152
|
+
|
|
147
153
|
declare class TwitterNamespace extends BaseNamespace {
|
|
148
154
|
getPostsByIds(postIds: string[], options?: {
|
|
149
155
|
fields?: string[];
|
|
150
156
|
forceLatest?: boolean;
|
|
151
157
|
}): Promise<TwitterPost[]>;
|
|
152
158
|
getPostsByAuthor(identifier: string, options?: {
|
|
153
|
-
identifierType?: string;
|
|
154
159
|
fields?: string[];
|
|
155
160
|
startDate?: string;
|
|
156
161
|
endDate?: string;
|
|
157
162
|
forceLatest?: boolean;
|
|
163
|
+
responseType?: ResponseType;
|
|
164
|
+
limit?: number;
|
|
158
165
|
}): Promise<PaginatedResult<TwitterPost>>;
|
|
159
166
|
searchPosts(query: string, options?: {
|
|
160
167
|
fields?: string[];
|
|
@@ -164,7 +171,8 @@ declare class TwitterNamespace extends BaseNamespace {
|
|
|
164
171
|
authorId?: string;
|
|
165
172
|
language?: string;
|
|
166
173
|
forceLatest?: boolean;
|
|
167
|
-
responseType?:
|
|
174
|
+
responseType?: ResponseType;
|
|
175
|
+
limit?: number;
|
|
168
176
|
}): Promise<PaginatedResult<TwitterPost>>;
|
|
169
177
|
getRetweets(postId: string, options?: {
|
|
170
178
|
fields?: string[];
|
|
@@ -206,6 +214,8 @@ declare class TwitterNamespace extends BaseNamespace {
|
|
|
206
214
|
endDate?: string;
|
|
207
215
|
language?: string;
|
|
208
216
|
forceLatest?: boolean;
|
|
217
|
+
responseType?: ResponseType;
|
|
218
|
+
limit?: number;
|
|
209
219
|
}): Promise<PaginatedResult<TwitterUser>>;
|
|
210
220
|
}
|
|
211
221
|
|
|
@@ -300,12 +310,16 @@ declare class InstagramNamespace extends BaseNamespace {
|
|
|
300
310
|
startDate?: string;
|
|
301
311
|
endDate?: string;
|
|
302
312
|
forceLatest?: boolean;
|
|
313
|
+
responseType?: ResponseType;
|
|
314
|
+
limit?: number;
|
|
303
315
|
}): Promise<PaginatedResult<InstagramPost>>;
|
|
304
316
|
searchPosts(query: string, options?: {
|
|
305
317
|
fields?: string[];
|
|
306
318
|
startDate?: string;
|
|
307
319
|
endDate?: string;
|
|
308
320
|
forceLatest?: boolean;
|
|
321
|
+
responseType?: ResponseType;
|
|
322
|
+
limit?: number;
|
|
309
323
|
}): Promise<PaginatedResult<InstagramPost>>;
|
|
310
324
|
getComments(postId: string, options?: {
|
|
311
325
|
fields?: string[];
|
|
@@ -334,6 +348,8 @@ declare class InstagramNamespace extends BaseNamespace {
|
|
|
334
348
|
startDate?: string;
|
|
335
349
|
endDate?: string;
|
|
336
350
|
forceLatest?: boolean;
|
|
351
|
+
responseType?: ResponseType;
|
|
352
|
+
limit?: number;
|
|
337
353
|
}): Promise<PaginatedResult<InstagramUser>>;
|
|
338
354
|
}
|
|
339
355
|
|
|
@@ -490,6 +506,8 @@ declare class RedditNamespace extends BaseNamespace {
|
|
|
490
506
|
time?: string;
|
|
491
507
|
subreddit?: string;
|
|
492
508
|
forceLatest?: boolean;
|
|
509
|
+
responseType?: ResponseType;
|
|
510
|
+
limit?: number;
|
|
493
511
|
}): Promise<PaginatedResult<RedditPost>>;
|
|
494
512
|
getPostWithComments(postId: string, options?: {
|
|
495
513
|
postFields?: string[];
|
|
@@ -540,10 +558,12 @@ declare class XpozClient {
|
|
|
540
558
|
instagram: InstagramNamespace;
|
|
541
559
|
reddit: RedditNamespace;
|
|
542
560
|
private transport;
|
|
561
|
+
private versionCheck;
|
|
543
562
|
constructor(options?: {
|
|
544
563
|
apiKey?: string;
|
|
545
564
|
serverUrl?: string;
|
|
546
565
|
timeoutMs?: number;
|
|
566
|
+
versionCheck?: boolean;
|
|
547
567
|
});
|
|
548
568
|
connect(): Promise<void>;
|
|
549
569
|
close(): Promise<void>;
|
|
@@ -574,6 +594,8 @@ declare class OperationCancelledError extends XpozError {
|
|
|
574
594
|
constructor(operationId: string);
|
|
575
595
|
}
|
|
576
596
|
|
|
577
|
-
declare const VERSION = "0.1
|
|
597
|
+
declare const VERSION = "0.2.1";
|
|
598
|
+
|
|
599
|
+
declare function checkForUpdates(): Promise<void>;
|
|
578
600
|
|
|
579
|
-
export { AuthenticationError, type InstagramComment, type InstagramPost, type InstagramUser, OperationCancelledError, OperationFailedError, OperationTimeoutError, PaginatedResult, type PaginationInfo, type RedditComment, type RedditPost, type RedditPostWithComments, type RedditSubreddit, type RedditUser, type SubredditWithPosts, type TwitterPost, type TwitterUser, VERSION, XpozClient, XpozConnectionError, XpozError };
|
|
601
|
+
export { AuthenticationError, type InstagramComment, type InstagramPost, type InstagramUser, OperationCancelledError, OperationFailedError, OperationTimeoutError, PaginatedResult, type PaginationInfo, type RedditComment, type RedditPost, type RedditPostWithComments, type RedditSubreddit, type RedditUser, ResponseType, type SubredditWithPosts, type TwitterPost, type TwitterUser, VERSION, XpozClient, XpozConnectionError, XpozError, checkForUpdates };
|
package/dist/index.d.ts
CHANGED
|
@@ -144,17 +144,24 @@ interface TwitterUser {
|
|
|
144
144
|
[key: string]: unknown;
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
declare enum ResponseType {
|
|
148
|
+
Fast = "fast",
|
|
149
|
+
Paging = "paging",
|
|
150
|
+
Csv = "csv"
|
|
151
|
+
}
|
|
152
|
+
|
|
147
153
|
declare class TwitterNamespace extends BaseNamespace {
|
|
148
154
|
getPostsByIds(postIds: string[], options?: {
|
|
149
155
|
fields?: string[];
|
|
150
156
|
forceLatest?: boolean;
|
|
151
157
|
}): Promise<TwitterPost[]>;
|
|
152
158
|
getPostsByAuthor(identifier: string, options?: {
|
|
153
|
-
identifierType?: string;
|
|
154
159
|
fields?: string[];
|
|
155
160
|
startDate?: string;
|
|
156
161
|
endDate?: string;
|
|
157
162
|
forceLatest?: boolean;
|
|
163
|
+
responseType?: ResponseType;
|
|
164
|
+
limit?: number;
|
|
158
165
|
}): Promise<PaginatedResult<TwitterPost>>;
|
|
159
166
|
searchPosts(query: string, options?: {
|
|
160
167
|
fields?: string[];
|
|
@@ -164,7 +171,8 @@ declare class TwitterNamespace extends BaseNamespace {
|
|
|
164
171
|
authorId?: string;
|
|
165
172
|
language?: string;
|
|
166
173
|
forceLatest?: boolean;
|
|
167
|
-
responseType?:
|
|
174
|
+
responseType?: ResponseType;
|
|
175
|
+
limit?: number;
|
|
168
176
|
}): Promise<PaginatedResult<TwitterPost>>;
|
|
169
177
|
getRetweets(postId: string, options?: {
|
|
170
178
|
fields?: string[];
|
|
@@ -206,6 +214,8 @@ declare class TwitterNamespace extends BaseNamespace {
|
|
|
206
214
|
endDate?: string;
|
|
207
215
|
language?: string;
|
|
208
216
|
forceLatest?: boolean;
|
|
217
|
+
responseType?: ResponseType;
|
|
218
|
+
limit?: number;
|
|
209
219
|
}): Promise<PaginatedResult<TwitterUser>>;
|
|
210
220
|
}
|
|
211
221
|
|
|
@@ -300,12 +310,16 @@ declare class InstagramNamespace extends BaseNamespace {
|
|
|
300
310
|
startDate?: string;
|
|
301
311
|
endDate?: string;
|
|
302
312
|
forceLatest?: boolean;
|
|
313
|
+
responseType?: ResponseType;
|
|
314
|
+
limit?: number;
|
|
303
315
|
}): Promise<PaginatedResult<InstagramPost>>;
|
|
304
316
|
searchPosts(query: string, options?: {
|
|
305
317
|
fields?: string[];
|
|
306
318
|
startDate?: string;
|
|
307
319
|
endDate?: string;
|
|
308
320
|
forceLatest?: boolean;
|
|
321
|
+
responseType?: ResponseType;
|
|
322
|
+
limit?: number;
|
|
309
323
|
}): Promise<PaginatedResult<InstagramPost>>;
|
|
310
324
|
getComments(postId: string, options?: {
|
|
311
325
|
fields?: string[];
|
|
@@ -334,6 +348,8 @@ declare class InstagramNamespace extends BaseNamespace {
|
|
|
334
348
|
startDate?: string;
|
|
335
349
|
endDate?: string;
|
|
336
350
|
forceLatest?: boolean;
|
|
351
|
+
responseType?: ResponseType;
|
|
352
|
+
limit?: number;
|
|
337
353
|
}): Promise<PaginatedResult<InstagramUser>>;
|
|
338
354
|
}
|
|
339
355
|
|
|
@@ -490,6 +506,8 @@ declare class RedditNamespace extends BaseNamespace {
|
|
|
490
506
|
time?: string;
|
|
491
507
|
subreddit?: string;
|
|
492
508
|
forceLatest?: boolean;
|
|
509
|
+
responseType?: ResponseType;
|
|
510
|
+
limit?: number;
|
|
493
511
|
}): Promise<PaginatedResult<RedditPost>>;
|
|
494
512
|
getPostWithComments(postId: string, options?: {
|
|
495
513
|
postFields?: string[];
|
|
@@ -540,10 +558,12 @@ declare class XpozClient {
|
|
|
540
558
|
instagram: InstagramNamespace;
|
|
541
559
|
reddit: RedditNamespace;
|
|
542
560
|
private transport;
|
|
561
|
+
private versionCheck;
|
|
543
562
|
constructor(options?: {
|
|
544
563
|
apiKey?: string;
|
|
545
564
|
serverUrl?: string;
|
|
546
565
|
timeoutMs?: number;
|
|
566
|
+
versionCheck?: boolean;
|
|
547
567
|
});
|
|
548
568
|
connect(): Promise<void>;
|
|
549
569
|
close(): Promise<void>;
|
|
@@ -574,6 +594,8 @@ declare class OperationCancelledError extends XpozError {
|
|
|
574
594
|
constructor(operationId: string);
|
|
575
595
|
}
|
|
576
596
|
|
|
577
|
-
declare const VERSION = "0.1
|
|
597
|
+
declare const VERSION = "0.2.1";
|
|
598
|
+
|
|
599
|
+
declare function checkForUpdates(): Promise<void>;
|
|
578
600
|
|
|
579
|
-
export { AuthenticationError, type InstagramComment, type InstagramPost, type InstagramUser, OperationCancelledError, OperationFailedError, OperationTimeoutError, PaginatedResult, type PaginationInfo, type RedditComment, type RedditPost, type RedditPostWithComments, type RedditSubreddit, type RedditUser, type SubredditWithPosts, type TwitterPost, type TwitterUser, VERSION, XpozClient, XpozConnectionError, XpozError };
|
|
601
|
+
export { AuthenticationError, type InstagramComment, type InstagramPost, type InstagramUser, OperationCancelledError, OperationFailedError, OperationTimeoutError, PaginatedResult, type PaginationInfo, type RedditComment, type RedditPost, type RedditPostWithComments, type RedditSubreddit, type RedditUser, ResponseType, type SubredditWithPosts, type TwitterPost, type TwitterUser, VERSION, 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.1
|
|
251
|
+
var VERSION = "0.2.1";
|
|
252
252
|
|
|
253
253
|
// src/mcp/transport.ts
|
|
254
254
|
var USER_AGENT = `xpoz-ts-sdk/${VERSION}`;
|
|
@@ -361,6 +361,12 @@ var OperationCancelledError = class extends XpozError {
|
|
|
361
361
|
var DEFAULT_SERVER_URL = "https://mcp.xpoz.ai/mcp";
|
|
362
362
|
var ENV_API_KEY = "XPOZ_API_KEY";
|
|
363
363
|
var ENV_SERVER_URL = "XPOZ_SERVER_URL";
|
|
364
|
+
var ResponseType = /* @__PURE__ */ ((ResponseType2) => {
|
|
365
|
+
ResponseType2["Fast"] = "fast";
|
|
366
|
+
ResponseType2["Paging"] = "paging";
|
|
367
|
+
ResponseType2["Csv"] = "csv";
|
|
368
|
+
return ResponseType2;
|
|
369
|
+
})(ResponseType || {});
|
|
364
370
|
var POLL_INTERVAL_MS = 5e3;
|
|
365
371
|
var DEFAULT_TIMEOUT_MS = 3e5;
|
|
366
372
|
|
|
@@ -465,6 +471,9 @@ var BaseNamespace = class {
|
|
|
465
471
|
}
|
|
466
472
|
async callAndMaybePoll(toolName, args) {
|
|
467
473
|
const result = await this.callTool(toolName, args);
|
|
474
|
+
if ("results" in result) {
|
|
475
|
+
return result;
|
|
476
|
+
}
|
|
468
477
|
const operationId = result["operationId"];
|
|
469
478
|
if (operationId) {
|
|
470
479
|
return waitForResult(this.callTool, operationId, this.timeoutMs);
|
|
@@ -483,7 +492,11 @@ var BaseNamespace = class {
|
|
|
483
492
|
return this.buildPaginatedResult(pageRaw, parseItem, toolName, baseArgs);
|
|
484
493
|
};
|
|
485
494
|
const fetchExport = async (opId) => {
|
|
486
|
-
const pollResult = await waitForResult(
|
|
495
|
+
const pollResult = await waitForResult(
|
|
496
|
+
this.callTool,
|
|
497
|
+
opId,
|
|
498
|
+
this.timeoutMs
|
|
499
|
+
);
|
|
487
500
|
return pollResult["downloadUrl"] ?? "";
|
|
488
501
|
};
|
|
489
502
|
return new PaginatedResult({
|
|
@@ -559,12 +572,13 @@ var TwitterNamespace = class extends BaseNamespace {
|
|
|
559
572
|
}
|
|
560
573
|
async getPostsByAuthor(identifier, options = {}) {
|
|
561
574
|
const args = this.buildArgs({
|
|
562
|
-
identifier,
|
|
563
|
-
identifierType: options.identifierType ?? "username",
|
|
575
|
+
username: identifier,
|
|
564
576
|
fields: options.fields,
|
|
565
577
|
startDate: options.startDate,
|
|
566
578
|
endDate: options.endDate,
|
|
567
|
-
forceLatest: options.forceLatest
|
|
579
|
+
forceLatest: options.forceLatest,
|
|
580
|
+
responseType: options.responseType,
|
|
581
|
+
limit: options.limit
|
|
568
582
|
});
|
|
569
583
|
const result = await this.callAndMaybePoll(GET_TWITTER_POSTS_BY_AUTHOR, args);
|
|
570
584
|
return this.buildPaginatedResult(result, parseTwitterPost, GET_TWITTER_POSTS_BY_AUTHOR, args);
|
|
@@ -579,9 +593,10 @@ var TwitterNamespace = class extends BaseNamespace {
|
|
|
579
593
|
authorId: options.authorId,
|
|
580
594
|
language: options.language,
|
|
581
595
|
forceLatest: options.forceLatest,
|
|
582
|
-
responseType: options.responseType
|
|
596
|
+
responseType: options.responseType,
|
|
597
|
+
limit: options.limit
|
|
583
598
|
});
|
|
584
|
-
if (options.responseType === "csv") {
|
|
599
|
+
if (options.responseType === "csv" /* Csv */) {
|
|
585
600
|
const raw = await this.callTool(SEARCH_TWITTER_POSTS, args);
|
|
586
601
|
const exportOpId = raw["operationId"] ?? raw["dataDumpExportOperationId"] ?? null;
|
|
587
602
|
const csvRaw = { results: [], dataDumpExportOperationId: exportOpId };
|
|
@@ -692,7 +707,9 @@ var InstagramNamespace = class extends BaseNamespace {
|
|
|
692
707
|
fields: options.fields,
|
|
693
708
|
startDate: options.startDate,
|
|
694
709
|
endDate: options.endDate,
|
|
695
|
-
forceLatest: options.forceLatest
|
|
710
|
+
forceLatest: options.forceLatest,
|
|
711
|
+
responseType: options.responseType,
|
|
712
|
+
limit: options.limit
|
|
696
713
|
});
|
|
697
714
|
const result = await this.callAndMaybePoll(GET_INSTAGRAM_POSTS_BY_USER, args);
|
|
698
715
|
return this.buildPaginatedResult(
|
|
@@ -703,7 +720,15 @@ var InstagramNamespace = class extends BaseNamespace {
|
|
|
703
720
|
);
|
|
704
721
|
}
|
|
705
722
|
async searchPosts(query, options = {}) {
|
|
706
|
-
const args = this.buildArgs({
|
|
723
|
+
const args = this.buildArgs({
|
|
724
|
+
query,
|
|
725
|
+
fields: options.fields,
|
|
726
|
+
startDate: options.startDate,
|
|
727
|
+
endDate: options.endDate,
|
|
728
|
+
forceLatest: options.forceLatest,
|
|
729
|
+
responseType: options.responseType,
|
|
730
|
+
limit: options.limit
|
|
731
|
+
});
|
|
707
732
|
const result = await this.callAndMaybePoll(SEARCH_INSTAGRAM_POSTS, args);
|
|
708
733
|
return this.buildPaginatedResult(result, parsePost, SEARCH_INSTAGRAM_POSTS, args);
|
|
709
734
|
}
|
|
@@ -870,12 +895,53 @@ var RedditNamespace = class extends BaseNamespace {
|
|
|
870
895
|
}
|
|
871
896
|
};
|
|
872
897
|
|
|
898
|
+
// src/versionCheck.ts
|
|
899
|
+
var NPM_REGISTRY_URL = "https://registry.npmjs.org/@xpoz/xpoz/latest";
|
|
900
|
+
var CHECK_TIMEOUT_MS = 3e3;
|
|
901
|
+
var PACKAGE_NAME = "@xpoz/xpoz";
|
|
902
|
+
var hasWarned = false;
|
|
903
|
+
async function checkForUpdates() {
|
|
904
|
+
if (hasWarned) return;
|
|
905
|
+
try {
|
|
906
|
+
const controller = new AbortController();
|
|
907
|
+
const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS);
|
|
908
|
+
const response = await fetch(NPM_REGISTRY_URL, {
|
|
909
|
+
signal: controller.signal,
|
|
910
|
+
headers: { Accept: "application/json" }
|
|
911
|
+
});
|
|
912
|
+
clearTimeout(timeout);
|
|
913
|
+
if (!response.ok) return;
|
|
914
|
+
const data = await response.json();
|
|
915
|
+
const latest = data.version;
|
|
916
|
+
if (!latest || latest === VERSION) return;
|
|
917
|
+
if (isNewerVersion(latest, VERSION)) {
|
|
918
|
+
hasWarned = true;
|
|
919
|
+
console.warn(
|
|
920
|
+
`[xpoz] A newer version of ${PACKAGE_NAME} is available: ${latest} (current: ${VERSION}). Run \`npm install ${PACKAGE_NAME}@latest\` to update.`
|
|
921
|
+
);
|
|
922
|
+
}
|
|
923
|
+
} catch {
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
function isNewerVersion(latestVersion, currentVersion) {
|
|
927
|
+
const latestVersionParts = latestVersion.split(".").map(Number);
|
|
928
|
+
const currentVersionParts = currentVersion.split(".").map(Number);
|
|
929
|
+
for (let i = 0; i < 3; i++) {
|
|
930
|
+
const latestVersionPart = latestVersionParts[i] ?? 0;
|
|
931
|
+
const currentVersionPart = currentVersionParts[i] ?? 0;
|
|
932
|
+
if (latestVersionPart > currentVersionPart) return true;
|
|
933
|
+
if (latestVersionPart < currentVersionPart) return false;
|
|
934
|
+
}
|
|
935
|
+
return false;
|
|
936
|
+
}
|
|
937
|
+
|
|
873
938
|
// src/client.ts
|
|
874
939
|
var XpozClient = class {
|
|
875
940
|
twitter;
|
|
876
941
|
instagram;
|
|
877
942
|
reddit;
|
|
878
943
|
transport;
|
|
944
|
+
versionCheck;
|
|
879
945
|
constructor(options = {}) {
|
|
880
946
|
const apiKey = options.apiKey ?? process.env[ENV_API_KEY];
|
|
881
947
|
if (!apiKey) {
|
|
@@ -883,6 +949,7 @@ var XpozClient = class {
|
|
|
883
949
|
`API key required. Get your token at http://xpoz.ai/get-token?utm_source=ts_sdk&utm_medium=sdk (login \u2192 copy token), then pass it as apiKey or set the ${ENV_API_KEY} environment variable.`
|
|
884
950
|
);
|
|
885
951
|
}
|
|
952
|
+
this.versionCheck = options.versionCheck ?? true;
|
|
886
953
|
const serverUrl = options.serverUrl ?? process.env[ENV_SERVER_URL] ?? DEFAULT_SERVER_URL;
|
|
887
954
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
888
955
|
this.transport = new McpTransport(serverUrl, apiKey);
|
|
@@ -893,6 +960,9 @@ var XpozClient = class {
|
|
|
893
960
|
}
|
|
894
961
|
async connect() {
|
|
895
962
|
await this.transport.connect();
|
|
963
|
+
if (this.versionCheck) {
|
|
964
|
+
checkForUpdates();
|
|
965
|
+
}
|
|
896
966
|
}
|
|
897
967
|
async close() {
|
|
898
968
|
await this.transport.close();
|
|
@@ -907,8 +977,10 @@ export {
|
|
|
907
977
|
OperationFailedError,
|
|
908
978
|
OperationTimeoutError,
|
|
909
979
|
PaginatedResult,
|
|
980
|
+
ResponseType,
|
|
910
981
|
VERSION,
|
|
911
982
|
XpozClient,
|
|
912
983
|
XpozConnectionError,
|
|
913
|
-
XpozError
|
|
984
|
+
XpozError,
|
|
985
|
+
checkForUpdates
|
|
914
986
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xpoz/xpoz",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "TypeScript SDK for the Xpoz social media intelligence platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -43,5 +43,14 @@
|
|
|
43
43
|
"url": "https://github.com/XPOZpublic/xpoz-ts-sdk/issues"
|
|
44
44
|
},
|
|
45
45
|
"license": "MIT",
|
|
46
|
-
"keywords": [
|
|
46
|
+
"keywords": [
|
|
47
|
+
"xpoz",
|
|
48
|
+
"social-media",
|
|
49
|
+
"twitter",
|
|
50
|
+
"instagram",
|
|
51
|
+
"reddit",
|
|
52
|
+
"sdk",
|
|
53
|
+
"mcp",
|
|
54
|
+
"api"
|
|
55
|
+
]
|
|
47
56
|
}
|