@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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@xpoz/xpoz)](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 Reddit data through a simple, typed interface.
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 Reddit. The platform indexes billions of posts, user profiles, and engagement metrics — making it possible to search, analyze, and export social media data at scale.
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
- | `country` | `string` | Country (if geo-tagged) |
820
- | `createdAt` | `string` | Creation timestamp |
821
- | `createdAtDate` | `string` | Creation date (YYYY-MM-DD) |
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
- | `createdAtDate` | `string` | Creation date |
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
- | `createdAtDate` | `string` | Creation date |
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` | Creation timestamp |
980
- | `createdAtDate` | `string` | Creation date (YYYY-MM-DD) |
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.10";
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,